aboutsummaryrefslogtreecommitdiff
path: root/Client/Source/Phy2DLite/World.cpp
blob: 76e57ea2c1cc6ba9f7c97331044042d967eca176 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "World.h"
#include "Body.h"
#include "Joint.h"
#include "Arbiter.h"
#include "Constants.h"

using namespace Phy2D;

using std::vector;
using std::map;
using std::pair;

typedef map<ArbiterKey, Arbiter>::iterator ArbIter;
typedef pair<ArbiterKey, Arbiter> ArbPair;

bool World::accumulateImpulses = true;
bool World::warmStarting = true;
bool World::positionCorrection = true;

void World::Add(Body* body)
{
    bodies.push_back(body);
}

void World::Add(Joint* joint)
{
    joints.push_back(joint);
}

void World::Clear()
{
    bodies.clear();
    joints.clear();
    arbiters.clear();
}

void World::BroadPhase()
{
    // O(n^2) broad-phase
    for (int i = 0; i < (int)bodies.size(); ++i)
    {
        Body* bi = bodies[i];

        for (int j = i + 1; j < (int)bodies.size(); ++j)
        {
            Body* bj = bodies[j];

            if (bi->invMass == _0 && bj->invMass == _0)
                continue;

            Arbiter newArb(bi, bj);
            ArbiterKey key(bi, bj);

            if (newArb.numContacts > 0)
            {
                ArbIter iter = arbiters.find(key);
                if (iter == arbiters.end())
                {
                    arbiters.insert(ArbPair(key, newArb));
                }
                else
                {
                    iter->second.Update(newArb.contacts, newArb.numContacts);
                }
            }
            else
            {
                arbiters.erase(key);
            }
        }
    }
}

void World::Step(fixed dt)
{
    fixed inv_dt = dt > _0 ? (fixed)_1 / dt : (fixed)_0;

    // Determine overlapping bodies and update contact points.
    BroadPhase();

    // Integrate forces.
    for (int i = 0; i < (int)bodies.size(); ++i)
    {
        Body* b = bodies[i];

        if (b->invMass == _0)
            continue;

        b->velocity += dt * (gravity + b->invMass * b->force);
        b->angularVelocity += dt * b->invI * b->torque;
    }

    // Perform pre-steps.
    for (ArbIter arb = arbiters.begin(); arb != arbiters.end(); ++arb)
    {
        arb->second.PreStep(inv_dt);
    }

    for (int i = 0; i < (int)joints.size(); ++i)
    {
        joints[i]->PreStep(inv_dt);
    }

    // Perform iterations
    for (int i = 0; i < iterations; ++i)
    {
        for (ArbIter arb = arbiters.begin(); arb != arbiters.end(); ++arb)
        {
            arb->second.ApplyImpulse();
        }

        for (int j = 0; j < (int)joints.size(); ++j)
        {
            joints[j]->ApplyImpulse();
        }
    }

    // Integrate Velocities
    for (int i = 0; i < (int)bodies.size(); ++i)
    {
        Body* b = bodies[i];

        b->position += dt * b->velocity;
        b->rotation += dt * b->angularVelocity;

        b->force.Set(_0, _0);
        b->torque = _0;
    }
}