diff --git a/CMakeLists.txt b/CMakeLists.txt index af368e1..d4aa351 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 3.7) - option(VERSION_STRING "Project version string" "0.0.0") project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX) diff --git a/src/entity/components/genome.hpp b/src/entity/components/genome.hpp new file mode 100644 index 0000000..a1941f0 --- /dev/null +++ b/src/entity/components/genome.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ENTITY_COMPONENT_GENOME_HPP +#define ANTKEEPER_ENTITY_COMPONENT_GENOME_HPP + +#include +#include + +namespace entity { +namespace component { + +/// Complete set of genetic material in an organism. +struct genome +{ + /** + * Number of complete sets of chromosomes in a cell. + * + * A value of `1` indicates the organism is haploid, `2` is diploid, `3` is triploid, etc. + */ + unsigned int ploidy; + + /** + * Set of DNA base sequences for every chromosomes in the genome. + * + * A DNA base sequence is a string of IUPAC DNA base symbols. Homologous chromosomes should be stored consecutively, such that in a diploid organism, a chromosome with an even index is homologous to the following chromosome. + */ + std::vector chromosomes; +}; + +} // namespace component +} // namespace entity + +#endif // ANTKEEPER_ENTITY_COMPONENT_GENOME_HPP diff --git a/src/entity/components/proteome.hpp b/src/entity/components/proteome.hpp new file mode 100644 index 0000000..5d6e184 --- /dev/null +++ b/src/entity/components/proteome.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ENTITY_COMPONENT_PROTEOME_HPP +#define ANTKEEPER_ENTITY_COMPONENT_PROTEOME_HPP + +#include +#include + +namespace entity { +namespace component { + +/// Set of all proteins that can be expressed by an organism. +struct proteome +{ + /// Set of amino acid sequences of every protein in the proteome. + std::vector proteins; +}; + +} // namespace component +} // namespace entity + +#endif // ANTKEEPER_ENTITY_COMPONENT_PROTEOME_HPP diff --git a/src/entity/systems/morphogenesis.cpp b/src/entity/systems/morphogenesis.cpp new file mode 100644 index 0000000..fa6da0e --- /dev/null +++ b/src/entity/systems/morphogenesis.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include "entity/systems/morphogenesis.hpp" +#include "entity/id.hpp" + +namespace entity { +namespace system { + +morphogenesis::morphogenesis(entity::registry& registry): + updatable(registry) +{} + +void morphogenesis::update(double t, double dt) +{} + +} // namespace system +} // namespace entity diff --git a/src/entity/systems/morphogenesis.hpp b/src/entity/systems/morphogenesis.hpp new file mode 100644 index 0000000..86fbbc5 --- /dev/null +++ b/src/entity/systems/morphogenesis.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ENTITY_SYSTEM_MORPHOGENESIS_HPP +#define ANTKEEPER_ENTITY_SYSTEM_MORPHOGENESIS_HPP + +#include "entity/systems/updatable.hpp" + +namespace entity { +namespace system { + +/** + * Constructs the forms of organisms from their genetic codes. + * + * Algorithm: + * + * 1. Consider inital egg cell as a sphere at the origin. + * 2. Use the marching cubes algorithm to generate a mesh from the isosurface formed by the sum of all cells. + * 3. Generate evenly-distributed points across surface area of the mesh (Poisson sample?). + * 4. For each point, evaluate morphogenic genes to determine type, direction, and color of the next cell. + * 5. Create new cells given the output of step 4. + * 6. Go to step 2 and repeat. + */ +class morphogenesis: + public updatable +{ +public: + morphogenesis(entity::registry& registry); + + /** + * Scales then adds the timestep `dt` to the current time, then recalculates the positions of morphogenesising bodies. + * + * @param t Time, in seconds. + * @param dt Delta time, in seconds. + */ + virtual void update(double t, double dt); + +private: +}; + +} // namespace system +} // namespace entity + +#endif // ANTKEEPER_ENTITY_SYSTEM_MORPHOGENESIS_HPP diff --git a/src/entity/systems/proteome.cpp b/src/entity/systems/proteome.cpp new file mode 100644 index 0000000..73bde69 --- /dev/null +++ b/src/entity/systems/proteome.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include "entity/systems/proteome.hpp" +#include "entity/components/proteome.hpp" +#include "genetics/sequence.hpp" +#include "genetics/standard-code.hpp" + +namespace entity { +namespace system { + +proteome::proteome(entity::registry& registry): + updatable(registry) +{ + registry.on_construct().connect<&proteome::on_genome_construct>(this); + registry.on_replace().connect<&proteome::on_genome_replace>(this); +} + +void proteome::update(double t, double dt) +{} + +void proteome::on_genome_construct(entity::registry& registry, entity::id entity_id, entity::component::genome& genome) +{ + on_genome_replace(registry, entity_id, genome); +} + +void proteome::on_genome_replace(entity::registry& registry, entity::id entity_id, entity::component::genome& genome) +{ + // Allocate a proteome component + entity::component::proteome proteome_component; + + // For each chromosome in the genome + for (const std::string& chromosome: genome.chromosomes) + { + // Find the first ORF in the chromosome + auto orf = genetics::sequence::find_orf(chromosome.begin(), chromosome.end(), genetics::standard_code); + + // While the ORF is valid + while (orf.start != chromosome.end()) + { + // Translate the base sequence into an amino acid sequence (protein) + std::string protein; + genetics::sequence::translate(orf.start, orf.stop, std::back_inserter(protein), genetics::standard_code); + + // Append protein to the proteome + proteome_component.proteins.push_back(protein); + + // Find the next ORF + orf = genetics::sequence::find_orf(orf.stop, chromosome.end(), genetics::standard_code); + } + } + + // Assign or replace the entity's proteome component + registry.assign_or_replace(entity_id, proteome_component); +} + +} // namespace system +} // namespace entity diff --git a/src/entity/systems/proteome.hpp b/src/entity/systems/proteome.hpp new file mode 100644 index 0000000..567fbf4 --- /dev/null +++ b/src/entity/systems/proteome.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ENTITY_SYSTEM_PROTEOME_HPP +#define ANTKEEPER_ENTITY_SYSTEM_PROTEOME_HPP + +#include "entity/systems/updatable.hpp" +#include "entity/components/genome.hpp" +#include "entity/id.hpp" + +namespace entity { +namespace system { + +/** + * Generates proteomes for every genome. + */ +class proteome: + public updatable +{ +public: + proteome(entity::registry& registry); + + /** + * Scales then adds the timestep `dt` to the current time, then recalculates the positions of proteomeing bodies. + * + * @param t Time, in seconds. + * @param dt Delta time, in seconds. + */ + virtual void update(double t, double dt); + +private: + void on_genome_construct(entity::registry& registry, entity::id entity_id, entity::component::genome& genome); + void on_genome_replace(entity::registry& registry, entity::id entity_id, entity::component::genome& genome); +}; + +} // namespace system +} // namespace entity + +#endif // ANTKEEPER_ENTITY_SYSTEM_PROTEOME_HPP diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp index ea89ca3..323513d 100644 --- a/src/game/bootloader.cpp +++ b/src/game/bootloader.cpp @@ -77,6 +77,7 @@ #include "entity/systems/blackbody.hpp" #include "entity/systems/atmosphere.hpp" #include "entity/systems/orbit.hpp" +#include "entity/systems/proteome.hpp" #include "entity/components/marker.hpp" #include "entity/commands.hpp" #include "utility/paths.hpp" @@ -878,6 +879,9 @@ void setup_systems(game_context* ctx) // Setup astronomy system ctx->astronomy_system = new entity::system::astronomy(*ctx->entity_registry); + // Setup proteome system + ctx->proteome_system = new entity::system::proteome(*ctx->entity_registry); + // Set time scale float time_scale = 60.0f; if (ctx->config->has("time_scale")) @@ -1277,7 +1281,7 @@ void setup_callbacks(game_context* ctx) ctx->constraint_system->update(t, dt); ctx->tracking_system->update(t, dt); ctx->painting_system->update(t, dt); - + ctx->proteome_system->update(t, dt); //(*ctx->focal_point_tween)[1] = ctx->orbit_cam->get_focal_point(); @@ -1295,8 +1299,6 @@ void setup_callbacks(game_context* ctx) ctx->application_controls->update(); ctx->menu_controls->update(); ctx->camera_controls->update(); - - } ); diff --git a/src/game/game-context.hpp b/src/game/game-context.hpp index c4d54de..df64b71 100644 --- a/src/game/game-context.hpp +++ b/src/game/game-context.hpp @@ -99,6 +99,7 @@ namespace entity class nest; class render; class samara; + class proteome; } } @@ -255,6 +256,7 @@ struct game_context entity::system::atmosphere* atmosphere_system; entity::system::astronomy* astronomy_system; entity::system::orbit* orbit_system; + entity::system::proteome* proteome_system; // Game biome* biome; diff --git a/src/game/states/play-state.cpp b/src/game/states/play-state.cpp index 0a7beb2..714b28d 100644 --- a/src/game/states/play-state.cpp +++ b/src/game/states/play-state.cpp @@ -26,6 +26,7 @@ #include "entity/components/copy-transform.hpp" #include "entity/components/copy-translation.hpp" #include "entity/components/model.hpp" +#include "entity/components/genome.hpp" #include "entity/components/snap.hpp" #include "entity/components/terrain.hpp" #include "entity/components/tool.hpp" @@ -362,13 +363,20 @@ void play_state_enter(game_context* ctx) // Place larva in chamber { - auto larva = larva_archetype->create(entity_registry); - entity::command::assign_render_layers(entity_registry, larva, 1); - entity::command::warp_to(entity_registry, larva, {50, 0.1935f, 0}); + auto larva_eid = larva_archetype->create(entity_registry); + entity::command::assign_render_layers(entity_registry, larva_eid, 1); + entity::command::warp_to(entity_registry, larva_eid, {50, 0.1935f, 0}); //auto& transform = entity_registry.get(larva_entity); //transform.transform = math::identity_transform; //transform.transform.translation = nest->get_shaft_position(*central_shaft, central_shaft->depth[1]); //transform.transform.translation.y -= 1.0f; + + // Construct larva genome + entity::component::genome genome; + genome.ploidy = 2; + const std::string antp = "ATGACCATGAGCACCAACAACTGCGAAAGCATGACCAGCTATTTTACCAACAGCTATATGGGCGCGGATATGCATCATGGCCATTATCCGGGCAACGGCGTGACCGATCTGGATGCGCAGCAGATGCATCATTATAGCCAGAACGCGAACCATCAGGGCAACATGCCGTATCCGCGCTTTCCGCCGTATGATCGCATGCCGTATTATAACGGCCAGGGCATGGATCAGCAGCAGCAGCATCAGGTGTATAGCCGCCCGGATAGCCCGAGCAGCCAGGTGGGCGGCGTGATGCCGCAGGCGCAGACCAACGGCCAGCTGGGCGTGCCGCAGCAGCAGCAGCAGCAGCAGCAGCAGCCGAGCCAGAACCAGCAGCAGCAGCAGGCGCAGCAGGCGCCGCAGCAGCTGCAGCAGCAGCTGCCGCAGGTGACCCAGCAGGTGACCCATCCGCAGCAGCAGCAGCAGCAGCCGGTGGTGTATGCGAGCTGCAAACTGCAGGCGGCGGTGGGCGGCCTGGGCATGGTGCCGGAAGGCGGCAGCCCGCCGCTGGTGGATCAGATGAGCGGCCATCATATGAACGCGCAGATGACCCTGCCGCATCATATGGGCCATCCGCAGGCGCAGGTGCATCAGAACCATCATAACATGGGCATGTATCAGCAGCAGAGCGGCGTGCCGCCGGTGGGCGCGCCGCCGCAGGGCATGATGCATCAGGGCCAGGGCCCGCCGCAGATGCATCAGGGCCATCCGGGCCAGCATACCCCGCCGAGCCAGAACCCGAACAGCCAGAGCAGCGGCATGCCGAGCCCGCTGTATCCGTGGATGCGCAGCCAGTTTGAACGCAAACGCGGCCGCCAGACCTATACCCGCTATCAGACCCTGGAACTGGAAAAAGAATTTCATTTTAACCGCTATCTGACCCGCCGCCGCCGCATTGAAATTGCGCATGCGCTGTGCCTGACCGAACGCCAGATTAAAATTTGGTTTCAGAACCGCCGCATGAAATGGAAAAAAGAAAACAAAACCAAAGGCGAACCGGGCAGCGGCGGCGAAGGCGATGAAATTACCCCGCCGAACAGCCCGCAGTAG"; + genome.chromosomes.push_back(antp); + entity_registry.assign(larva_eid, genome); } entity::system::control* control_system = ctx->control_system; @@ -382,62 +390,6 @@ void play_state_enter(game_context* ctx) std::string biome_name = (*ctx->strings)[ctx->biome->name]; logger->log("Entered biome \"" + biome_name + "\""); - - - std::srand(std::time(nullptr)); - //auto rng = [](){ return std::rand(); }; - - std::random_device rd; - std::mt19937 rng(rd()); - - - std::string sequence_a = "CCTTGCCCTTTGGGTCGCCCCCCTAG"; - std::string sequence_b = "ATGTTTCCCGAAGGGTAG"; - std::string sequence_c = "AAATGCCCCCCCCCCCCCCCCCCCCCCCCCCCTAGAAAAAAAAA"; - std::string orf_a; - std::string protein_a; - std::string protein_b; - std::string protein_c; - - - std::cout << "sequence a: " << sequence_a << std::endl; - genetics::sequence::transcribe(sequence_a.begin(), sequence_a.end(), sequence_a.begin()); - std::cout << "sequence a: " << sequence_a << std::endl; - - std::string complement; - genetics::sequence::rna::complement(sequence_a.begin(), sequence_a.end(), std::back_inserter(complement)); - std::cout << "complement: " << complement << std::endl; - - auto orf = genetics::sequence::find_orf(sequence_a.begin(), sequence_a.end(), genetics::standard_code); - if (orf.start != sequence_a.end()) - { - std::copy(orf.start, orf.stop, std::back_inserter(orf_a)); - std::cout << "orf a: " << orf_a << std::endl; - - genetics::sequence::translate(orf.start, orf.stop, std::back_inserter(protein_a), genetics::standard_code); - std::cout << "protein a: " << protein_a << std::endl; - } - - protein_b = "MFFFFP"; - protein_c = "MFFFYP"; - int score; - - std::cout << std::endl; - std::cout << "protein_b: " << protein_b << std::endl; - std::cout << "protein_c: " << protein_c << std::endl; - - score = genetics::protein::score(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum62); - std::cout << "score blosum62: " << score << std::endl; - - score = genetics::protein::score(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum80); - std::cout << "score blosum80: " << score << std::endl; - - - std::cout << "identity : " << genetics::protein::identity(protein_b.begin(), protein_b.end(), protein_c.begin()) << std::endl; - std::cout << "similarity62: " << genetics::protein::similarity(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum62) << std::endl; - std::cout << "similarity80: " << genetics::protein::similarity(protein_b.begin(), protein_b.end(), protein_c.begin(), genetics::matrix::blosum80) << std::endl; - - } void play_state_exit(game_context* ctx)