1 /*
2   Copyright (C) 2009 Facundo Domínguez
3 
4   This file is part of Spacejunk.
5 
6   Spacejunk is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   Foobar is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "simulation.h"
21 #include "collisionengine.h"
22 #include "functionexts.h"
23 
24 using namespace std;
25 
Simulation(const PlayerState & ps,const list<int> & onStep)26 Simulation::Simulation(const PlayerState & ps,const list<int> &onStep)
27         : physic(ps),tevents(this),onStep(onStep),colPrecision(35),deltaCol(0) {
28     ce=new CollisionEngine<PhysicBody,Simulation>(-20000,-20000,20000,20000,this);
29     for (vector<PhysicBody*>::iterator i=physic.bodies.begin();
30             i!=physic.bodies.end();i++)
31         if (*i) ce->add(*i);
32 };
33 
34 
35 class Collision : public Event {
36 public:
37     Simulation * sim;
38     int c1,c2;
39     Vector2d normal;
40 
Collision()41     Collision() : sim(NULL),c1(-1),c2(-1),normal(0) {};
Collision(Simulation * sim,int c1,int c2,const Vector2d & normal)42     Collision(Simulation * sim,int c1,int c2,const Vector2d & normal):
43             sim(sim),c1(c1),c2(c2),normal(normal) {};
setQueue(Simulation * sim,const TimerId & tid)44     void setQueue(Simulation * sim,const TimerId & tid) {}
45     int fire(Simulation * sim);
cancel(Simulation * sim)46     void cancel(Simulation * sim) {}
47 };
48 
49 
fire(Simulation * sim)50 int Collision::fire(Simulation * sim) {
51     PhysicBody * b1=sim->physic.bodies[c1];
52     PhysicBody * b2=sim->physic.bodies[c2];
53     if (!b1 || !b2) return 0;
54 
55     b1->testForCollision();
56     b2->testForCollision();
57 
58     for (EventListenerList<SimCollisionListener*>::iterator i=sim->collisionListeners.begin();i!=sim->collisionListeners.end();i++)
59         (*i)->evtCollision(sim,b1,b2,normal);
60     return 0;
61 }
62 
63 
handle_col(Simulation * sim,PhysicBody * c1,PhysicBody * c2,real t,const Vector2d & normal)64 int handle_col(Simulation * sim,PhysicBody * c1,PhysicBody * c2,real t,const Vector2d & normal) {
65     int key=(int)(t*sim->physic.getInterpolatedTime());
66     sim->coldata.push_front(make_pair(key,Collision(sim,c1->id,c2->id,normal)));
67     return 0;
68 };
69 
handle_collisions()70 int Simulation::handle_collisions() {
71     ce->step(wrap_collision_handler<PhysicBody,Simulation,handle_col>);
72     if (!coldata.empty()) {
73         int t=physic.unstep();
74         tevents.clock-=t;
75         for (list<std::pair<int,Collision> >::iterator i=coldata.begin();coldata.end()!=i;i++) {
76             tevents.set(i->first,i->second);
77         }
78         coldata.clear();
79         return t;
80     }
81     return 0;
82 };
83 
step(int delta)84 void Simulation::step(int delta) {
85     step(delta,null);
86 };
87 
clear()88 void Simulation::clear() {
89     for (vector<PhysicBody*>::iterator i=physic.bodies.begin();i!=physic.bodies.end();i++) {
90         if (!*i) continue;
91         deleteBody((*i)->id);
92     }
93     physic.clear();
94 };
95 
purge()96 void Simulation::purge() {
97     for (vector<PhysicBody*>::iterator i=physic.bodies.begin();i!=physic.bodies.end();i++) {
98         if (!*i) continue;
99         PhysicBody * pb=*i;
100         deleteBody_without_event((*i)->id);
101         delete pb;
102     }
103     physic.clear();
104     tevents.clear();
105 };
106 
addBody(PhysicBody * c)107 void Simulation::addBody(PhysicBody * c) {
108     physic.addBody(c);
109     ce->add(c);
110 }
111 
addBody(int id,PhysicBody * c)112 void Simulation::addBody(int id,PhysicBody * c) {
113     physic.addBody(id,c);
114     ce->add(c);
115 }
116 
deleteBody(int id)117 void Simulation::deleteBody(int id) {
118     if (id<0 || !physic.bodies[id]) return;
119 
120     for (EventListenerList<SimDeletionListener*>::iterator i=deletionListeners.begin();i!=deletionListeners.end();i++)
121         (*i)->evtDeleteBody(this,id);
122 
123     deleteBody_without_event(id);
124 }
125 
deleteBody_without_event(int id)126 void Simulation::deleteBody_without_event(int id) {
127     ce->deleteBody(physic.bodies[id]);
128     physic.deleteBody(id);
129 }
130 
~Simulation()131 Simulation::~Simulation() {
132     delete ce;
133 };
134 
operator =(const Simulation & orig)135 void Simulation::operator = (const Simulation & orig) {
136     purge();
137 
138     physic=orig.physic;
139     for (vector<PhysicBody*>::const_iterator i=physic.bodies.begin();i!=physic.bodies.end();i++) {
140         if (!*i) continue;
141         ce->add(*i);
142     }
143 
144     colPrecision=orig.colPrecision;
145     deltaCol=orig.deltaCol;
146     orig.tevents.copy(tevents);
147 };
148