00001 #include "collide.H"
00002
00003
00004
00005
00006
00007
00008 CWvec
00009 Collide::_get_move(CWpt& source, CWvec& velocity)
00010 {
00011 Wpt dest = source + velocity;
00012 Wtransf xf;
00013
00014
00015 xf = Wtransf::translation(source - _BSphere->get_bb().center());
00016 _BSphere->transform(xf);
00017
00018 xf = Wtransf::translation(Wpt(source+velocity) - _DestSphere->get_bb().center());
00019 _DestSphere->transform(xf);
00020
00021
00022
00023 _polyBox = _BSphere->get_bb() + _DestSphere->get_bb();
00024
00025
00026 _hitFaces.clear();
00027
00028
00029 for(int i = 0; i < _RootNodes.num(); i++)
00030 buildCollisionList(_RootNodes[i]);
00031
00032
00033 if (_hitFaces.empty())
00034 return velocity;
00035
00036
00037
00038 bool first = true;
00039 double nearDist = -1.0;
00040 Bface* nearCollide = NULL;
00041 Wpt nearIntersect;
00042 Wpt nearFaceIntersect;
00043 Wpt polyIntersect;
00044
00045
00046 for(int i = 0; i < _hitFaces.num(); i++)
00047 {
00048 Wpt camIntersect;
00049
00050 Wpt faceIntersect;
00051
00052 Wpt fOrigin = _hitFaces[i]->centroid();
00053 Wvec fNorm = _hitFaces[i]->norm();
00054
00055
00056 double fDist = intersect(source, -fNorm, fOrigin, fNorm);
00057
00058
00059
00060
00061
00062 Wvec dRad = (source - (fNorm * (_size/fNorm.length())))
00063 - Wpt::Origin();
00064
00065 double radius = _size;
00066
00067
00068 if(fabs(fDist) <= radius)
00069 {
00070
00071 Wvec distNorm = fNorm * (fDist/fNorm.length());
00072 faceIntersect = source + -distNorm;
00073 }
00074 else
00075 {
00076 camIntersect = source + (fNorm * (radius/fNorm.length()));
00077 double t = intersect(camIntersect, velocity, fOrigin, fNorm);
00078
00079
00080 Wvec v = velocity * (t/velocity.length());
00081 faceIntersect = camIntersect + v;
00082 }
00083
00084
00085
00086 polyIntersect = faceIntersect;
00087
00088
00089 if(!_hitFaces[i]->contains(faceIntersect))
00090 {
00091 Wvec bc;
00092 bool inside = false;
00093 polyIntersect = _hitFaces[i]->nearest_pt(faceIntersect,bc,inside);
00094 }
00095
00096
00097 Wvec invVelocity = -velocity;
00098
00099
00100
00101 double t = intersectSphere(source,dRad,polyIntersect,radius);
00102
00103
00104 if(t>=0 && t <= velocity.length())
00105 {
00106 Wvec v = invVelocity * (t/invVelocity.length());
00107 Wpt sPoint = polyIntersect + v;
00108
00109 if (first || t < nearDist)
00110 {
00111 nearDist = t;
00112 nearCollide = _hitFaces[i];
00113 nearIntersect = sPoint;
00114 nearFaceIntersect = polyIntersect;
00115 first = false;
00116 }
00117 }
00118 }
00119
00120
00121 if(first)
00122 return velocity;
00123
00124
00125 Wvec v = velocity * (nearDist / velocity.length());
00126
00127 if (v.length() < .01)
00128 return v;
00129
00130
00131 Wpt newSource = source + v;
00132 Wpt slidePlaneO = nearFaceIntersect;
00133 Wvec slidePlaneN = nearFaceIntersect - newSource;
00134
00135 double time = intersect(source+velocity, slidePlaneN, slidePlaneO, slidePlaneN);
00136
00137
00138 Wvec destinationProjectionNormal = slidePlaneN * (time/slidePlaneN.length());
00139 Wpt newDestinationPoint = dest + destinationProjectionNormal;
00140
00141
00142
00143 Wvec newVelocityVector = newDestinationPoint - newSource;
00144
00145 return _get_move(source + v, newVelocityVector);
00146 }
00147
00148 bool
00149 Collide::_update_scene()
00150 {
00151 CGELlist objects = VIEW::peek()->active();
00152
00153
00154 for (int i=0; i<objects.num(); i++)
00155 {
00156 ARRAY<OctreeNode*> nodes;
00157 GEOMptr geom = GEOM::upcast(objects[i]);
00158
00159 if (geom && BMESH::isa(geom->body()))
00160 {
00161 Bvert_list list;
00162 Bface_list fs;
00163 ARRAY<Wvec> bcs;
00164
00165 nodes += sps(BMESH::upcast(geom->body()), _height, _regularity, _min_dist, fs, bcs);
00166 _RootNodes.push(nodes[0]);
00167 _objs += 1;
00168 }
00169 }
00170
00171
00172 return true;
00173 }
00174
00175
00176 double
00177 Collide::intersect(CWpt& pOrigin, CWvec& pNormal, CWpt& rOrigin, CWvec& rVector)
00178 {
00179 double d = -(Wvec(pOrigin) * pNormal);
00180 return -((pNormal * Wvec(rOrigin) + d) / (pNormal * rVector));
00181 }
00182
00183
00184
00185 double
00186 Collide::intersectSphere(CWpt& rO, CWvec& rV, CWpt& sO, double sR)
00187 {
00188 Wvec Q = sO - rO;
00189 double c = Q.length();
00190 double v = Q * rV;
00191 double d = sR*sR - (c*c - v*v);
00192
00193
00194
00195 if (d < 0.0) return -1.0;
00196
00197
00198
00199 return v - sqrt(d);
00200 }
00201
00202 bool
00203 Collide::buildCollisionList(OctreeNode* node)
00204 {
00205
00206
00207 if(node->get_leaf() != 1 && node->get_leaf() != 0)
00208 return false;
00209
00210
00211 if(!node->overlaps(_polyBox))
00212 return false;
00213
00214
00215
00216 if(node->get_leaf())
00217 _hitFaces = _hitFaces + node->intersects();
00218 else
00219 {
00220 OctreeNode** children = node->get_children();
00221 for(int i = 0; i<8; i++)
00222 buildCollisionList(children[i]);
00223 }
00224 return true;
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 CWvec
00254 Gravity::_get_dir(CWpt& p)
00255 {
00256 cout << "GEtting DIrection" << endl;
00257 cout << _world << endl;
00258
00259
00260 if(_ground == NULL)
00261 return Wvec(0,0,0);
00262
00263 if(_currentGrav == WORLD)
00264 return _strength * _world_dir;
00265
00266 Wpt cent = _ground->bbox().center();
00267 Wpt max = _ground->bbox().max();
00268
00269 if(_currentGrav == GLOBE)
00270 return _strength * (cent-p).normalized();
00271
00272 if(_currentGrav == LANDSCAPE)
00273 return _strength * (Wvec(0,cent[1],0) - Wvec(0,max[1],0)).normalized();
00274
00275 return Wvec(0,0,0);
00276
00277 }
00278
00279
00280 bool
00281 Gravity::set_grav(GEOMptr g, mlib::CWvec& d, int t)
00282 {
00283 cout << "GRAVITY BEING SET" << endl;
00284 _ground = g;
00285 _world_dir = d;
00286 _currentGrav = t;
00287 return true;
00288 }
00289
00290
00291 void
00292 Gravity::set_globe(GEOMptr g)
00293 {
00294 _ground = g;
00295 _globe = true;
00296 _landscape = false;
00297 _world = false;
00298
00299 }
00300 void
00301 Gravity::set_landscape(GEOMptr g)
00302 {
00303 _ground = g;
00304 _globe = false;
00305 _landscape = true;
00306 _world = false;
00307 }
00308 void Gravity::set_world(Wvec d)
00309 {
00310 _world_dir = d;
00311 _globe = false;
00312 _landscape = false;
00313 _world = true;
00314 }
00315
00316
00317
00318