Panda3D
|
00001 // Filename: physxCloth.cxx 00002 // Created by: enn0x (30Mar10) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "physxCloth.h" 00016 #include "physxClothDesc.h" 00017 #include "physxScene.h" 00018 #include "physxGroupsMask.h" 00019 #include "physxShape.h" 00020 #include "physxManager.h" 00021 00022 #include "boundingBox.h" 00023 00024 TypeHandle PhysxCloth::_type_handle; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: PhysxCloth::link 00028 // Access: Public 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 void PhysxCloth:: 00032 link(NxCloth *clothPtr) { 00033 00034 // Link self 00035 _ptr = clothPtr; 00036 _error_type = ET_ok; 00037 _ptr->userData = this; 00038 00039 set_name(clothPtr->getName()); 00040 00041 PhysxScene *scene = (PhysxScene *)_ptr->getScene().userData; 00042 scene->_cloths.add(this); 00043 } 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: PhysxCloth::unlink 00047 // Access: Public 00048 // Description: 00049 //////////////////////////////////////////////////////////////////// 00050 void PhysxCloth:: 00051 unlink() { 00052 00053 // Unlink self 00054 _ptr->userData = NULL; 00055 _error_type = ET_released; 00056 00057 PhysxScene *scene = (PhysxScene *)_ptr->getScene().userData; 00058 scene->_cloths.remove(this); 00059 00060 _node = NULL; 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: PhysxCloth::release 00065 // Access: Published 00066 // Description: 00067 //////////////////////////////////////////////////////////////////// 00068 void PhysxCloth:: 00069 release() { 00070 00071 nassertv(_error_type == ET_ok); 00072 00073 unlink(); 00074 _ptr->getScene().releaseCloth(*_ptr); 00075 _ptr = NULL; 00076 } 00077 00078 //////////////////////////////////////////////////////////////////// 00079 // Function: PhysxCloth::update 00080 // Access: Public 00081 // Description: 00082 //////////////////////////////////////////////////////////////////// 00083 void PhysxCloth:: 00084 update() { 00085 00086 if (_node) { 00087 00088 // Update node mesh data 00089 _node->update(); 00090 00091 // Update node bounding volume 00092 NxBounds3 bounds; 00093 _ptr->getWorldBounds(bounds); 00094 00095 BoundingBox bb(PhysxManager::nxVec3_to_point3(bounds.min), 00096 PhysxManager::nxVec3_to_point3(bounds.max)); 00097 _node->set_bounds(&bb); 00098 } 00099 } 00100 00101 //////////////////////////////////////////////////////////////////// 00102 // Function: PhysxCloth::get_scene 00103 // Access: Published 00104 // Description: Returns the scene which this cloth belongs to. 00105 //////////////////////////////////////////////////////////////////// 00106 PhysxScene *PhysxCloth:: 00107 get_scene() const { 00108 00109 nassertr(_error_type == ET_ok, NULL); 00110 return (PhysxScene *)_ptr->getScene().userData; 00111 } 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: PhysxCloth::get_cloth_node 00115 // Access: Published 00116 // Description: 00117 //////////////////////////////////////////////////////////////////// 00118 PhysxClothNode *PhysxCloth:: 00119 get_cloth_node() const { 00120 00121 nassertr(_error_type == ET_ok, NULL); 00122 return _node; 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: PhysxCloth::create_cloth_node 00127 // Access: Published 00128 // Description: 00129 //////////////////////////////////////////////////////////////////// 00130 PhysxClothNode *PhysxCloth:: 00131 create_cloth_node(const char *name) { 00132 00133 nassertr(_error_type == ET_ok, NULL); 00134 00135 _node = new PhysxClothNode(name); 00136 _node->allocate(this); 00137 00138 return _node; 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: PhysxCloth::set_name 00143 // Access: Published 00144 // Description: Sets a name string for the object that can be 00145 // retrieved with get_name(). 00146 // This is for debugging and is not used by the 00147 // engine. 00148 //////////////////////////////////////////////////////////////////// 00149 void PhysxCloth:: 00150 set_name(const char *name) { 00151 00152 nassertv(_error_type == ET_ok); 00153 00154 _name = name ? name : ""; 00155 _ptr->setName(_name.c_str()); 00156 } 00157 00158 //////////////////////////////////////////////////////////////////// 00159 // Function: PhysxCloth::get_name 00160 // Access: Published 00161 // Description: Retrieves the name string. 00162 //////////////////////////////////////////////////////////////////// 00163 const char *PhysxCloth:: 00164 get_name() const { 00165 00166 nassertr(_error_type == ET_ok, ""); 00167 return _ptr->getName(); 00168 } 00169 00170 //////////////////////////////////////////////////////////////////// 00171 // Function: PhysxCloth::set_group 00172 // Access: Published 00173 // Description: Sets which collision group this cloth is part of. 00174 // Collision group must be between 0 and 31. 00175 //////////////////////////////////////////////////////////////////// 00176 void PhysxCloth:: 00177 set_group(unsigned int group) { 00178 00179 nassertv(_error_type == ET_ok); 00180 nassertv(group >= 0 && group < 32); 00181 _ptr->setGroup(group); 00182 } 00183 00184 //////////////////////////////////////////////////////////////////// 00185 // Function: PhysxCloth::get_group 00186 // Access: Published 00187 // Description: Retrieves the collision group this cloth is part 00188 // of. 00189 //////////////////////////////////////////////////////////////////// 00190 unsigned int PhysxCloth:: 00191 get_group() const { 00192 00193 nassertr(_error_type == ET_ok, 0); 00194 return _ptr->getGroup(); 00195 } 00196 00197 //////////////////////////////////////////////////////////////////// 00198 // Function: PhysxCloth::set_thickness 00199 // Access: Published 00200 // Description: Sets the cloth thickness (must be positive). 00201 //////////////////////////////////////////////////////////////////// 00202 void PhysxCloth:: 00203 set_thickness(float thickness) { 00204 00205 nassertv(_error_type == ET_ok); 00206 _ptr->setThickness(thickness); 00207 } 00208 00209 //////////////////////////////////////////////////////////////////// 00210 // Function: PhysxCloth::get_thickness 00211 // Access: Published 00212 // Description: Gets the cloth thickness. 00213 //////////////////////////////////////////////////////////////////// 00214 float PhysxCloth:: 00215 get_thickness() const { 00216 00217 nassertr(_error_type == ET_ok, 0.0f); 00218 return _ptr->getThickness(); 00219 } 00220 00221 //////////////////////////////////////////////////////////////////// 00222 // Function: PhysxCloth::get_density 00223 // Access: Published 00224 // Description: Gets the cloth density. 00225 //////////////////////////////////////////////////////////////////// 00226 float PhysxCloth:: 00227 get_density() const { 00228 00229 nassertr(_error_type == ET_ok, 0.0f); 00230 return _ptr->getDensity(); 00231 } 00232 00233 //////////////////////////////////////////////////////////////////// 00234 // Function: PhysxCloth::get_relative_grid_spacing 00235 // Access: Published 00236 // Description: Gets the relative grid spacing for the broad 00237 // phase. The cloth is represented by a set of 00238 // world aligned cubical cells in broad phase. The 00239 // size of these cells is determined by multiplying 00240 // the length of the diagonal of the AABB of the 00241 // initial soft body size with this constant. 00242 //////////////////////////////////////////////////////////////////// 00243 float PhysxCloth:: 00244 get_relative_grid_spacing() const { 00245 00246 nassertr(_error_type == ET_ok, 0.0f); 00247 return _ptr->getRelativeGridSpacing(); 00248 } 00249 00250 //////////////////////////////////////////////////////////////////// 00251 // Function: PhysxCloth::get_num_particles 00252 // Access: Published 00253 // Description: Gets the number of cloth particles. 00254 //////////////////////////////////////////////////////////////////// 00255 unsigned int PhysxCloth:: 00256 get_num_particles() { 00257 00258 nassertr(_error_type == ET_ok, 0); 00259 return _ptr->getNumberOfParticles(); 00260 } 00261 00262 //////////////////////////////////////////////////////////////////// 00263 // Function: PhysxCloth::set_flag 00264 // Access: Published 00265 // Description: Sets the value of a single flag. 00266 //////////////////////////////////////////////////////////////////// 00267 void PhysxCloth:: 00268 set_flag(PhysxClothFlag flag, bool value) { 00269 00270 nassertv(_error_type == ET_ok); 00271 00272 NxU32 flags = _ptr->getFlags(); 00273 00274 if (value == true) { 00275 flags |= flag; 00276 } 00277 else { 00278 flags &= ~(flag); 00279 } 00280 00281 _ptr->setFlags(flags); 00282 } 00283 00284 //////////////////////////////////////////////////////////////////// 00285 // Function: PhysxCloth::get_flag 00286 // Access: Published 00287 // Description: Retrieves the value of a single flag. 00288 //////////////////////////////////////////////////////////////////// 00289 bool PhysxCloth:: 00290 get_flag(PhysxClothFlag flag) const { 00291 00292 nassertr(_error_type == ET_ok, false); 00293 00294 return (_ptr->getFlags() & flag) ? true : false; 00295 } 00296 00297 //////////////////////////////////////////////////////////////////// 00298 // Function: PhysxCloth::set_groups_mask 00299 // Access: Published 00300 // Description: Sets 128-bit mask used for collision filtering. 00301 //////////////////////////////////////////////////////////////////// 00302 void PhysxCloth:: 00303 set_groups_mask(const PhysxGroupsMask &mask) { 00304 00305 nassertv(_error_type == ET_ok); 00306 00307 NxGroupsMask _mask = mask.get_mask(); 00308 _ptr->setGroupsMask(_mask); 00309 } 00310 00311 //////////////////////////////////////////////////////////////////// 00312 // Function: PhysxCloth::get_groups_mask 00313 // Access: Published 00314 // Description: Gets the 128-bit groups mask used for collision 00315 // filtering. 00316 //////////////////////////////////////////////////////////////////// 00317 PhysxGroupsMask PhysxCloth:: 00318 get_groups_mask() const { 00319 00320 PhysxGroupsMask mask; 00321 00322 nassertr(_error_type == ET_ok, mask); 00323 00324 NxGroupsMask _mask = _ptr->getGroupsMask(); 00325 mask.set_mask(_mask); 00326 00327 return mask; 00328 } 00329 00330 //////////////////////////////////////////////////////////////////// 00331 // Function: PhysxCloth::is_sleeping 00332 // Access: Published 00333 // Description: Returns true if this cloth is sleeping. 00334 // 00335 // When a cloth does not move for a period of time, 00336 // it is no longer simulated in order to save time. 00337 // This state is called sleeping. However, because the 00338 // object automatically wakes up when it is either 00339 // touched by an awake object, or one of its 00340 // properties is changed by the user, the entire sleep 00341 // mechanism should be transparent to the user. 00342 //////////////////////////////////////////////////////////////////// 00343 bool PhysxCloth:: 00344 is_sleeping() const { 00345 00346 nassertr(_error_type == ET_ok, false); 00347 return _ptr->isSleeping(); 00348 } 00349 00350 //////////////////////////////////////////////////////////////////// 00351 // Function: PhysxCloth::wake_up 00352 // Access: Published 00353 // Description: Wakes up the cloth if it is sleeping. 00354 // 00355 // The wakeCounterValue determines how long until the 00356 // body is put to sleep, a value of zero means that 00357 // the body is sleeping. wake_up(0) is equivalent to 00358 // PhysxCloth::put_to_sleep(). 00359 //////////////////////////////////////////////////////////////////// 00360 void PhysxCloth:: 00361 wake_up(float wakeCounterValue) { 00362 00363 nassertv(_error_type == ET_ok); 00364 _ptr->wakeUp(wakeCounterValue); 00365 } 00366 00367 //////////////////////////////////////////////////////////////////// 00368 // Function: PhysxCloth::put_to_sleep 00369 // Access: Published 00370 // Description: Forces the cloth to sleep. 00371 // 00372 // The cloth will stay asleep until the next 00373 // call to simulate, and will not wake up until then 00374 // even when otherwise it would (for example a force 00375 // is applied to it). It can however wake up during 00376 // the next do_physics call. 00377 //////////////////////////////////////////////////////////////////// 00378 void PhysxCloth:: 00379 put_to_sleep() { 00380 00381 nassertv(_error_type == ET_ok); 00382 _ptr->putToSleep(); 00383 } 00384 00385 //////////////////////////////////////////////////////////////////// 00386 // Function: PhysxCloth::set_sleep_linear_velocity 00387 // Access: Published 00388 // Description: Sets the linear velocity below which an cloth 00389 // may go to sleep. Cloths whose linear velocity is 00390 // above this threshold will not be put to sleep. 00391 // 00392 // Setting the sleep angular/linear velocity only 00393 // makes sense when the BF_energy_sleep_test is not 00394 // set. 00395 //////////////////////////////////////////////////////////////////// 00396 void PhysxCloth:: 00397 set_sleep_linear_velocity(float threshold) { 00398 00399 nassertv(_error_type == ET_ok); 00400 _ptr->setSleepLinearVelocity(threshold); 00401 } 00402 00403 //////////////////////////////////////////////////////////////////// 00404 // Function: PhysxCloth::get_sleep_linear_velocity 00405 // Access: Published 00406 // Description: Returns the linear velocity below which an soft 00407 // body may go to sleep. cloths whose linear velocity 00408 // is above this threshold will not be put to sleep. 00409 //////////////////////////////////////////////////////////////////// 00410 float PhysxCloth:: 00411 get_sleep_linear_velocity() const { 00412 00413 nassertr(_error_type == ET_ok, 0.0f); 00414 return _ptr->getSleepLinearVelocity(); 00415 } 00416 00417 //////////////////////////////////////////////////////////////////// 00418 // Function: PhysxCloth::attach_vertex_to_global_pos 00419 // Access: Published 00420 // Description: Attaches a cloth vertex to a position in world 00421 // space. 00422 //////////////////////////////////////////////////////////////////// 00423 void PhysxCloth:: 00424 attach_vertex_to_global_pos(unsigned int vertexId, LPoint3f const &pos) { 00425 00426 nassertv(_error_type == ET_ok); 00427 nassertv(!pos.is_nan()); 00428 00429 _ptr->attachVertexToGlobalPosition(vertexId, PhysxManager::point3_to_nxVec3(pos)); 00430 } 00431 00432 //////////////////////////////////////////////////////////////////// 00433 // Function: PhysxCloth::attach_to_shape 00434 // Access: Published 00435 // Description: Attaches the cloth to a shape. All cloth points 00436 // currently inside the shape are attached. 00437 // 00438 // This method only works with primitive and convex 00439 // shapes. Since the inside of a general triangle mesh 00440 // is not clearly defined. 00441 //////////////////////////////////////////////////////////////////// 00442 void PhysxCloth:: 00443 attach_to_shape(PhysxShape *shape) { 00444 00445 nassertv(_error_type == ET_ok); 00446 nassertv(shape); 00447 00448 NxU32 attachmentFlags = 0; // --TODO-- 00449 _ptr->attachToShape(shape->ptr(), attachmentFlags); 00450 } 00451 00452 //////////////////////////////////////////////////////////////////// 00453 // Function: PhysxCloth::attach_to_colliding_shapes 00454 // Access: Published 00455 // Description: Attaches the cloth to all shapes, currently 00456 // colliding. 00457 // 00458 // This method only works with primitive and convex 00459 // shapes. Since the inside of a general triangle mesh 00460 // is not clearly defined. 00461 //////////////////////////////////////////////////////////////////// 00462 void PhysxCloth:: 00463 attach_to_colliding_shapes() { 00464 00465 nassertv(_error_type == ET_ok); 00466 00467 NxU32 attachmentFlags = 0; // --TODO-- 00468 _ptr->attachToCollidingShapes(attachmentFlags); 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: PhysxCloth::detach_from_shape 00473 // Access: Published 00474 // Description: Detaches the cloth from a shape it has been 00475 // attached to before. 00476 // 00477 // If the cloth has not been attached to the shape 00478 // before, the call has no effect. 00479 //////////////////////////////////////////////////////////////////// 00480 void PhysxCloth:: 00481 detach_from_shape(PhysxShape *shape) { 00482 00483 nassertv(_error_type == ET_ok); 00484 nassertv(shape); 00485 00486 _ptr->detachFromShape(shape->ptr()); 00487 } 00488 00489 //////////////////////////////////////////////////////////////////// 00490 // Function: PhysxCloth::free_vertex 00491 // Access: Published 00492 // Description: Frees a previously attached cloth point. 00493 //////////////////////////////////////////////////////////////////// 00494 void PhysxCloth:: 00495 free_vertex(unsigned int vertexId) { 00496 00497 nassertv(_error_type == ET_ok); 00498 _ptr->freeVertex(vertexId); 00499 } 00500 00501 //////////////////////////////////////////////////////////////////// 00502 // Function: PhysxCloth::attach_vertex_to_shape 00503 // Access: Published 00504 // Description: Attaches a cloth vertex to a local position within 00505 // a shape. 00506 //////////////////////////////////////////////////////////////////// 00507 void PhysxCloth:: 00508 attach_vertex_to_shape(unsigned int vertexId, PhysxShape *shape, LPoint3f const &localPos) { 00509 00510 nassertv(_error_type == ET_ok); 00511 nassertv(!localPos.is_nan()); 00512 nassertv(shape); 00513 00514 NxU32 attachmentFlags = 0; // --TODO-- 00515 _ptr->attachVertexToShape(vertexId, shape->ptr(), 00516 PhysxManager::point3_to_nxVec3(localPos), 00517 attachmentFlags); 00518 } 00519 00520 //////////////////////////////////////////////////////////////////// 00521 // Function: PhysxCloth::get_vertex_attachment_status 00522 // Access: Published 00523 // Description: Return the attachment status of the given vertex. 00524 //////////////////////////////////////////////////////////////////// 00525 PhysxEnums::PhysxVertexAttachmentStatus PhysxCloth:: 00526 get_vertex_attachment_status(unsigned int vertexId) const { 00527 00528 nassertr(_error_type == ET_ok, VAS_none); 00529 // --TODO-- nassertr(vertexId < _ptr->getNumberOfParticles(), VAS_none); 00530 00531 return (PhysxVertexAttachmentStatus) _ptr->getVertexAttachmentStatus(vertexId); 00532 } 00533 00534 //////////////////////////////////////////////////////////////////// 00535 // Function: PhysxCloth::get_vertex_attachment_shape 00536 // Access: Published 00537 // Description: Returns the pointer to an attached shape pointer 00538 // of the given vertex. If the vertex is not attached 00539 // or attached to a global position, NULL is returned. 00540 //////////////////////////////////////////////////////////////////// 00541 PhysxShape *PhysxCloth:: 00542 get_vertex_attachment_shape(unsigned int vertexId) const { 00543 00544 nassertr(_error_type == ET_ok, NULL); 00545 // --TODO-- nassertr(vertexId < _ptr->getNumberOfParticles(), NULL); 00546 00547 NxShape *shapePtr = _ptr->getVertexAttachmentShape(vertexId); 00548 PhysxShape *shape = shapePtr ? (PhysxShape *)(shapePtr->userData) : NULL; 00549 00550 return shape; 00551 } 00552 00553 //////////////////////////////////////////////////////////////////// 00554 // Function: PhysxCloth::get_vertex_attachment_pos 00555 // Access: Published 00556 // Description: Returns the attachment position of the given 00557 // vertex. If the vertex is attached to shape, the 00558 // position local to the shape's pose is returned. If 00559 // the vertex is not attached, the return value is 00560 // undefined. 00561 //////////////////////////////////////////////////////////////////// 00562 LPoint3f PhysxCloth:: 00563 get_vertex_attachment_pos(unsigned int vertexId) const { 00564 00565 nassertr(_error_type == ET_ok, LPoint3f::zero()); 00566 // --TODO-- nassertr(vertexId < _ptr->getNumberOfParticles(), LPoint3f::zero()); 00567 00568 return PhysxManager::nxVec3_to_point3(_ptr->getVertexAttachmentPosition(vertexId)); 00569 } 00570 00571 //////////////////////////////////////////////////////////////////// 00572 // Function: PhysxCloth::set_external_acceleration 00573 // Access: Published 00574 // Description: Sets an external acceleration which affects all non 00575 // attached particles of the cloth. 00576 //////////////////////////////////////////////////////////////////// 00577 void PhysxCloth:: 00578 set_external_acceleration(LVector3f const &acceleration) { 00579 00580 nassertv(_error_type == ET_ok); 00581 nassertv_always(!acceleration.is_nan()); 00582 00583 _ptr->setExternalAcceleration(PhysxManager::vec3_to_nxVec3(acceleration)); 00584 } 00585 00586 //////////////////////////////////////////////////////////////////// 00587 // Function: PhysxCloth::set_wind_acceleration 00588 // Access: Published 00589 // Description: Sets an acceleration acting normal to the cloth 00590 // surface at each vertex. 00591 //////////////////////////////////////////////////////////////////// 00592 void PhysxCloth:: 00593 set_wind_acceleration(LVector3f const &acceleration) { 00594 00595 nassertv(_error_type == ET_ok); 00596 nassertv_always(!acceleration.is_nan()); 00597 00598 _ptr->setWindAcceleration(PhysxManager::vec3_to_nxVec3(acceleration)); 00599 } 00600 00601 //////////////////////////////////////////////////////////////////// 00602 // Function: PhysxCloth::get_external_acceleration 00603 // Access: Published 00604 // Description: Retrieves the external acceleration which affects 00605 // all non attached particles of the cloth. 00606 //////////////////////////////////////////////////////////////////// 00607 LVector3f PhysxCloth:: 00608 get_external_acceleration() const { 00609 00610 nassertr(_error_type == ET_ok, LVector3f::zero()); 00611 return PhysxManager::nxVec3_to_vec3(_ptr->getExternalAcceleration()); 00612 } 00613 00614 //////////////////////////////////////////////////////////////////// 00615 // Function: PhysxCloth::get_wind_acceleration 00616 // Access: Published 00617 // Description: Retrieves the acceleration acting normal to the 00618 // cloth surface at each vertex 00619 //////////////////////////////////////////////////////////////////// 00620 LVector3f PhysxCloth:: 00621 get_wind_acceleration() const { 00622 00623 nassertr(_error_type == ET_ok, LVector3f::zero()); 00624 return PhysxManager::nxVec3_to_vec3(_ptr->getWindAcceleration()); 00625 } 00626 00627 //////////////////////////////////////////////////////////////////// 00628 // Function: PhysxCloth::add_force_at_vertex 00629 // Access: Published 00630 // Description: Applies a force (or impulse) defined in the 00631 // global coordinate frame, to a particular vertex 00632 // of the cloth. 00633 //////////////////////////////////////////////////////////////////// 00634 void PhysxCloth:: 00635 add_force_at_vertex(LVector3f const &force, int vertexId, PhysxForceMode mode) { 00636 00637 nassertv(_error_type == ET_ok); 00638 _ptr->addForceAtVertex(PhysxManager::vec3_to_nxVec3(force), 00639 vertexId, 00640 (NxForceMode) mode); 00641 } 00642 00643 //////////////////////////////////////////////////////////////////// 00644 // Function: PhysxCloth::add_force_at_pos 00645 // Access: Published 00646 // Description: Applies a radial force (or impulse) at a 00647 // particular position. All vertices within radius 00648 // will be affected with a quadratic drop-off. 00649 //////////////////////////////////////////////////////////////////// 00650 void PhysxCloth:: 00651 add_force_at_pos(LPoint3f const &pos, float magnitude, float radius, PhysxForceMode mode) { 00652 00653 nassertv(_error_type == ET_ok); 00654 _ptr->addForceAtPos(PhysxManager::point3_to_nxVec3(pos), 00655 magnitude, 00656 radius, 00657 (NxForceMode) mode); 00658 } 00659 00660 //////////////////////////////////////////////////////////////////// 00661 // Function: PhysxCloth::add_directed_force_at_pos 00662 // Access: Published 00663 // Description: Applies a directed force (or impulse) at a 00664 // particular position. All vertices within radius 00665 // will be affected with a quadratic drop-off. 00666 //////////////////////////////////////////////////////////////////// 00667 void PhysxCloth:: 00668 add_directed_force_at_pos(LPoint3f const &pos, LVector3f const &force, float radius, PhysxForceMode mode) { 00669 00670 nassertv(_error_type == ET_ok); 00671 _ptr->addDirectedForceAtPos(PhysxManager::point3_to_nxVec3(pos), 00672 PhysxManager::vec3_to_nxVec3(force), 00673 radius, 00674 (NxForceMode) mode); 00675 } 00676