1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 #include "world.hh"
5 #include "body.hh"
6 #include "view.hh"
7 #include <stdlib.h>
8 
World()9 World::World()
10     : _static_friction(0.2), _dynamic_friction(0.2),
11       _angular_friction(0.3), _angular_friction_2(1)
12 {
13 }
14 
15 void
set_static_friction(double d)16 World::set_static_friction(double d)
17 {
18     _static_friction = d;
19 }
20 
21 void
set_dynamic_friction(double d)22 World::set_dynamic_friction(double d)
23 {
24     _dynamic_friction = d;
25 }
26 
27 void
set_angular_friction(double d)28 World::set_angular_friction(double d)
29 {
30     if (d < 0)
31 	d = 0;
32     _angular_friction = d;
33 }
34 
35 void
add(Body * b)36 World::add(Body *b)
37 {
38     _bodies.push_back(b);
39     b->embody(this);
40     if (b->movable())
41 	_moving_bodies.push_back(b);
42     if (b->z_plane() > 0)
43 	_collidable_bodies.push_back(b);
44 }
45 
46 void
remove(Body * b)47 World::remove(Body *b)
48 {
49     for (int i = 0; i < _moving_bodies.size(); i++)
50 	if (_moving_bodies[i] == b) {
51 	    _moving_bodies[i] = _moving_bodies.back();
52 	    _moving_bodies.pop_back();
53 	    break;
54 	}
55     for (int i = 0; i < _collidable_bodies.size(); i++)
56 	if (_collidable_bodies[i] == b) {
57 	    _collidable_bodies[i] = _collidable_bodies.back();
58 	    _collidable_bodies.pop_back();
59 	    break;
60 	}
61     for (int i = 0; i < _bodies.size(); i++)
62 	if (_bodies[i] == b) {
63 	    _bodies[i] = _bodies.back();
64 	    _bodies.pop_back();
65 	    break;
66 	}
67 }
68 
69 extern "C" {
70 static int
body_qsorter(const void * thunk1,const void * thunk2)71 body_qsorter(const void *thunk1, const void *thunk2)
72 {
73     const Body **b1 = (const Body **)thunk1;
74     const Body **b2 = (const Body **)thunk2;
75     return (*b1)->move_phase() - (*b2)->move_phase();
76 }
77 }
78 
79 void
reset()80 World::reset()
81 {
82     for (int i = 0; i < _bodies.size(); i++)
83 	_bodies[i]->reset();
84     if (_bodies.size())
85 	qsort(&_bodies[0], _bodies.size(), sizeof(Body *), body_qsorter);
86 }
87 
88 void
trail_snapshot()89 World::trail_snapshot()
90 {
91     for (int i = 0; i < _bodies.size(); i++)
92 	_bodies[i]->trail_snapshot();
93 }
94 
95 void
random_place(bool do_movable,bool do_stationary,View * view)96 World::random_place(bool do_movable, bool do_stationary, View *view)
97 {
98     Point ll = view->lower_left();
99     Point ur = view->upper_right();
100     Point delta = ur - ll;
101 
102     for (int i = 0; i < _bodies.size(); i++)
103 	if (_bodies[i]->movable() ? do_movable : do_stationary) {
104 	    Point p = ll;
105 	    p.x += ((double)rand() / RAND_MAX) * delta.x;
106 	    p.y += ((double)rand() / RAND_MAX) * delta.y;
107 	    double rotation = ((double)rand() / RAND_MAX) * 2*M_PI;
108 	    _bodies[i]->place(p, rotation);
109 	}
110 
111     reset();
112 }
113 
114 void
draw(View * v) const115 World::draw(View *v) const
116 {
117     v->clear();
118     for (int i = 0; i < _bodies.size(); i++)
119 	_bodies[i]->draw(v);
120     v->expose();
121 }
122 
123 #define MOVE_TIME_QUANTUM 0.1
124 void
move() const125 World::move() const
126 {
127     for (int i = 0; i < _bodies.size(); i++)
128 	_bodies[i]->move(MOVE_TIME_QUANTUM);
129 }
130 
131 void
check_collisions() const132 World::check_collisions() const
133 {
134     int cs = _collidable_bodies.size();
135     if (cs) {
136 	Body * const *cb = _collidable_bodies.begin();
137 	for (int i = 0; i < cs - 1; i++)
138 	    for (int j = i + 1; j < cs; j++)
139 		if (cb[i]->might_collide(cb[j]))
140 		    cb[i]->collide(cb[j]);
141     }
142 }
143