/*
Preamble:
    These exact physics calculations are documented in a TeX Document soon to be in the source tree of
    the project. (as of 06/05/26 not in the tree)

    The physics calculations are done using a Semi-Implicit Euler integrator. (big words)

    | Parameter          | Value  | Description                                    | Mapped code identifier       |
    |--------------------|--------|------------------------------------------------|------------------------------|
    | `GRAVITY`          | 1200.0 | Downward acceleration (px s⁻²)                  | `GRAVITY` (constant)         |
    | `RESTITUTION`      | 0.6    | Energy retention after bounce                  | `RESTITUTION` (constant)     |
    | `AIR_DRAG`         | 0.999  | Velocity multiplier per frame                  | `AIR_DRAG` (constant)        |
    | `GROUND_FRICTION`  | 0.8    | Horizontal speed reduction on ground           | `GROUND_FRICTION` (constant) |
    | `REST_THRESHOLD`   | 5.0    | Minimum `\|v_y\|` to consider at rest          | `REST_THRESHOLD` (constant)  |


    06/05/26 - rattatwinko ; when cleaning the source code
*/

#include "physics.h"
#include <cmath>

physics::physics() : physics(0.0, 0.0) {}

physics::physics(double x, double y, double vx, double vy)
    : m_x(x), m_y(y), m_vx(vx), m_vy(vy) {
}

void physics::update(double dt, int screenWidth, int screenHeight, int objWidth, int objHeight) {
    m_vy += GRAVITY * dt;
    m_vx *= AIR_DRAG;
    m_vy *= AIR_DRAG;

    m_x += m_vx * dt;
    m_y += m_vy * dt;

    const double rightBound = static_cast<double>(screenWidth - objWidth);
    const double bottomBound = static_cast<double>(screenHeight - objHeight);

    if (m_x < 0.0) {
        m_x = 0.0;
        m_vx = -m_vx * RESTITUTION;
    }
    else if (m_x > rightBound) {
        m_x = rightBound;
        m_vx = -m_vx * RESTITUTION;
    }

    if (m_y < 0.0) {
        m_y = 0.0;
        m_vy = -m_vy * RESTITUTION;
    }
    else if (m_y > bottomBound) {
        m_y = bottomBound;
        m_vy = -m_vy * RESTITUTION;
        m_vx *= GROUND_FRICTION;
        if (std::fabs(m_vy) < REST_THRESHOLD)
            m_vy = 0.0;
    }
}

void physics::setPos(double x, double y) {
    m_x = x;
    m_y = y;
}

void physics::setVelocity(double vx, double vy) {
    m_vx = vx;
    m_vy = vy;
}

void physics::resetVelocity() {
    m_vx = m_vy = 0.0;
}