/
PhysicsServer.cpp
executable file
·225 lines (177 loc) · 5.26 KB
/
PhysicsServer.cpp
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// PhysicsServer.cpp: implementation of the PhysicsServer class.
//
// Copyright (2005) Gideon Pertzov
//
// This source code is provided "AS IS" without express or implied warranties.
// You may use this source code in FREEWARE applications you distribute,
// Provided that credit is given to the original author.
// You MAY NOT use the source code in ANY COMMERCIAL APPLICATION
// Without the written consent of the original author.
//
// http://www.gpdev.net
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <cmath>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
//#define new DEBUG_NEW
#include "Mmgr\mmgr.h"
#endif
#include "PhysicsServer.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// create static instance
PhysicsServer PhysicsServer::_instance;
// constructor
PhysicsServer::PhysicsServer() : _world(0),
_space(0),
_contactgroup(0),
_envSpace(0),
_ground(0)
{
ZeroMemory(_wall, sizeof(_wall));
}
PhysicsServer::~PhysicsServer()
{
shutdown();
}
// initialize server (supply world dimensions)
bool PhysicsServer::init(int groundSizeX, int groundSizeY)
{
if (groundSizeX <= 20 || groundSizeY <= 20)
return false;
// create global ODE world
_world = dWorldCreate();
// create global space
_space = dHashSpaceCreate(0);
// create group for handling collisions
_contactgroup = dJointGroupCreate (0);
// make ground a bit slippery :)
_envData.slip = 0.15;
// TODO: let user specify ground surface properties
// set world properties
dWorldSetGravity (_world,0,0,-(PHYS_GRAVITY*PHYS_MASS_SCALE));
dWorldSetERP (_world, 0.6);
// create ground and walls (0,0,0 is the ground's center)
// and put them in their own space
_envSpace = dSimpleSpaceCreate(_space);
_ground = dCreatePlane (_envSpace,0, 0, 1, 0);
dGeomSetData(_ground, (void*)&_envData);
_wall[0] = dCreatePlane(_envSpace, 1, 0, 0, -(groundSizeX/2.0) ); // a,b,c,d
_wall[1] = dCreatePlane(_envSpace, -1, 0, 0, -(groundSizeX/2.0) ); // a,b,c,d
_wall[2] = dCreatePlane(_envSpace, 0, 1, 0, -(groundSizeY/2.0) ); // a,b,c,d
_wall[3] = dCreatePlane(_envSpace, 0, -1, 0, -(groundSizeY/2.0) ); // a,b,c,d
return true;
}
// shutdown server (cleanup)
void PhysicsServer::shutdown()
{
// clear client list
_clientList.clear();
// cleanup
if(_contactgroup)
{
dJointGroupDestroy (_contactgroup);
_contactgroup = NULL;
}
if (_space)
{
dSpaceDestroy (_space);
_space = NULL;
}
if (_world)
{
dWorldDestroy (_world);
_world = NULL;
}
}
// register a physics client with the physics server
bool PhysicsServer::registerClient(PhysicsClient* client)
{
if (client == NULL)
return false;
// init client
bool success = client->init(_world, _space, _envSpace );
// add client to list
if (success)
_clientList.push_back(client);
return success;
}
// static callback for collision handling
void PhysicsServer::collisionCallback (void *data, dGeomID o1, dGeomID o2)
{
assert( data != NULL);
PhysicsServer* serverPtr = (PhysicsServer*)data;
serverPtr->checkCollision(serverPtr, o1, o2);
}
// main collision handling function
void PhysicsServer::checkCollision(void *data, dGeomID o1, dGeomID o2)
{
int i,n;
if( dGeomIsSpace( o1 ) || dGeomIsSpace( o2 ) )
{
dSpaceCollide2( o1, o2, data, &collisionCallback );
}
else
{
int mode = 0;
double slip1 = 0;
double slip2 = 0;
// get bodies
dBodyID body1 = dGeomGetBody(o1);
dBodyID body2 = dGeomGetBody(o2);
// get geom data
PhysGeomData* pData1 = (PhysGeomData*)dGeomGetData(o1);
PhysGeomData* pData2 = (PhysGeomData*)dGeomGetData(o2);
// set contact params according to geom data
if (pData1 != NULL)
slip1 = pData1->slip;
if (pData2 != NULL)
slip2 = pData2->slip;
// set mode
if (slip1 != 0)
mode |= dContactSlip1;
if (slip2 != 0)
mode |= dContactSlip2;
static const int N = 8; // max number of contact points
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
if (n > 0)
{
for (i=0; i<n; i++)
{
contact[i].surface.mode = mode; /*dContactSlip1 | dContactSlip2 | dContactSoftERP | dContactSoftCFM;*/
contact[i].surface.mu = dInfinity;
contact[i].surface.slip1 = slip1;
contact[i].surface.slip2 = slip2;
// contact[i].surface.soft_erp = 0.7;
// contact[i].surface.soft_cfm = 0.1;
dJointID c = dJointCreateContact (_world, _contactgroup, &contact[i]);
dJointAttach (c, body1, body2);
}
}
}
}
// update simulation state
bool PhysicsServer::update(double step)
{
if (_world == 0 || _space == 0)
return false;
// handle collisions
dSpaceCollide (_space, this, &collisionCallback);
// update all clients
list<PhysicsClient*>::const_iterator iter = _clientList.begin();
while(iter != _clientList.end() )
{
(*iter)->update(step);
iter++;
}
// step world
dWorldStep (_world, step);
// remove all contact joints
dJointGroupEmpty (_contactgroup);
return true;
}