LCOV - code coverage report
Current view: top level - core/physics - Particles.cpp (source / functions) Coverage Total Hit
Test: coverage-src.info Lines: 0.0 % 160 0
Test Date: 2025-05-27 23:26:07 Functions: 0.0 % 14 0

            Line data    Source code
       1              : #include "Particles.hpp"
       2              : 
       3              : #include "core/physics/Particles.hpp"
       4              : #include "core/utility/Getline.hpp"
       5              : 
       6              : #include "spdlog/spdlog.h"
       7              : 
       8              : #include <filesystem>
       9              : #include <fstream>
      10              : #include <map>
      11              : 
      12              : namespace Soldank
      13              : {
      14            0 : Particle::Particle(bool _active,
      15              :                    glm::vec2 _position,
      16              :                    glm::vec2 _old_position,
      17              :                    glm::vec2 _velocity,
      18              :                    glm::vec2 force,
      19              :                    float one_over_mass,
      20              :                    float timestep,
      21              :                    float gravity,
      22              :                    float e_damping,
      23            0 :                    float v_damping)
      24            0 :     : active(_active)
      25            0 :     , position(_position)
      26            0 :     , old_position(_old_position)
      27            0 :     , velocity_(_velocity)
      28            0 :     , force_(force)
      29            0 :     , one_over_mass_(one_over_mass)
      30            0 :     , timestep_(timestep)
      31            0 :     , gravity_(gravity)
      32            0 :     , e_damping_(e_damping)
      33            0 :     , v_damping_(v_damping)
      34              : {
      35            0 : }
      36              : 
      37            0 : void Particle::Euler()
      38              : {
      39            0 :     old_position = position;
      40            0 :     force_.y += gravity_;
      41            0 :     glm::vec2 current_force = force_;
      42            0 :     current_force *= one_over_mass_ * std::pow(timestep_, 2);
      43            0 :     velocity_ += current_force;
      44            0 :     position += velocity_;
      45            0 :     velocity_ *= e_damping_;
      46            0 :     force_ = glm::vec2(0.0, 0.0);
      47            0 : }
      48              : 
      49            0 : void Particle::Verlet()
      50              : {
      51            0 :     glm::vec2 a = position * (1.0F + v_damping_);
      52            0 :     glm::vec2 b = old_position * v_damping_;
      53              : 
      54            0 :     old_position = position;
      55            0 :     force_.y += gravity_;
      56            0 :     glm::vec2 current_force = force_;
      57            0 :     current_force *= one_over_mass_ * std::pow(timestep_, 2);
      58            0 :     position = a - b + current_force;
      59            0 :     force_ = glm::vec2(0.0, 0.0);
      60            0 : }
      61              : 
      62            0 : ParticleSystem::ParticleSystem(const std::vector<Particle>& particles,
      63            0 :                                const std::vector<Constraint>& constraints)
      64            0 :     : particles_(particles)
      65            0 :     , constraints_(constraints)
      66              : {
      67            0 : }
      68              : 
      69            0 : void ParticleSystem::DoVerletTimestep()
      70              : {
      71            0 :     for (Particle& particle : particles_) {
      72            0 :         if (particle.active) {
      73            0 :             particle.Verlet();
      74              :         }
      75              :     }
      76            0 :     SatisfyConstraints();
      77            0 : }
      78              : 
      79            0 : void ParticleSystem::DoVerletTimestepFor(unsigned int particle_num, unsigned int constraint_num)
      80              : {
      81            0 :     particles_[particle_num - 1].Verlet();
      82            0 :     SatisfyConstraintFor(constraint_num - 1);
      83            0 : }
      84              : 
      85            0 : void ParticleSystem::DoEulerTimestep()
      86              : {
      87            0 :     for (Particle& particle : particles_) {
      88            0 :         if (particle.active) {
      89            0 :             particle.Euler();
      90              :         }
      91              :     }
      92            0 : }
      93              : 
      94            0 : void ParticleSystem::DoEulerTimestepFor(unsigned int particle_num)
      95              : {
      96            0 :     particles_[particle_num - 1].Euler();
      97            0 : }
      98              : 
      99            0 : void ParticleSystem::SatisfyConstraints()
     100              : {
     101            0 :     for (const Constraint& constraint : constraints_) {
     102            0 :         if (constraint.active) {
     103            0 :             SatisfyConstraint(constraint, particles_);
     104              :         }
     105              :     }
     106            0 : }
     107              : 
     108            0 : void ParticleSystem::SatisfyConstraintFor(unsigned int constraint_num)
     109              : {
     110            0 :     SatisfyConstraint(constraints_[constraint_num - 1], particles_);
     111            0 : }
     112              : 
     113            0 : void ParticleSystem::SatisfyConstraint(const Constraint& constraint,
     114              :                                        std::vector<Particle>& particles)
     115              : {
     116            0 :     unsigned int a = constraint.particle_num.x - 1;
     117            0 :     unsigned int b = constraint.particle_num.y - 1;
     118              : 
     119            0 :     glm::vec2 delta = particles[b].position - particles[a].position;
     120            0 :     auto length = glm::length(delta);
     121              : 
     122            0 :     if (length > 0.0) {
     123            0 :         auto diff = (length - constraint.rest_length) / length;
     124              : 
     125              :         // delta *= diff / 2.0f;
     126            0 :         if (particles[a].GetOneOverMass() > 0.0) {
     127            0 :             particles[a].position += delta * diff / 2.0F;
     128              :         }
     129              : 
     130            0 :         if (particles[b].GetOneOverMass() > 0.0) {
     131            0 :             particles[b].position -= delta * diff / 2.0F;
     132              :         }
     133              :     }
     134            0 : }
     135              : 
     136            0 : std::shared_ptr<ParticleSystem> ParticleSystem::Load(ParticleSystemType particle_system_type,
     137              :                                                      float scale,
     138              :                                                      const IFileReader& file_reader)
     139              : {
     140              :     // TODO: const
     141            0 :     const float grav = 0.06F;
     142            0 :     switch (particle_system_type) {
     143            0 :         case ParticleSystemType::Soldier: {
     144              :             // TODO: load it at the application start
     145              :             static std::map<float, std::shared_ptr<ParticleSystem>>
     146            0 :               soldier_particle_system_by_scale;
     147            0 :             if (!soldier_particle_system_by_scale.contains(scale)) {
     148            0 :                 soldier_particle_system_by_scale[scale] =
     149            0 :                   LoadFromFile("gostek.po", scale, 1.0F, 1.06F * grav, 0.0F, 0.9945F, file_reader);
     150              :             }
     151            0 :             return std::make_shared<ParticleSystem>(*soldier_particle_system_by_scale.at(scale));
     152              :         }
     153            0 :         case ParticleSystemType::Flag: {
     154            0 :             static std::map<float, std::shared_ptr<ParticleSystem>> flag_particle_system_by_scale;
     155            0 :             if (!flag_particle_system_by_scale.contains(scale)) {
     156            0 :                 flag_particle_system_by_scale[scale] =
     157            0 :                   LoadFromFile("flag.po", scale, 1.0F, 1.06F * grav, 0.0F, 0.9945F, file_reader);
     158              :             }
     159            0 :             return std::make_shared<ParticleSystem>(*flag_particle_system_by_scale.at(scale));
     160              :         }
     161            0 :         case ParticleSystemType::Weapon: {
     162            0 :             static std::map<float, std::shared_ptr<ParticleSystem>> weapon_particle_system_by_scale;
     163            0 :             if (!weapon_particle_system_by_scale.contains(scale)) {
     164            0 :                 weapon_particle_system_by_scale[scale] =
     165            0 :                   LoadFromFile("karabin.po", scale, 1.0F, 1.06F * grav, 0.0F, 0.9945F, file_reader);
     166              :             }
     167            0 :             return std::make_shared<ParticleSystem>(*weapon_particle_system_by_scale.at(scale));
     168              :         }
     169            0 :         case ParticleSystemType::Kit: {
     170            0 :             static std::map<float, std::shared_ptr<ParticleSystem>> kit_particle_system_by_scale;
     171            0 :             if (!kit_particle_system_by_scale.contains(scale)) {
     172            0 :                 kit_particle_system_by_scale[scale] =
     173            0 :                   LoadFromFile("kit.po", scale, 1.0F, 1.06F * grav, 0.0F, 0.989F, file_reader);
     174              :             }
     175            0 :             return std::make_shared<ParticleSystem>(*kit_particle_system_by_scale.at(scale));
     176              :         }
     177            0 :         case ParticleSystemType::Parachute: {
     178              :             static std::map<float, std::shared_ptr<ParticleSystem>>
     179            0 :               parachute_particle_system_by_scale;
     180            0 :             if (!parachute_particle_system_by_scale.contains(scale)) {
     181            0 :                 parachute_particle_system_by_scale[scale] =
     182            0 :                   LoadFromFile("para.po", scale, 1.0F, 1.06F * grav, 0.0F, 0.9945F, file_reader);
     183              :             }
     184            0 :             return std::make_shared<ParticleSystem>(*parachute_particle_system_by_scale.at(scale));
     185              :         }
     186            0 :         case ParticleSystemType::StationaryGun: {
     187              :             static std::map<float, std::shared_ptr<ParticleSystem>>
     188            0 :               stat_gun_particle_system_by_scale;
     189            0 :             if (!stat_gun_particle_system_by_scale.contains(scale)) {
     190            0 :                 stat_gun_particle_system_by_scale[scale] =
     191            0 :                   LoadFromFile("stat.po", scale, 1.0F, 1.06F * grav, 0.0F, 0.9945F, file_reader);
     192              :             }
     193            0 :             return std::make_shared<ParticleSystem>(*stat_gun_particle_system_by_scale.at(scale));
     194              :         }
     195              :     }
     196              : }
     197              : 
     198            0 : std::shared_ptr<ParticleSystem> ParticleSystem::LoadFromFile(const std::string& file_name,
     199              :                                                              float scale,
     200              :                                                              float timestep,
     201              :                                                              float gravity,
     202              :                                                              float e_damping,
     203              :                                                              float v_damping,
     204              :                                                              const IFileReader& file_reader)
     205              : {
     206            0 :     std::vector<Particle> particles;
     207            0 :     std::vector<Constraint> constraints;
     208              : 
     209            0 :     std::filesystem::path file_path = "objects/";
     210            0 :     file_path += file_name;
     211            0 :     auto file_data = file_reader.Read(file_path.string());
     212            0 :     if (!file_data.has_value()) {
     213            0 :         std::string message = "Could not open file: " + file_path.string();
     214            0 :         throw std::runtime_error(message.c_str());
     215            0 :     }
     216            0 :     std::stringstream data_buffer{ *file_data };
     217              : 
     218            0 :     auto read_float = [](std::stringstream& buffer) {
     219            0 :         std::string line;
     220            0 :         GetlineSafe(buffer, line);
     221            0 :         return std::stof(line);
     222            0 :     };
     223              : 
     224            0 :     std::string line;
     225            0 :     GetlineSafe(data_buffer, line);
     226              : 
     227            0 :     while (line != "CONSTRAINTS") {
     228            0 :         float x = read_float(data_buffer);
     229            0 :         read_float(data_buffer);
     230            0 :         float z = read_float(data_buffer);
     231            0 :         glm::vec2 p = glm::vec2(-x * scale / 1.2, -z * scale);
     232              : 
     233            0 :         particles.emplace_back(true,
     234              :                                p,
     235              :                                p,
     236            0 :                                glm::vec2(0.0, 0.0),
     237            0 :                                glm::vec2(0.0, 0.0),
     238            0 :                                1.0,
     239              :                                timestep,
     240              :                                gravity,
     241              :                                e_damping,
     242              :                                v_damping);
     243              : 
     244            0 :         GetlineSafe(data_buffer, line);
     245              :     }
     246              : 
     247            0 :     while (!data_buffer.eof()) {
     248            0 :         GetlineSafe(data_buffer, line);
     249              : 
     250            0 :         if (data_buffer.eof() || line.empty() || line == "ENDFILE") {
     251            0 :             break;
     252              :         }
     253            0 :         line.erase(0, 1); // first character is always P
     254            0 :         unsigned int pa_num = std::stoul(line);
     255              : 
     256            0 :         GetlineSafe(data_buffer, line);
     257            0 :         line.erase(0, 1); // first character is always P
     258            0 :         unsigned int pb_num = std::stoul(line);
     259              : 
     260            0 :         auto delta = particles[pa_num - 1].position - particles[pb_num - 1].position;
     261            0 :         constraints.push_back({ true, glm::uvec2(pa_num, pb_num), glm::length(delta) });
     262              :     }
     263              : 
     264            0 :     spdlog::info("Particle {}, loaded {} particles and {} constraints",
     265            0 :                  file_path.string(),
     266            0 :                  particles.size(),
     267            0 :                  constraints.size());
     268              : 
     269            0 :     return std::make_shared<ParticleSystem>(particles, constraints);
     270            0 : }
     271              : } // namespace Soldank
        

Generated by: LCOV version 2.0-1