Ver Fonte

Cloth simulation and rendering. No tearing yet.

enn0x há 15 anos atrás
pai
commit
8dd0b6ca96

+ 4 - 0
panda/src/physx/config_physx.cxx

@@ -22,7 +22,9 @@
 #include "physxCapsuleController.h"
 #include "physxCapsuleForceFieldShape.h"
 #include "physxCapsuleShape.h"
+#include "physxCloth.h"
 #include "physxClothMesh.h"
+#include "physxClothNode.h"
 #include "physxContactPair.h"
 #include "physxContactPoint.h"
 #include "physxController.h"
@@ -118,7 +120,9 @@ init_libphysx() {
   PhysxCapsuleController::init_type();
   PhysxCapsuleForceFieldShape::init_type();
   PhysxCapsuleShape::init_type();
+  PhysxCloth::init_type();
   PhysxClothMesh::init_type();
+  PhysxClothNode::init_type();
   PhysxContactPair::init_type();
   PhysxContactPoint::init_type();
   PhysxController::init_type();

+ 61 - 0
panda/src/physx/physxCloth.I

@@ -0,0 +1,61 @@
+// Filename: physxCloth.I
+// Created by:  enn0x (30Mar10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PhysxCloth::
+PhysxCloth() : PhysxObject() {
+
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PhysxCloth::
+~PhysxCloth() {
+
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::ls
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PhysxCloth::
+ls() const {
+
+  ls(nout);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::ls
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PhysxCloth::
+ls(ostream &out, int indent_level) const {
+
+  indent(out, indent_level) << get_type().get_name()
+                            << " (at 0x" << this << ")";
+  //out << " N:0x" << _node;
+  out << "\n";
+}
+

+ 669 - 0
panda/src/physx/physxCloth.cxx

@@ -0,0 +1,669 @@
+// Filename: physxCloth.cxx
+// Created by:  enn0x (30Mar10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "physxCloth.h"
+#include "physxClothDesc.h"
+#include "physxScene.h"
+#include "physxGroupsMask.h"
+#include "physxShape.h"
+#include "physxManager.h"
+
+#include "boundingBox.h"
+
+TypeHandle PhysxCloth::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::link
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+link(NxCloth *ptr) {
+
+  // Link self
+  _ptr = ptr;
+  _error_type = ET_ok;
+  _ptr->userData = this;
+
+  PhysxScene *scene = (PhysxScene *)_ptr->getScene().userData;
+  scene->_cloths.add(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::unlink
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+unlink() {
+
+  // Unlink self
+  _ptr->userData = NULL;
+  _error_type = ET_released;
+
+  PhysxScene *scene = (PhysxScene *)_ptr->getScene().userData;
+  scene->_cloths.remove(this);
+
+  _node = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::release
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+release() {
+
+  nassertv(_error_type == ET_ok);
+
+  unlink();
+  _ptr->getScene().releaseCloth(*_ptr);
+  _ptr = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::update
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+update() {
+
+  // Update node mesh data
+  _node->update();
+
+  // Update node bounding volume
+  NxBounds3 bounds;
+  _ptr->getWorldBounds(bounds);
+
+  BoundingBox bb(PhysxManager::nxVec3_to_point3(bounds.min),
+                 PhysxManager::nxVec3_to_point3(bounds.max));
+  _node->set_bounds(&bb);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_scene
+//       Access: Published
+//  Description: Returns the scene which this cloth belongs to.
+////////////////////////////////////////////////////////////////////
+PhysxScene *PhysxCloth::
+get_scene() const {
+
+  nassertr(_error_type == ET_ok, NULL);
+  return (PhysxScene *)_ptr->getScene().userData;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_cloth_node
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PhysxClothNode *PhysxCloth::
+get_cloth_node() const {
+
+  nassertr(_error_type == ET_ok, NULL);
+  return _node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::create_cloth_node
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PhysxClothNode *PhysxCloth::
+create_cloth_node(const char *name) {
+
+  nassertr(_error_type == ET_ok, NULL);
+
+  _node = new PhysxClothNode(name);
+  _node->allocate(this);
+
+  return _node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_name
+//       Access: Published
+//  Description: Sets a name string for the object that can be
+//               retrieved with get_name(). 
+//               This is for debugging and is not used by the
+//               engine.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_name(const char *name) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->setName(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_name
+//       Access: Published
+//  Description: Retrieves the name string.
+////////////////////////////////////////////////////////////////////
+const char *PhysxCloth::
+get_name() const {
+
+  nassertr(_error_type == ET_ok, "");
+  return _ptr->getName();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_group
+//       Access: Published
+//  Description: Sets which collision group this cloth is part of.
+//               Collision group must be between 0 and 31.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_group(unsigned int group) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv(group >= 0 && group < 32);
+  _ptr->setGroup(group);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_group
+//       Access: Published
+//  Description: Retrieves the collision group this cloth is part
+//               of.
+////////////////////////////////////////////////////////////////////
+unsigned int PhysxCloth::
+get_group() const {
+
+  nassertr(_error_type == ET_ok, 0);
+  return _ptr->getGroup();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_thickness
+//       Access: Published
+//  Description: Sets the cloth thickness (must be positive).
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_thickness(float thickness) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->setFriction(thickness);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_thickness
+//       Access: Published
+//  Description: Gets the cloth thickness.
+////////////////////////////////////////////////////////////////////
+float PhysxCloth::
+get_thickness() const {
+
+  nassertr(_error_type == ET_ok, 0.0f);
+  return _ptr->getThickness();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_density
+//       Access: Published
+//  Description: Gets the cloth density.
+////////////////////////////////////////////////////////////////////
+float PhysxCloth::
+get_density() const {
+
+  nassertr(_error_type == ET_ok, 0.0f);
+  return _ptr->getDensity();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_relative_grid_spacing
+//       Access: Published
+//  Description: Gets the relative grid spacing for the broad
+//               phase. The cloth is represented by a set of
+//               world aligned cubical cells in broad phase. The
+//               size of these cells is determined by multiplying
+//               the length of the diagonal of the AABB of the
+//               initial soft body size with this constant.
+////////////////////////////////////////////////////////////////////
+float PhysxCloth::
+get_relative_grid_spacing() const {
+
+  nassertr(_error_type == ET_ok, 0.0f);
+  return _ptr->getRelativeGridSpacing();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_num_particles
+//       Access: Published
+//  Description: Gets the number of cloth particles.
+////////////////////////////////////////////////////////////////////
+unsigned int PhysxCloth::
+get_num_particles() {
+
+  nassertr(_error_type == ET_ok, 0);
+  return _ptr->getNumberOfParticles();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_flag
+//       Access: Published
+//  Description: Sets the value of a single flag.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_flag(PhysxClothFlag flag, bool value) {
+
+  nassertv(_error_type == ET_ok);
+
+  NxU32 flags = _ptr->getFlags();
+
+  if (value == true) {
+    flags |= flag;
+  } 
+  else {
+    flags &= ~(flag);
+  }
+
+  _ptr->setFlags(flags);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_flag
+//       Access: Published
+//  Description: Retrieves the value of a single flag.
+////////////////////////////////////////////////////////////////////
+bool PhysxCloth::
+get_flag(PhysxClothFlag flag) const {
+
+  nassertr(_error_type == ET_ok, false);
+
+  return (_ptr->getFlags() & flag) ? true : false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_groups_mask
+//       Access: Published
+//  Description: Sets 128-bit mask used for collision filtering.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_groups_mask(const PhysxGroupsMask &mask) {
+
+  nassertv(_error_type == ET_ok);
+
+  NxGroupsMask _mask = mask.get_mask();
+  _ptr->setGroupsMask(_mask);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_groups_mask
+//       Access: Published
+//  Description: Gets the 128-bit groups mask used for collision
+//               filtering.
+////////////////////////////////////////////////////////////////////
+PhysxGroupsMask PhysxCloth::
+get_groups_mask() const {
+
+  PhysxGroupsMask mask;
+
+  nassertr(_error_type == ET_ok, mask);
+
+  NxGroupsMask _mask = _ptr->getGroupsMask();
+  mask.set_mask(_mask);
+
+  return mask;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::is_sleeping
+//       Access: Published
+//  Description: Returns true if this cloth is sleeping. 
+//
+//               When a cloth does not move for a period of time,
+//               it is no longer simulated in order to save time.
+//               This state is called sleeping. However, because the
+//               object automatically wakes up when it is either
+//               touched by an awake object, or one of its
+//               properties is changed by the user, the entire sleep
+//               mechanism should be transparent to the user.
+////////////////////////////////////////////////////////////////////
+bool PhysxCloth::
+is_sleeping() const {
+
+  nassertr(_error_type == ET_ok, false);
+  return _ptr->isSleeping();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::wake_up
+//       Access: Published
+//  Description: Wakes up the cloth if it is sleeping. 
+//
+//               The wakeCounterValue determines how long until the
+//               body is put to sleep, a value of zero means that
+//               the body is sleeping. wake_up(0) is equivalent to
+//               PhysxCloth::put_to_sleep().
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+wake_up(float wakeCounterValue) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->wakeUp(wakeCounterValue);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::put_to_sleep
+//       Access: Published
+//  Description: Forces the cloth to sleep. 
+//
+//               The cloth  will stay asleep until the next
+//               call to simulate, and will not wake up until then
+//               even when otherwise it would (for example a force
+//               is applied to it). It can however wake up during
+//               the next do_physics call.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+put_to_sleep() {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->putToSleep();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_sleep_linear_velocity
+//       Access: Published
+//  Description: Sets the linear velocity below which an cloth
+//               may go to sleep. Cloths whose linear velocity is
+//               above this threshold will not be put to sleep.
+//
+//               Setting the sleep angular/linear velocity only
+//               makes sense when the BF_energy_sleep_test is not
+//               set.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_sleep_linear_velocity(float threshold) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->setSleepLinearVelocity(threshold);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_sleep_linear_velocity
+//       Access: Published
+//  Description: Returns the linear velocity below which an soft
+//               body may go to sleep. cloths whose linear velocity
+//               is above this threshold will not be put to sleep.
+////////////////////////////////////////////////////////////////////
+float PhysxCloth::
+get_sleep_linear_velocity() const {
+
+  nassertr(_error_type == ET_ok, 0.0f);
+  return _ptr->getSleepLinearVelocity();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::attach_vertex_to_global_pos
+//       Access: Published
+//  Description: Attaches a cloth vertex to a position in world
+//               space.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+attach_vertex_to_global_pos(unsigned int vertexId, LPoint3f const &pos) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv(!pos.is_nan());
+
+  _ptr->attachVertexToGlobalPosition(vertexId, PhysxManager::point3_to_nxVec3(pos));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::attach_to_shape
+//       Access: Published
+//  Description: Attaches the cloth to a shape. All cloth points
+//               currently inside the shape are attached.
+//
+//               This method only works with primitive and convex
+//               shapes. Since the inside of a general triangle mesh
+//               is not clearly defined.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+attach_to_shape(PhysxShape *shape) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv(shape);
+
+  NxU32 attachmentFlags = 0; // --TODO--
+  _ptr->attachToShape(shape->ptr(), attachmentFlags);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::attach_to_colliding_shapes
+//       Access: Published
+//  Description: Attaches the cloth to all shapes, currently
+//               colliding. 
+//
+//               This method only works with primitive and convex
+//               shapes. Since the inside of a general triangle mesh
+//               is not clearly defined.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+attach_to_colliding_shapes() {
+
+  nassertv(_error_type == ET_ok);
+
+  NxU32 attachmentFlags = 0; // --TODO--
+  _ptr->attachToCollidingShapes(attachmentFlags);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::detach_from_shape
+//       Access: Published
+//  Description: Detaches the cloth from a shape it has been
+//               attached to before. 
+//
+//               If the cloth has not been attached to the shape
+//               before, the call has no effect.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+detach_from_shape(PhysxShape *shape) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv(shape);
+
+  _ptr->detachFromShape(shape->ptr());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::free_vertex
+//       Access: Published
+//  Description: Frees a previously attached cloth point.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+free_vertex(unsigned int vertexId) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->freeVertex(vertexId);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::attach_vertex_to_shape
+//       Access: Published
+//  Description: Attaches a cloth vertex to a local position within
+//               a shape.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+attach_vertex_to_shape(unsigned int vertexId, PhysxShape *shape, LPoint3f const &localPos) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv(!localPos.is_nan());
+  nassertv(shape);
+
+  NxU32 attachmentFlags = 0; // --TODO--
+  _ptr->attachVertexToShape(vertexId, shape->ptr(),
+                            PhysxManager::point3_to_nxVec3(localPos),
+                            attachmentFlags);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_vertex_attachment_status
+//       Access: Published
+//  Description: Return the attachment status of the given vertex.
+////////////////////////////////////////////////////////////////////
+PhysxEnums::PhysxVertexAttachmentStatus PhysxCloth::
+get_vertex_attachment_status(unsigned int vertexId) const {
+
+  nassertr(_error_type == ET_ok, VAS_none);
+  // --TODO-- nassertr(vertexId < _ptr->getNumberOfParticles(), VAS_none);
+
+  return (PhysxVertexAttachmentStatus) _ptr->getVertexAttachmentStatus(vertexId);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_vertex_attachment_shape
+//       Access: Published
+//  Description: Returns the pointer to an attached shape pointer
+//               of the given vertex. If the vertex is not attached
+//               or attached to a global position, NULL is returned.
+////////////////////////////////////////////////////////////////////
+PhysxShape *PhysxCloth::
+get_vertex_attachment_shape(unsigned int vertexId) const {
+
+  nassertr(_error_type == ET_ok, NULL);
+  // --TODO-- nassertr(vertexId < _ptr->getNumberOfParticles(), NULL);
+
+  NxShape *shapePtr = _ptr->getVertexAttachmentShape(vertexId);
+  PhysxShape *shape = shapePtr ? (PhysxShape *)(shapePtr->userData) : NULL;
+
+  return shape;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_vertex_attachment_pos
+//       Access: Published
+//  Description: Returns the attachment position of the given
+//               vertex. If the vertex is attached to shape, the
+//               position local to the shape's pose is returned. If
+//               the vertex is not attached, the return value is
+//               undefined.
+////////////////////////////////////////////////////////////////////
+LPoint3f PhysxCloth::
+get_vertex_attachment_pos(unsigned int vertexId) const {
+
+  nassertr(_error_type == ET_ok, LPoint3f::zero());
+  // --TODO-- nassertr(vertexId < _ptr->getNumberOfParticles(), LPoint3f::zero());
+
+  return PhysxManager::nxVec3_to_point3(_ptr->getVertexAttachmentPosition(vertexId));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_external_acceleration
+//       Access: Published
+//  Description: Sets an external acceleration which affects all non
+//               attached particles of the cloth.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_external_acceleration(LVector3f const &acceleration) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv_always(!acceleration.is_nan());
+
+  _ptr->setExternalAcceleration(PhysxManager::vec3_to_nxVec3(acceleration));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::set_wind_acceleration
+//       Access: Published
+//  Description: Sets an acceleration acting normal to the cloth
+//               surface at each vertex.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+set_wind_acceleration(LVector3f const &acceleration) {
+
+  nassertv(_error_type == ET_ok);
+  nassertv_always(!acceleration.is_nan());
+
+  _ptr->setWindAcceleration(PhysxManager::vec3_to_nxVec3(acceleration));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_external_acceleration
+//       Access: Published
+//  Description: Retrieves the external acceleration which affects
+//               all non attached particles of the cloth.
+////////////////////////////////////////////////////////////////////
+LVector3f PhysxCloth::
+get_external_acceleration() const {
+
+  nassertr(_error_type == ET_ok, LVector3f::zero());
+  return PhysxManager::nxVec3_to_vec3(_ptr->getExternalAcceleration());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::get_wind_acceleration
+//       Access: Published
+//  Description: Retrieves the acceleration acting normal to the
+//               cloth surface at each vertex
+////////////////////////////////////////////////////////////////////
+LVector3f PhysxCloth::
+get_wind_acceleration() const {
+
+  nassertr(_error_type == ET_ok, LVector3f::zero());
+  return PhysxManager::nxVec3_to_vec3(_ptr->getWindAcceleration());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::add_force_at_vertex
+//       Access: Published
+//  Description: Applies a force (or impulse) defined in the 
+//               global coordinate frame, to a particular vertex
+//               of the cloth.
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+add_force_at_vertex(LVector3f const &force, int vertexId, PhysxForceMode mode) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->addForceAtVertex(PhysxManager::vec3_to_nxVec3(force),
+                         vertexId,
+                         (NxForceMode) mode);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::add_force_at_pos
+//       Access: Published
+//  Description: Applies a radial force (or impulse) at a
+//               particular position. All vertices within radius
+//               will be affected with a quadratic drop-off. 
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+add_force_at_pos(LPoint3f const &pos, float magnitude, float radius, PhysxForceMode mode) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->addForceAtPos(PhysxManager::point3_to_nxVec3(pos),
+                      magnitude,
+                      radius,
+                      (NxForceMode) mode);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxCloth::add_directed_force_at_pos
+//       Access: Published
+//  Description: Applies a directed force (or impulse) at a
+//               particular position. All vertices within radius
+//               will be affected with a quadratic drop-off.  
+////////////////////////////////////////////////////////////////////
+void PhysxCloth::
+add_directed_force_at_pos(LPoint3f const &pos, LVector3f const &force, float radius, PhysxForceMode mode) {
+
+  nassertv(_error_type == ET_ok);
+  _ptr->addDirectedForceAtPos(PhysxManager::point3_to_nxVec3(pos),
+                              PhysxManager::vec3_to_nxVec3(force),
+                              radius,
+                              (NxForceMode) mode);
+}
+

+ 136 - 0
panda/src/physx/physxCloth.h

@@ -0,0 +1,136 @@
+// Filename: physxCloth.h
+// Created by:  enn0x (30Mar10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PHYSXCLOTH_H
+#define PHYSXCLOTH_H
+
+#include "pandabase.h"
+#include "lvector3.h"
+#include "lpoint3.h"
+
+#include "physxObject.h"
+#include "physxObjectCollection.h"
+#include "physxEnums.h"
+#include "physx_includes.h"
+
+class PhysxScene;
+class PhysxGroupsMask;
+class PhysxClothNode;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PhysxCloth
+// Description : 
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAPHYSX PhysxCloth : public PhysxObject, public PhysxEnums {
+
+PUBLISHED:
+  INLINE PhysxCloth();
+  INLINE ~PhysxCloth();
+
+  PhysxScene *get_scene() const;
+  PhysxClothNode *get_cloth_node() const;
+  PhysxClothNode *create_cloth_node(const char *name);
+
+  void set_name(const char *name);
+  void set_group(unsigned int group);
+  void set_groups_mask(const PhysxGroupsMask &mask);
+  void set_flag(PhysxClothFlag flag, bool value);
+  void set_thickness(float thickness);
+
+  const char *get_name() const;
+  unsigned int get_num_particles();
+  unsigned int get_group() const;
+  PhysxGroupsMask get_groups_mask() const;
+  bool get_flag(PhysxClothFlag flag) const;
+  float get_thickness() const;
+  float get_density() const;
+  float get_relative_grid_spacing() const;
+
+  // Attachment
+  void attach_vertex_to_global_pos(unsigned int vertexId, LPoint3f const &pos);
+  void free_vertex(unsigned int vertexId);
+  void attach_to_shape(PhysxShape *shape);
+  void attach_to_colliding_shapes();
+  void detach_from_shape(PhysxShape *shape);
+  void attach_vertex_to_shape(unsigned int vertexId, PhysxShape *shape, LPoint3f const &localPos);
+  PhysxVertexAttachmentStatus get_vertex_attachment_status(unsigned int vertexId) const;
+  PhysxShape *get_vertex_attachment_shape(unsigned int vertexId) const;
+  LPoint3f get_vertex_attachment_pos(unsigned int vertexId) const;
+
+  // Sleeping
+  bool is_sleeping() const;
+  void wake_up(float wakeCounterValue=NX_SLEEP_INTERVAL);
+  void put_to_sleep();
+  void set_sleep_linear_velocity(float threshold);
+  float get_sleep_linear_velocity() const;
+
+  // Forces
+  void set_external_acceleration(LVector3f const &acceleration);
+  LVector3f get_external_acceleration() const;
+
+  void set_wind_acceleration(LVector3f const &acceleration);
+  LVector3f get_wind_acceleration() const;
+
+  void add_force_at_vertex(LVector3f const &force, int vertexId,
+                           PhysxForceMode mode=FM_force);
+  void add_force_at_pos(LPoint3f const &pos, float magnitude, float radius,
+                        PhysxForceMode mode=FM_force);
+  void add_directed_force_at_pos(LPoint3f const &pos, LVector3f const &force, float radius,
+                                 PhysxForceMode mode=FM_force);
+
+  INLINE void ls() const;
+  INLINE void ls(ostream &out, int indent_level=0) const;
+
+public:
+  void update();
+
+////////////////////////////////////////////////////////////////////
+PUBLISHED:
+  void release();
+
+public:
+  INLINE NxCloth *ptr() const { return _ptr; };
+
+  void link(NxCloth *ptr);
+  void unlink();
+
+private:
+  NxCloth *_ptr;
+  PT(PhysxClothNode) _node;
+
+////////////////////////////////////////////////////////////////////
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    PhysxObject::init_type();
+    register_type(_type_handle, "PhysxCloth", 
+                  PhysxObject::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {
+    init_type();
+    return get_class_type();
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "physxCloth.I"
+
+#endif // PHYSXCLOTH_H

+ 59 - 0
panda/src/physx/physxClothDesc.I

@@ -0,0 +1,59 @@
+// Filename: physxClothDesc.I
+// Created by:  enn0x (30Mar10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PhysxClothDesc::
+PhysxClothDesc() {
+
+  _desc.name = "";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PhysxClothDesc::
+~PhysxClothDesc() {
+
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_to_default
+//       Access: Published
+//  Description: (re)sets the structure to the default.
+////////////////////////////////////////////////////////////////////
+INLINE void PhysxClothDesc::
+set_to_default() {
+
+  _desc.setToDefault();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::is_valid
+//       Access: Published
+//  Description: Returns true if the descriptor is valid.
+////////////////////////////////////////////////////////////////////
+INLINE bool PhysxClothDesc::
+is_valid() const {
+
+  return _desc.isValid();
+}
+

+ 358 - 0
panda/src/physx/physxClothDesc.cxx

@@ -0,0 +1,358 @@
+// Filename: physxClothDesc.cxx
+// Created by:  enn0x (30Mar10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "physxClothDesc.h"
+#include "physxClothMesh.h"
+#include "physxManager.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_name
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_name(const char *name) {
+
+  _desc.name = name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_global_pos
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_global_pos(const LPoint3f &pos) {
+
+  _desc.globalPose.t = PhysxManager::point3_to_nxVec3(pos);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_global_mat
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_global_mat(const LMatrix4f &mat) {
+
+  _desc.globalPose = PhysxManager::mat4_to_nxMat34(mat);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_global_hpr
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_global_hpr(float h, float p, float r) {
+
+  LQuaternionf q;
+  LMatrix3f rot;
+  NxMat34 m;
+
+  q.set_hpr(LVector3f(h, p, r));
+  q.extract_to_matrix(rot);
+
+  _desc.globalPose.M = PhysxManager::mat3_to_nxMat33(rot);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_thickness
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_thickness(float thickness) {
+
+  _desc.thickness = thickness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_density
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_density(float density) {
+
+  _desc.density = density;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_bending_stiffness
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_bending_stiffness(float stiffness) {
+
+  _desc.bendingStiffness = stiffness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_stretching_stiffness
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_stretching_stiffness(float stiffness) {
+
+  _desc.stretchingStiffness = stiffness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_damping_coefficient
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_damping_coefficient(float damping) {
+
+  _desc.dampingCoefficient = damping;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_friction
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_friction(float friction) {
+
+  _desc.friction = friction;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_pressure
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_pressure(float pressure) {
+
+  _desc.pressure = pressure;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_tear_factor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_tear_factor(float tearFactor) {
+
+  _desc.tearFactor = tearFactor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_flag
+//       Access: Published
+//  Description: Raise or lower individual ClothFlag flags.
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_flag(PhysxClothFlag flag, bool value) {
+
+  if (value == true) {
+    _desc.flags |= flag;
+  }
+  else {
+    _desc.flags &= ~(flag);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_solver_iterations
+//       Access: Published
+//  Description: Number of solver iterations.
+//               Small numbers make the simulation faster while 
+//               the cloth gets less stiff.
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_solver_iterations(unsigned int iterations) {
+
+  _desc.solverIterations = iterations;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::set_cloth_mesh
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+set_cloth_mesh(PhysxClothMesh *mesh) {
+
+  _desc.clothMesh = mesh->ptr();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_name
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const char *PhysxClothDesc::
+get_name() const {
+
+  return _desc.name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_global_pos
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+LPoint3f PhysxClothDesc::
+get_global_pos() const {
+
+  return PhysxManager::nxVec3_to_point3(_desc.globalPose.t);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_global_mat
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+LMatrix4f PhysxClothDesc::
+get_global_mat() const {
+
+  return PhysxManager::nxMat34_to_mat4(_desc.globalPose);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_thickness
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_thickness() const {
+
+  return _desc.thickness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_density
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_density() const {
+
+  return _desc.density;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_bending_stiffness
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_bending_stiffness() const {
+
+  return _desc.bendingStiffness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_stretching_stiffness
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_stretching_stiffness() const {
+
+  return _desc.stretchingStiffness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_damping_coefficient
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_damping_coefficient() const {
+
+  return _desc.dampingCoefficient;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_friction
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_friction() const {
+
+  return _desc.friction;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_pressure
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_pressure() const {
+
+  return _desc.pressure;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_tear_factor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float PhysxClothDesc::
+get_tear_factor() const {
+
+  return _desc.tearFactor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_flag
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool PhysxClothDesc::
+get_flag(PhysxClothFlag flag) const {
+
+  return (_desc.flags & flag) ? true : false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_solver_iterations
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+unsigned int PhysxClothDesc::
+get_solver_iterations() const {
+
+  return _desc.solverIterations;
+}
+
+/*
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothDesc::get_mesh_numbers
+//       Access: Public
+//  Description: Used by PhysScene to query the sizes of arrays
+//               to allocate for the user buffers in PhysxClothNode.
+////////////////////////////////////////////////////////////////////
+void PhysxClothDesc::
+get_mesh_numbers(NxU32 &numVertices, NxU32 &numTriangles) {
+
+  NxClothMeshDesc meshDesc;
+  _desc.clothMesh->saveToDesc(meshDesc);
+
+  numVertices = meshDesc.numVertices;
+  numTriangles = meshDesc.numTriangles;
+}
+*/
+

+ 80 - 0
panda/src/physx/physxClothDesc.h

@@ -0,0 +1,80 @@
+// Filename: physxClothDesc.h
+// Created by:  enn0x (30Mar10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PHYSXCLOTHDESC_H
+#define PHYSXCLOTHDESC_H
+
+#include "pandabase.h"
+#include "lpoint3.h"
+#include "lmatrix.h"
+
+#include "physxEnums.h"
+#include "physx_includes.h"
+
+class PhysxClothMesh;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PhysxClothDesc
+// Description : Descriptor for PhysxCloth.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAPHYSX PhysxClothDesc : public PhysxEnums {
+
+PUBLISHED:
+  INLINE PhysxClothDesc();
+  INLINE ~PhysxClothDesc();
+
+  INLINE void set_to_default();
+  INLINE bool is_valid() const;
+
+  void set_cloth_mesh(PhysxClothMesh *mesh);
+
+  void set_name(const char *name);
+  void set_global_pos(const LPoint3f &pos);
+  void set_global_mat(const LMatrix4f &mat);
+  void set_global_hpr(float h, float p, float r);
+  void set_thickness(float thickness);
+  void set_density(float density);
+  void set_bending_stiffness(float stiffness);
+  void set_stretching_stiffness(float stiffness);
+  void set_damping_coefficient(float damping);
+  void set_friction(float friction);
+  void set_pressure(float pressure);
+  void set_tear_factor(float tearFactor);
+  void set_solver_iterations(unsigned int interations);
+  void set_flag(PhysxClothFlag flag, bool value);
+
+  const char *get_name() const;
+  LPoint3f get_global_pos() const;
+  LMatrix4f get_global_mat() const;
+  float get_thickness() const;
+  float get_density() const;
+  float get_bending_stiffness() const;
+  float get_stretching_stiffness() const;
+  float get_damping_coefficient() const;
+  float get_friction() const;
+  float get_pressure() const;
+  float get_tear_factor() const;
+  unsigned int get_solver_iterations() const;
+  bool get_flag(PhysxClothFlag flag) const;
+
+public:
+  //void get_mesh_numbers(NxU32 &numVertices, NxU32 &numTriangles);
+
+public:
+  NxClothDesc _desc;
+};
+
+#include "physxClothDesc.I"
+
+#endif // PHYSXCLOTHDESC_H

+ 35 - 1
panda/src/physx/physxClothMeshDesc.I

@@ -22,13 +22,14 @@ INLINE PhysxClothMeshDesc::
 PhysxClothMeshDesc() {
 
   _desc.flags = 0;
-  _desc.pointStrideBytes = 5*sizeof(NxReal);
+  _desc.pointStrideBytes = sizeof(NxVec3);
   _desc.triangleStrideBytes = 3*sizeof(NxU32);
   _desc.points = NULL;
   _desc.triangles = NULL;
 
   _points = NULL;
   _triangles = NULL;
+  _texcoords = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -46,6 +47,10 @@ INLINE PhysxClothMeshDesc::
   if (_triangles) {
     delete [] _triangles;
   }
+
+  if (_texcoords) {
+    delete [] _texcoords;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -59,3 +64,32 @@ is_valid() const {
   return _desc.isValid();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothMeshDesc::get_desc
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const NxClothMeshDesc &PhysxClothMeshDesc::
+get_desc() const {
+
+  return _desc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothMeshDesc::get_texcoords
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const plist<LPoint2f> PhysxClothMeshDesc::
+get_texcoords() const {
+
+  plist<LPoint2f> texcoords;
+
+  for (unsigned int i=0; i < _desc.numVertices; i++) {
+    LPoint2f uv = _texcoords[i];
+    texcoords.push_back(uv);
+  }
+
+  return texcoords;
+}
+

+ 15 - 24
panda/src/physx/physxClothMeshDesc.cxx

@@ -32,14 +32,22 @@
 void PhysxClothMeshDesc::
 set_num_vertices(unsigned int numVertices) {
 
+  // Vertices
   if (_desc.points) {
     delete [] _points;
   }
 
-  _points = new NxReal[5 * numVertices];
+  _points = new NxVec3[numVertices];
 
   _desc.numVertices = numVertices;
   _desc.points = _points;
+
+  // Texture coordinates
+  if (_texcoords) {
+    delete [] _texcoords;
+  }
+
+  _texcoords = new LPoint2f[numVertices];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -53,12 +61,8 @@ set_vertex(unsigned int idx, const LPoint3f &vert, const LPoint2f &texcoord) {
 
   nassertv(_desc.numVertices > idx);
 
-  idx = 5 * idx;
-  _points[idx]     = vert.get_x();
-  _points[idx + 1] = vert.get_y();
-  _points[idx + 2] = vert.get_z();
-  _points[idx + 3] = texcoord.get_x();
-  _points[idx + 4] = texcoord.get_y();
+  _points[idx] = PhysxManager::point3_to_nxVec3(vert);
+  _texcoords[idx] = texcoord;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -101,17 +105,6 @@ set_triangle(unsigned int idx,
   _triangles[idx + 2] = i3;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: PhysxClothMeshDesc::get_desc
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-const NxClothMeshDesc &PhysxClothMeshDesc::
-get_desc() const {
-
-  return _desc;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: PhysxClothMeshDesc::set_from_node_path
 //       Access: Published
@@ -182,17 +175,16 @@ set_from_node_path(const NodePath &np) {
   NxU32 numVertices = dataVertices.size();
   NxU32 numTriangles = dataIndices.size() / 3;
 
-  _points = new NxReal[5 * numVertices];
+  _points = new NxVec3[numVertices];
   _triangles = new NxU32[3 * numTriangles];
+  _texcoords = new LPoint2f[numVertices];
 
   i = 0;
   pvector<LPoint3f>::const_iterator vit;
   for (vit=dataVertices.begin(); vit!=dataVertices.end(); vit++) {
     LPoint3f v = *vit;
 
-    _points[5*i]   = v.get_x();
-    _points[5*i+1] = v.get_y();
-    _points[5*i+2] = v.get_z();
+    _points[i] = PhysxManager::point3_to_nxVec3(v);
     i++;
   }
 
@@ -201,8 +193,7 @@ set_from_node_path(const NodePath &np) {
   for (tcit=dataTexcoords.begin(); tcit!=dataTexcoords.end(); tcit++) {
     LPoint2f tc = *tcit;
 
-    _points[5*i+3] = tc.get_x();
-    _points[5*i+4] = tc.get_y();
+    _texcoords[i]   = tc;
     i++;
   }
 

+ 9 - 4
panda/src/physx/physxClothMeshDesc.h

@@ -19,6 +19,7 @@
 #include "lpoint3.h"
 #include "lpoint2.h"
 #include "nodePath.h"
+#include "plist.h"
 
 #include "physx_includes.h"
 
@@ -35,7 +36,8 @@ PUBLISHED:
   INLINE bool is_valid() const;
 
   void set_num_vertices(unsigned int n);
-  void set_vertex(unsigned int idx, const LPoint3f &vert, const LPoint2f &texcoord);
+  void set_vertex(unsigned int idx,
+                  const LPoint3f &vert, const LPoint2f &texcoord);
 
   void set_num_triangles(unsigned int n);
   void set_triangle(unsigned int idx,
@@ -44,12 +46,15 @@ PUBLISHED:
   void set_from_node_path(const NodePath &np);
 
 public:
-  const NxClothMeshDesc &get_desc() const;
+  INLINE const NxClothMeshDesc &get_desc() const;
+  INLINE const plist<LPoint2f> get_texcoords() const;
 
 private:
-  NxReal *_points;
-  NxU32 *_triangles;
   NxClothMeshDesc _desc;
+  NxVec3 *_points;
+  NxU32 *_triangles;
+
+  LPoint2f *_texcoords;
 };
 
 #include "physxClothMeshDesc.I"

+ 53 - 0
panda/src/physx/physxClothNode.I

@@ -0,0 +1,53 @@
+// Filename: physxClothNode.I
+// Created by:  enn0x (05Apr10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PhysxClothNode::
+PhysxClothNode(const char *name) : GeomNode(name) {
+
+  _numVertices = 0;
+
+  _vdata = new GeomVertexData("", GeomVertexFormat::get_v3n3t2(), Geom::UH_stream);
+
+  _prim = new GeomTriangles(Geom::UH_stream);
+  _prim->set_shade_model(Geom::SM_uniform);
+
+  _geom = new Geom(_vdata);
+  _geom->add_primitive(_prim);
+
+  this->add_geom(_geom);
+
+  _numTexcoords = 0;
+  _texcoords = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PhysxClothNode::
+~PhysxClothNode() {
+
+  if (_texcoords) {
+    delete [] _texcoords;
+  }
+}
+

+ 229 - 0
panda/src/physx/physxClothNode.cxx

@@ -0,0 +1,229 @@
+// Filename: physxClothNode.cxx
+// Created by:  enn0x (05Apr10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "physxClothNode.h"
+#include "physxCloth.h"
+#include "physxFileStream.h"
+
+#include "geomVertexFormat.h"
+#include "geomVertexWriter.h"
+
+TypeHandle PhysxClothNode::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::allocate
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothNode::
+allocate(PhysxCloth *cloth) {
+
+  _cloth = cloth;
+
+  // Retrieve number of vertices and triangles the hard way
+  NxClothMeshDesc meshDesc;
+  _cloth->ptr()->getClothMesh()->saveToDesc(meshDesc);
+
+  NxU32 numVertices = meshDesc.numVertices;
+  NxU32 numTriangles = meshDesc.numTriangles;
+
+  NxReal factor = 1.0f; // TODO: max(1.0f, factor);
+
+  // Reserve more memory for vertices than the initial mesh takes because
+  // tearing creates new vertices
+  NxU32 maxVertices = factor * numVertices;
+  _mesh.verticesPosBegin = (NxVec3 *)malloc(sizeof(NxVec3) * maxVertices);
+  _mesh.verticesNormalBegin = (NxVec3 *)malloc(sizeof(NxVec3) * maxVertices);
+  _mesh.verticesPosByteStride = sizeof(NxVec3);
+  _mesh.verticesNormalByteStride = sizeof(NxVec3);
+  _mesh.maxVertices = maxVertices;
+  _mesh.numVerticesPtr = (NxU32 *)malloc(sizeof(NxU32));
+
+  // The number of triangles is constant, even if the cloth is torn
+  NxU32 maxIndices = 3 * numTriangles;
+  _mesh.indicesBegin = (NxU32 *)malloc(sizeof(NxU32) * maxIndices);
+  _mesh.indicesByteStride = sizeof(NxU32);
+  _mesh.maxIndices = maxIndices;
+  _mesh.numIndicesPtr = (NxU32 *)malloc(sizeof(NxU32));
+
+  NxU32 maxParentIndices = maxVertices;
+  _mesh.parentIndicesBegin = (NxU32 *)malloc(sizeof(NxU32)*maxParentIndices);
+  _mesh.parentIndicesByteStride = sizeof(NxU32);
+  _mesh.maxParentIndices = maxParentIndices;
+  _mesh.numParentIndicesPtr = (NxU32 *)malloc(sizeof(NxU32));
+
+  *(_mesh.numVerticesPtr) = 0;
+  *(_mesh.numIndicesPtr) = 0;
+
+  _cloth->ptr()->setMeshData(_mesh);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::update
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothNode::
+update() {
+
+  NxU32 numVertices = *(_mesh.numVerticesPtr);
+
+  if (numVertices == _numVertices) {
+    update_geom();
+  }
+  else {
+    update_texcoords();
+    create_geom();
+    _numVertices = numVertices;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::create_geom
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothNode::
+create_geom() {
+
+  _prim->clear_vertices();
+
+  GeomVertexWriter vwriter = GeomVertexWriter(_vdata, InternalName::get_vertex());
+  GeomVertexWriter nwriter = GeomVertexWriter(_vdata, InternalName::get_normal());
+  GeomVertexWriter twriter = GeomVertexWriter(_vdata, InternalName::get_texcoord());
+
+  // Vertices and normals
+  NxU32 numVertices = *(_mesh.numVerticesPtr);
+  NxVec3 *v = (NxVec3 *)_mesh.verticesPosBegin;
+  NxVec3 *n = (NxVec3 *)_mesh.verticesNormalBegin;
+
+  for (unsigned int i=0; i < numVertices; i++) {
+    vwriter.add_data3f(v->x, v->y, v->z);
+    v++;
+    nwriter.add_data3f(n->x, n->y, n->z);
+    n++;
+  }
+
+  // Texture coordinates
+  NxReal tex_u;
+  NxReal tex_v;
+
+  if (_texcoords) {
+    for (unsigned int i=0; i < numVertices; i++) {
+      tex_u = _texcoords[2*i];
+      tex_v = _texcoords[2*i+1];
+      twriter.add_data2f(tex_u, tex_v);
+    }
+  }
+
+  // Indices
+  NxU32 numIndices = *(_mesh.numIndicesPtr);
+  NxU32 *idx = (NxU32 *)_mesh.indicesBegin;
+
+  for (unsigned int i=0; i < numIndices; i++) {
+    _prim->add_vertex(*idx);
+    idx++;
+  }
+
+  _prim->close_primitive();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::update_geom
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PhysxClothNode::
+update_geom() {
+
+  GeomVertexWriter vwriter = GeomVertexWriter(_vdata, InternalName::get_vertex());
+  GeomVertexWriter nwriter = GeomVertexWriter(_vdata, InternalName::get_normal());
+
+  NxU32 numVertices = *(_mesh.numVerticesPtr);
+  NxVec3 *v = (NxVec3 *)_mesh.verticesPosBegin;
+  NxVec3 *n = (NxVec3 *)_mesh.verticesNormalBegin;
+
+  for (unsigned int i=0; i < numVertices; i++) {
+    vwriter.set_data3f(v->x, v->y, v->z);
+    v++;
+    nwriter.set_data3f(n->x, n->y, n->z);
+    n++;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::update_texcoords
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void PhysxClothNode::
+update_texcoords() {
+
+  if (!_texcoords) {
+    return;
+  }
+
+  NxU32 numVertices = *(_mesh.numVerticesPtr);
+  NxU32 *parent = (NxU32 *)_mesh.parentIndicesBegin + _numTexcoords;
+
+  for (NxU32 i=_numTexcoords; i < numVertices; i++, parent++) {
+    _texcoords[2*i] = _texcoords[2*(*parent)];
+    _texcoords[2*i+1] = _texcoords[2*(*parent)+1];
+  }
+
+  _numTexcoords = numVertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxClothNode::set_texcoords
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool PhysxClothNode::
+set_texcoords(const Filename &filename) {
+
+  if (filename.empty()) {
+    return false;
+  }
+
+  Filename fn(filename);
+  fn.resolve_filename(get_model_path());
+
+  if (!filename.exists()) {
+    return false;
+  }
+
+  PhysxFileStream fs(filename.c_str(), true);
+
+  fs.readByte(); // N
+  fs.readByte(); // X
+  fs.readByte(); // X
+  fs.readByte(); // 1
+  fs.readByte(); // T
+  fs.readByte(); // E
+  fs.readByte(); // X
+  fs.readByte(); // C
+  fs.readByte(); // 1
+
+  _numTexcoords = fs.readDword();
+  _texcoords = new float[2 * _numTexcoords];
+
+  for (unsigned int i=0; i<_numTexcoords; i++) {
+    _texcoords[2*i]   = fs.readFloat();
+    _texcoords[2*i+1] = fs.readFloat();
+  }
+
+  return true;
+}
+

+ 89 - 0
panda/src/physx/physxClothNode.h

@@ -0,0 +1,89 @@
+// Filename: physxClothNode.h
+// Created by:  enn0x (05Apr10)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PHYSXCLOTHNODE_H
+#define PHYSXCLOTHNODE_H
+
+#include "pandabase.h"
+#include "pointerTo.h"
+#include "geomNode.h"
+#include "transformState.h"
+#include "geom.h"
+#include "geomVertexData.h"
+#include "geomTriangles.h"
+#include "filename.h"
+
+#include "physx_includes.h"
+
+class PhysxCloth;
+
+////////////////////////////////////////////////////////////////////
+//       Class : PhysxClothNode
+// Description : Renderable geometry which represents a cloth mesh.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAPHYSX PhysxClothNode : public GeomNode {
+
+PUBLISHED:
+  INLINE PhysxClothNode(const char *name);
+  INLINE ~PhysxClothNode();
+
+  bool set_texcoords(const Filename &filename);
+
+public:
+  void allocate(PhysxCloth *cloth);
+  void update();
+
+private:
+  void create_geom();
+  void update_geom();
+  void update_texcoords();
+
+  unsigned int _numVertices;
+
+  NxMeshData _mesh;
+
+  PT(GeomVertexData) _vdata;
+  PT(Geom) _geom;
+  PT(GeomTriangles) _prim;
+
+  PT(PhysxCloth) _cloth;
+
+  unsigned int _numTexcoords;
+  float *_texcoords;
+
+////////////////////////////////////////////////////////////////////
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    GeomNode::init_type();
+    register_type(_type_handle, "PhysxClothNode", 
+                  GeomNode::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {
+    init_type();
+    return get_class_type();
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "physxClothNode.I"
+
+#endif // PHYSXCLOTHNODE_H

+ 52 - 0
panda/src/physx/physxEnums.h

@@ -141,6 +141,26 @@
 #define NX_BP_TYPE_SAP_SINGLE 0
 #define NX_BP_TYPE_SAP_MULTI 1
 
+// PhysxClothFlag
+#define NX_CLF_PRESSURE 1<<0
+#define NX_CLF_STATIC 1<<1
+#define NX_CLF_DISABLE_COLLISION 1<<2
+#define NX_CLF_SELFCOLLISION 1<<3
+#define NX_CLF_VISUALIZATION 1<<4
+#define NX_CLF_GRAVITY 1<<5
+#define NX_CLF_BENDING 1<<6
+#define NX_CLF_BENDING_ORTHO 1<<7
+#define NX_CLF_DAMPING 1<<8
+#define NX_CLF_COLLISION_TWOWAY 1<<9
+#define NX_CLF_TRIANGLE_COLLISION 1<<11
+#define NX_CLF_TEARABLE 1<<12
+#define NX_CLF_HARDWARE 1<<13
+#define NX_CLF_COMDAMPING 1<<14
+#define NX_CLF_VALIDBOUNDS 1<<15
+#define NX_CLF_FLUID_COLLISION 1<<16
+#define NX_CLF_DISABLE_DYNAMIC_CCD 1<<17
+#define NX_CLF_ADHERE 1<<18
+
 // PhysxContactPairFlag
 #define NX_IGNORE_PAIR 1<<0
 #define NX_NOTIFY_ON_START_TOUCH 1<<1
@@ -290,6 +310,11 @@
 #define NX_Y 2
 #define NX_Z 3
 
+// PhysxVertexAttachmentStatus
+#define NX_CLOTH_VERTEX_ATTACHMENT_NONE 0
+#define NX_CLOTH_VERTEX_ATTACHMENT_GLOBAL 1
+#define NX_CLOTH_VERTEX_ATTACHMENT_SHAPE 2
+
 // PhysxWheelShapeFlag
 #define NX_WF_WHEEL_AXIS_CONTACT_NORMAL 1<<0
 #define NX_WF_INPUT_LAT_SLIPVELOCITY 1<<1
@@ -440,6 +465,27 @@ PUBLISHED:
     BPT_sap_multi  = NX_BP_TYPE_SAP_MULTI
   };
 
+  enum PhysxClothFlag {
+    CLF_pressure            = NX_CLF_PRESSURE,
+    CLF_static              = NX_CLF_STATIC,
+    CLF_disable_collision   = NX_CLF_DISABLE_COLLISION,
+    CLF_selfcollision       = NX_CLF_SELFCOLLISION,
+    CLF_visualization       = NX_CLF_VISUALIZATION,
+    CLF_gravity             = NX_CLF_GRAVITY,
+    CLF_bending             = NX_CLF_BENDING,
+    CLF_bending_ortho       = NX_CLF_BENDING_ORTHO,
+    CLF_damping             = NX_CLF_DAMPING,
+    CLF_collision_twoway    = NX_CLF_COLLISION_TWOWAY,
+    CLF_triangle_collision  = NX_CLF_TRIANGLE_COLLISION,
+    CLF_tearable            = NX_CLF_TEARABLE,
+    CLF_hardware            = NX_CLF_HARDWARE,
+    CLF_comdamping          = NX_CLF_COMDAMPING,
+    CLF_validbounds         = NX_CLF_VALIDBOUNDS,
+    CLF_fluid_collision     = NX_CLF_FLUID_COLLISION,
+    CLF_disable_dynamic_ccd = NX_CLF_DISABLE_DYNAMIC_CCD,
+    CLF_adhere              = NX_CLF_ADHERE
+  };
+
   enum PhysxContactPairFlag {
     CPF_ignore_pair                     = NX_IGNORE_PAIR,
     CPF_notify_on_start_touch           = NX_NOTIFY_ON_START_TOUCH,
@@ -609,6 +655,12 @@ PUBLISHED:
     Z_up  = NX_Z
   };
 
+  enum PhysxVertexAttachmentStatus {
+    VAS_none   = NX_CLOTH_VERTEX_ATTACHMENT_NONE,
+    VAS_global = NX_CLOTH_VERTEX_ATTACHMENT_GLOBAL,
+    VAS_shape  = NX_CLOTH_VERTEX_ATTACHMENT_SHAPE
+  };
+
   enum PhysxWheelFlag {
     WF_steerable_input       = NX_WF_STEERABLE_INPUT,
     WF_steerable_auto        = NX_WF_STEERABLE_AUTO,

+ 48 - 6
panda/src/physx/physxKitchen.cxx

@@ -65,8 +65,8 @@ cook_convex_mesh(const PhysxConvexMeshDesc &meshDesc, const Filename &filename)
   nassertr_always(filename.touch(), false);
   nassertr_always(meshDesc.is_valid(), false);
 
-  PhysxFileStream stream = PhysxFileStream(filename, false);
-  return _cooking->NxCookConvexMesh(meshDesc.get_desc(), stream);
+  PhysxFileStream fs = PhysxFileStream(filename, false);
+  return _cooking->NxCookConvexMesh(meshDesc.get_desc(), fs);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -81,8 +81,8 @@ cook_triangle_mesh(const PhysxTriangleMeshDesc &meshDesc, const Filename &filena
   nassertr_always(filename.touch(), false);
   nassertr_always(meshDesc.is_valid(), false);
 
-  PhysxFileStream stream = PhysxFileStream(filename, false);
-  return _cooking->NxCookTriangleMesh(meshDesc.get_desc(), stream);
+  PhysxFileStream fs = PhysxFileStream(filename, false);
+  return _cooking->NxCookTriangleMesh(meshDesc.get_desc(), fs);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -93,13 +93,55 @@ cook_triangle_mesh(const PhysxTriangleMeshDesc &meshDesc, const Filename &filena
 bool PhysxKitchen::
 cook_cloth_mesh(const PhysxClothMeshDesc &meshDesc, const Filename &filename) {
 
+  nassertr_always(!filename.empty(), false);
+  nassertr_always(filename.touch(), false);
+  nassertr_always(meshDesc.is_valid(), false);
+
+  PhysxFileStream fs = PhysxFileStream(filename, false);
+  return _cooking->NxCookClothMesh(meshDesc.get_desc(), fs);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxKitchen::cook_texcoords
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool PhysxKitchen::
+cook_texcoords(const PhysxClothMeshDesc &meshDesc, const Filename &filename) {
 
   nassertr_always(!filename.empty(), false);
   nassertr_always(filename.touch(), false);
   nassertr_always(meshDesc.is_valid(), false);
 
-  PhysxFileStream stream = PhysxFileStream(filename, false);
-  return _cooking->NxCookClothMesh(meshDesc.get_desc(), stream);
+  const plist<LPoint2f> texcoords = meshDesc.get_texcoords();  
+
+  // Write texcoords to binary file
+  PhysxFileStream fs = PhysxFileStream(filename.c_str(), false);
+
+  // Header
+  fs.storeByte('N');
+  fs.storeByte('X');
+  fs.storeByte('S');
+  fs.storeByte(1);
+  fs.storeByte('T');
+  fs.storeByte('E');
+  fs.storeByte('X');
+  fs.storeByte('C');
+  fs.storeByte(1);
+
+  // Size
+  fs.storeDword(texcoords.size());
+
+  // Texcoords
+  plist<LPoint2f>::const_iterator it;
+  for(it=texcoords.begin(); it!=texcoords.end(); it++) {
+    LPoint2f v = *it;
+
+    fs.storeFloat(v.get_x());
+    fs.storeFloat(v.get_y());
+  }
+
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
panda/src/physx/physxKitchen.h

@@ -42,6 +42,7 @@ PUBLISHED:
   bool cook_convex_mesh(const PhysxConvexMeshDesc &meshDesc, const Filename &filename);
   bool cook_triangle_mesh(const PhysxTriangleMeshDesc &meshDesc, const Filename &filename);
   bool cook_cloth_mesh(const PhysxClothMeshDesc &meshDesc, const Filename &filename);
+  bool cook_texcoords(const PhysxClothMeshDesc &meshDesc, const Filename &filename);
 
   PhysxConvexMesh *cook_convex_mesh(const PhysxConvexMeshDesc &meshDesc);
   PhysxTriangleMesh *cook_triangle_mesh(const PhysxTriangleMeshDesc &meshDesc);

+ 2 - 0
panda/src/physx/physxScene.I

@@ -65,5 +65,7 @@ ls(ostream &out, int indent_level) const {
   _ffgroups.ls(out, indent_level);
   _controllers.ls(out, indent_level);
   _vehicles.ls(out, indent_level);
+  _cloths.ls(out, indent_level);
+  //_softbodies.ls(out, indent_level);
 }
 

+ 104 - 2
panda/src/physx/physxScene.cxx

@@ -22,6 +22,8 @@
 #include "physxConstraintDominance.h"
 #include "physxVehicle.h"
 #include "physxVehicleDesc.h"
+#include "physxCloth.h"
+#include "physxClothDesc.h"
 
 TypeHandle PhysxScene::_type_handle;
 
@@ -29,6 +31,8 @@ PStatCollector PhysxScene::_pcollector_fetch_results("App:PhysX:Fetch Results");
 PStatCollector PhysxScene::_pcollector_update_transforms("App:PhysX:Update Transforms");
 PStatCollector PhysxScene::_pcollector_debug_renderer("App:PhysX:Debug Renderer");
 PStatCollector PhysxScene::_pcollector_simulate("App:PhysX:Simulate");
+PStatCollector PhysxScene::_pcollector_cloth("App:PhysX:Cloth");
+//PStatCollector PhysxScene::_pcollector_softbody("App:PhysX:Softbody");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PhysxScene::link
@@ -123,8 +127,25 @@ unlink() {
     group->unlink();
   }
 
-  // Unlink cloths TODO
-  // Unlink softbodies TODO
+  // Unlink cloths
+  NxCloth **cloths = _ptr->getCloths();
+  NxU32 nCloths = _ptr->getNbCloths();
+
+  for (NxU32 i=0; i < nCloths; i++) {
+    PhysxCloth *cloth = (PhysxCloth *)cloths[i]->userData;
+    cloth->unlink();
+  }
+
+  // Unlink softbodies
+/*
+  NxSoftBody **sbs = _ptr->getSoftBodies();
+  NxU32 nSbs = _ptr->getNbSoftBodies();
+
+  for (NxU32 i=0; i < nSbs; i++) {
+    PhysxSoftBody *sb = (PhysxSoftBody *)sb[i]->userData;
+    sb->unlink();
+  }
+*/
 
   // Unlink materials
   NxMaterial *materials[5];
@@ -253,6 +274,28 @@ fetch_results() {
   _pcollector_debug_renderer.stop();
 
   nassertv(_ptr->isWritable());
+
+  // Update cloth nodes
+  _pcollector_cloth.start();
+
+  NxCloth **cloths = _ptr->getCloths();
+  for (NxU32 i=0; i < _ptr->getNbCloths(); i++) {
+    PT(PhysxCloth) cloth = (PhysxCloth *)cloths[i]->userData;
+    cloth->update();
+  }
+
+  _pcollector_cloth.stop();
+
+  // Update softbody nodes
+/*
+  _pcollector_softbody.start();
+  NxSoftBody **softbodies = _ptr->getSoftBodies();
+  for (NxU32 i=0; i < _ptr->getNbSoftBodies(); i++) {
+    PT(PhysxSoftBody) softbody = (PhysxSoftBody *)softbodies[i]->userData;
+    softbody->update();
+  }
+  _pcollector_softbody.stop();
+*/
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -856,6 +899,65 @@ get_force_field_shape_group(unsigned int idx) const {
   return groupPtr ? (PhysxForceFieldShapeGroup *)groupPtr->userData : NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxScene::get_num_cloths
+//       Access: Published
+//  Description: Gets the number of cloths in the scene.
+////////////////////////////////////////////////////////////////////
+unsigned int PhysxScene::
+get_num_cloths() const {
+
+  nassertr(_error_type == ET_ok, -1);
+  return _ptr->getNbCloths();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxScene::create_cloth
+//       Access: Published
+//  Description: Creates a cloth in this scene.
+////////////////////////////////////////////////////////////////////
+PhysxCloth *PhysxScene::
+create_cloth(PhysxClothDesc &desc) {
+
+  nassertr(_error_type == ET_ok, NULL);
+
+  PhysxCloth *cloth = new PhysxCloth();
+  nassertr(cloth, NULL);
+
+  NxCloth *clothPtr = _ptr->createCloth(desc._desc);
+  nassertr(clothPtr, NULL);
+
+  cloth->link(clothPtr);
+
+  // TODO:
+
+  // Allocate buffers in the cloth's geom node (PhysxMeshNode)
+  //NxU32 numVertices = 0;
+  //NxU32 numTriangles = 0;
+  //desc.get_mesh_numbers(numVertices, numTriangles);
+  //cloth->get_cloth_node()->allocate(numVertices, numTriangles, cloth);
+
+  return cloth;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PhysxScene::get_cloth
+//       Access: Published
+//  Description: Returns the n-th cloth from the array of
+//               all the cloths in the scene.
+////////////////////////////////////////////////////////////////////
+PhysxCloth *PhysxScene::
+get_cloth(unsigned int idx) const {
+
+  nassertr(_error_type == ET_ok, NULL);
+  nassertr_always(idx < _ptr->getNbCloths(), NULL);
+
+  NxCloth **cloths = _ptr->getCloths();
+  NxCloth *clothPtr = cloths[idx];
+
+  return (PhysxCloth *)(clothPtr->userData);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PhysxScene::get_num_vehicles
 //       Access: Published

+ 11 - 0
panda/src/physx/physxScene.h

@@ -50,6 +50,8 @@ class PhysxRaycastReport;
 class PhysxSceneStats2;
 class PhysxVehicle;
 class PhysxVehicleDesc;
+class PhysxCloth;
+class PhysxClothDesc;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PhysxScene
@@ -131,6 +133,12 @@ PUBLISHED:
   PhysxForceFieldShapeGroup *get_force_field_shape_group(unsigned int idx) const;
   MAKE_SEQ(get_force_field_shape_groups, get_num_force_field_shape_groups, get_force_field_shape_group);
 
+  // Cloths
+  unsigned int get_num_cloths() const;
+  PhysxCloth *create_cloth(PhysxClothDesc &desc);
+  PhysxCloth *get_cloth(unsigned int idx) const;
+  MAKE_SEQ(get_cloths, get_num_cloths, get_cloth);
+
   // Vehicles
   unsigned int get_num_vehicles() const;
   PhysxVehicle *create_vehicle(PhysxVehicleDesc &desc);
@@ -221,6 +229,7 @@ public:
   PhysxObjectCollection<PhysxForceFieldShapeGroup> _ffgroups;
   PhysxObjectCollection<PhysxController> _controllers;
   PhysxObjectCollection<PhysxVehicle> _vehicles;
+  PhysxObjectCollection<PhysxCloth> _cloths;
 
   PhysxMaterial *get_wheel_shape_material();
 
@@ -238,6 +247,8 @@ private:
   static PStatCollector _pcollector_update_transforms;
   static PStatCollector _pcollector_debug_renderer;
   static PStatCollector _pcollector_simulate;
+  static PStatCollector _pcollector_cloth;
+  //static PStatCollector _pcollector_softbody;
 
 ////////////////////////////////////////////////////////////////////
 public:

+ 5 - 2
panda/src/physx/physx_composite.cxx

@@ -17,6 +17,11 @@
 #include "physxCapsuleForceFieldShapeDesc.cxx"
 #include "physxCapsuleShape.cxx"
 #include "physxCapsuleShapeDesc.cxx"
+#include "physxCloth.cxx"
+#include "physxClothDesc.cxx"
+#include "physxClothMesh.cxx"
+#include "physxClothMeshDesc.cxx"
+#include "physxClothNode.cxx"
 #include "physxContactPair.cxx"
 #include "physxContactPoint.cxx"
 #include "physxContactReport.cxx"
@@ -112,5 +117,3 @@
 #include "physxWheelDesc.cxx"
 #include "physxWheelShape.cxx"
 #include "physxWheelShapeDesc.cxx"
-#include "physxClothMesh.cxx"
-#include "physxClothMeshDesc.cxx"