LCOV - code coverage report
Current view: top level - src/physics - PhysicsIntegrationSystem.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.9 % 124 109
Test Date: 2026-04-10 19:03:25 Functions: 100.0 % 6 6

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2025 aeml
       3              :  *
       4              :  * This program is free software: you can redistribute it and/or modify
       5              :  * it under the terms of the GNU General Public License as published by
       6              :  * the Free Software Foundation, either version 3 of the License, or
       7              :  * (at your option) any later version.
       8              :  *
       9              :  * This program is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12              :  * GNU General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU General Public License
      15              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #include "physics/Systems.hpp"
      19              : 
      20              : #include "jobs/JobSystem.hpp"
      21              : 
      22              : #include <algorithm>
      23              : #include <cmath>
      24              : 
      25              : namespace physics
      26              : {
      27              :     namespace
      28              :     {
      29          341 :         inline void EnsureDerivedMass(RigidBodyComponent& body)
      30              :         {
      31          341 :             if (body.mass <= 0.0f)
      32              :             {
      33            0 :                 body.invMass = 0.0f;
      34            0 :                 body.inertia = 0.0f;
      35            0 :                 body.invInertia = 0.0f;
      36            0 :                 return;
      37              :             }
      38              : 
      39          341 :             if (body.invMass <= 0.0f)
      40              :             {
      41            0 :                 body.invMass = 1.0f / body.mass;
      42              :             }
      43              : 
      44          341 :             if (body.inertia <= 0.0f)
      45              :             {
      46            0 :                 body.inertia = 0.5f * body.mass;
      47              :             }
      48              : 
      49          341 :             if (body.invInertia <= 0.0f && body.inertia > 0.0f)
      50              :             {
      51            0 :                 body.invInertia = 1.0f / body.inertia;
      52              :             }
      53              :         }
      54              :     }
      55              : 
      56        28605 :     void PhysicsIntegrationSystem::Update(ecs::World& world, float dt)
      57              :     {
      58        28605 :         auto* rbStorage = world.GetStorage<RigidBodyComponent>();
      59        28605 :         auto* tfStorage = world.GetStorage<TransformComponent>();
      60        28605 :         if (!rbStorage || !tfStorage) return;
      61              : 
      62        28589 :         auto& bodies = rbStorage->GetData();
      63        28589 :         const auto& entities = rbStorage->GetEntities();
      64        28589 :         size_t count = bodies.size();
      65              : 
      66        28604 :         auto integrateRange = [&](size_t start, size_t end) {
      67      2023788 :             for (size_t i = start; i < end; ++i) {
      68      1995184 :                 ecs::EntityId id = entities[i];
      69      1995184 :                 TransformComponent* tf = tfStorage->Get(id);
      70      1995184 :                 if (tf) {
      71      1995184 :                     auto& b = bodies[i];
      72      1995184 :                     if (b.invMass == 0.0f && b.mass > 0.0f) {
      73            0 :                         EnsureDerivedMass(b);
      74              :                     }
      75      1995184 :                     if (b.invMass == 0.0f) {
      76        91969 :                         b.angularVelocity = 0.0f;
      77        91969 :                         b.torque = 0.0f;
      78        91969 :                         continue;
      79              :                     }
      80              : 
      81      1903215 :                     b.lastX = tf->x;
      82      1903215 :                     b.lastY = tf->y;
      83      1903215 :                     b.lastAngle = tf->rotation;
      84              : 
      85      1903215 :                     const float ax = m_env.windX - m_env.drag * b.vx;
      86      1903215 :                     const float ay = m_env.gravityY + m_env.windY - m_env.drag * b.vy;
      87              : 
      88      1903215 :                     b.vx += ax * dt;
      89      1903215 :                     b.vy += ay * dt;
      90              : 
      91      1903215 :                     const float maxVel = 50.0f;
      92      1903215 :                     float vSq = b.vx * b.vx + b.vy * b.vy;
      93      1903215 :                     if (vSq > maxVel * maxVel) {
      94       102862 :                         float v = std::sqrt(vSq);
      95       102862 :                         b.vx = (b.vx / v) * maxVel;
      96       102862 :                         b.vy = (b.vy / v) * maxVel;
      97              :                     }
      98              : 
      99      1903215 :                     tf->x += b.vx * dt;
     100      1903215 :                     tf->y += b.vy * dt;
     101              : 
     102      1903215 :                     if (b.invInertia == 0.0f && b.inertia > 0.0f)
     103              :                     {
     104            0 :                         b.invInertia = 1.0f / b.inertia;
     105              :                     }
     106      1903215 :                     if (b.invInertia > 0.0f)
     107              :                     {
     108      1903215 :                         float angularAccel = b.torque * b.invInertia - b.angularDrag * b.angularVelocity;
     109      1903215 :                         b.angularVelocity += angularAccel * dt;
     110      1903215 :                         const float damping = std::max(0.0f, 1.0f - b.angularFriction * dt);
     111      1903215 :                         b.angularVelocity *= damping;
     112      1903215 :                         tf->rotation += b.angularVelocity * dt;
     113              :                     }
     114              :                     else
     115              :                     {
     116            0 :                         b.angularVelocity = 0.0f;
     117              :                     }
     118      1903215 :                     b.torque = 0.0f;
     119              : 
     120              :                 }
     121              :             }
     122        57193 :         };
     123              : 
     124        28589 :         if (m_jobSystem && count > 256) {
     125            1 :              const std::size_t batchSize = std::max(std::size_t(64), count / (m_jobSystem->WorkerCount() * 4));
     126            1 :              auto handles = m_jobSystem->Dispatch(count, batchSize, integrateRange);
     127            1 :              m_jobSystem->Wait(handles);
     128            1 :         } else {
     129        28588 :             integrateRange(0, count);
     130              :         }
     131              :     }
     132              : 
     133           22 :     void PhysicsIntegrationSystem::Integrate(std::vector<TransformComponent>& transforms,
     134              :                                              std::vector<RigidBodyComponent>& bodies,
     135              :                                              float                            dt) const
     136              :     {
     137           22 :         const std::size_t count = std::min(transforms.size(), bodies.size());
     138              : 
     139           26 :         auto integrateRange = [&](std::size_t start, std::size_t end)
     140              :         {
     141          367 :             for (std::size_t i = start; i < end; ++i)
     142              :             {
     143          341 :                 auto& t = transforms[i];
     144          341 :                 auto& b = bodies[i];
     145          341 :                 EnsureDerivedMass(b);
     146              : 
     147          341 :                 const float ax = m_env.windX - m_env.drag * b.vx;
     148          341 :                 const float ay = m_env.gravityY + m_env.windY - m_env.drag * b.vy;
     149              : 
     150          341 :                 b.vx += ax * dt;
     151          341 :                 b.vy += ay * dt;
     152              : 
     153          341 :                 const float maxVel = 50.0f;
     154          341 :                 float vSq = b.vx * b.vx + b.vy * b.vy;
     155          341 :                 if (vSq > maxVel * maxVel) {
     156            0 :                     float v = std::sqrt(vSq);
     157            0 :                     b.vx = (b.vx / v) * maxVel;
     158            0 :                     b.vy = (b.vy / v) * maxVel;
     159              :                 }
     160              : 
     161          341 :                 t.x += b.vx * dt;
     162          341 :                 t.y += b.vy * dt;
     163              : 
     164          341 :                 if (b.invInertia == 0.0f && b.inertia > 0.0f)
     165              :                 {
     166            0 :                     b.invInertia = 1.0f / b.inertia;
     167              :                 }
     168          341 :                 if (b.invInertia > 0.0f)
     169              :                 {
     170          341 :                     float angularAccel = b.torque * b.invInertia - b.angularDrag * b.angularVelocity;
     171          341 :                     b.angularVelocity += angularAccel * dt;
     172          341 :                     const float damping = std::max(0.0f, 1.0f - b.angularFriction * dt);
     173          341 :                     b.angularVelocity *= damping;
     174          341 :                     t.rotation += b.angularVelocity * dt;
     175              :                 }
     176              :                 else
     177              :                 {
     178            0 :                     b.angularVelocity = 0.0f;
     179              :                 }
     180          341 :                 b.torque = 0.0f;
     181              :             }
     182           48 :         };
     183              : 
     184           22 :         if (m_jobSystem && count > 256)
     185              :         {
     186            1 :             const std::size_t batchSize = std::max(std::size_t(64), count / (m_jobSystem->WorkerCount() * 4));
     187            1 :             auto handles = m_jobSystem->Dispatch(count, batchSize, integrateRange);
     188            1 :             m_jobSystem->Wait(handles);
     189            1 :         }
     190              :         else
     191              :         {
     192           21 :             integrateRange(0, count);
     193              :         }
     194           22 :     }
     195              : 
     196        28604 :     void PhysicsIntegrationSystem::UpdateVelocities(ecs::World& world, float dt)
     197              :     {
     198        28604 :         if (!std::isfinite(dt) || dt <= 0.0f)
     199              :         {
     200           32 :             return;
     201              :         }
     202              : 
     203        28572 :         auto* rbStorage = world.GetStorage<RigidBodyComponent>();
     204        28572 :         auto* tfStorage = world.GetStorage<TransformComponent>();
     205        28572 :         if (!rbStorage || !tfStorage) return;
     206              : 
     207        28572 :         auto& bodies = rbStorage->GetData();
     208        28572 :         const auto& entities = rbStorage->GetEntities();
     209        28572 :         size_t count = bodies.size();
     210              : 
     211      2022740 :         for (size_t i = 0; i < count; ++i) {
     212      1994168 :             ecs::EntityId id = entities[i];
     213      1994168 :             TransformComponent* tf = tfStorage->Get(id);
     214      1994168 :             if (tf) {
     215      1994168 :                 auto& b = bodies[i];
     216      1994168 :                 if (b.invMass == 0.0f) continue;
     217              : 
     218      1902199 :                 b.vx = (tf->x - b.lastX) / dt;
     219      1902199 :                 b.vy = (tf->y - b.lastY) / dt;
     220      1902199 :                 b.angularVelocity = (tf->rotation - b.lastAngle) / dt;
     221              : 
     222      1902199 :                 const float maxVel = 50.0f;
     223      1902199 :                 float vSq = b.vx * b.vx + b.vy * b.vy;
     224      1902199 :                 if (vSq > maxVel * maxVel) {
     225       184435 :                     float v = std::sqrt(vSq);
     226       184435 :                     b.vx = (b.vx / v) * maxVel;
     227       184435 :                     b.vy = (b.vy / v) * maxVel;
     228              :                 }
     229              :             }
     230              :         }
     231              :     }
     232              : }
        

Generated by: LCOV version 2.0-1