#ifndef NX_PHYSICS_NXCONTACTSTREAMITERATOR #define NX_PHYSICS_NXCONTACTSTREAMITERATOR /*----------------------------------------------------------------------------*\ | | Public Interface to NovodeX Technology | | www.novodex.com | \*----------------------------------------------------------------------------*/ /** \addtogroup physics @{ */ #include "Nxp.h" class NxShape; typedef NxU32 * NxContactStream; typedef const NxU32 * NxConstContactStream; /** \brief Flags which describe a contact @see NxContactStreamIterator */ enum NxShapePairStreamFlags { NX_SF_HAS_MATS_PER_POINT = (1<<0), //!< used when we have materials per triangle in a mesh. In this case the extData field is used after the point separation value. NX_SF_IS_INVALID = (1<<1), //!< this pair was invalidated in the system after being generated. The user should ignore these pairs. NX_SF_HAS_FEATURES_PER_POINT = (1<<2), //!< the stream includes per-point feature data //note: bits 8-15 are reserved for internal use (static ccd pullback counter) }; /** \brief NxContactStreamIterator is for iterating through packed contact streams.

The user code to use this iterator looks like this: \code void MyUserContactInfo::onContactNotify(NxPair & pair, NxU32 events) { NxContactStreamIterator i(pair.stream); while(i.goNextPair()) // user can call getNumPairs() here { while(i.goNextPatch()) // user can also call getShape() and getNumPatches() here { while(i.goNextPoint()) //user can also call getPatchNormal() and getNumPoints() here { //user can also call getPoint() and getSeparation() here } } } } \endcode

\note It is NOT OK to skip any of the iteration calls. For example, you may NOT put a break or a continue statement in any of the above blocks, short of completely aborting the iteration and deleting the NxContactStreamIterator object. \note The user should not rely on the exact geometry or positioning of contact points. The SDK is free to re-organise, merge or move contact points as long as the overall physical simulation is not affected.

If the stream was received from a NxFluidContactPair then some iterator methods work slightly different (see comments to the methods below).

Visulizations:

\li #NX_VISUALIZE_CONTACT_POINT \li #NX_VISUALIZE_CONTACT_NORMAL \li #NX_VISUALIZE_CONTACT_ERROR \li #NX_VISUALIZE_CONTACT_FORCE Platform: \li PC SW: Yes \li PPU : No (Hardware does not support contact stream readback) \li PS3 : Yes \li XB360: Yes @see NxConstContactStream NxUserContactReport */ class NxContactStreamIterator { public: /** \brief Starts the iteration, and returns the number of pairs. \param[in] stream @see NxConstContactStream */ NX_INLINE NxContactStreamIterator(NxConstContactStream stream); //iteration: /** \brief Goes on to the next pair, silently skipping invalid pairs. Returns false if there are no more pairs. Note that getNumPairs() also includes invalid pairs in the count. Once goNextPoint() returns false, the user should not call it again. \return True if there are more pairs. @see getNumPairs() getShape() */ NX_INLINE bool goNextPair(); /** \brief Goes on to the next patch (contacts with the same normal). Returns false if there are no more. Once goNextPatch() returns false, the user should not call it again until they move to the next pair. \return True if there are more patches. @see getPatchNormal() */ NX_INLINE bool goNextPatch(); /** \brief Goes on to the next contact point. Returns false if there are no more. Once goNextPoint() returns false, the user should not call it again unil they move to the next patch. \return True if there are more contact points. @see getPoint() */ NX_INLINE bool goNextPoint(); //accessors: /** \brief Returns the number of pairs in the structure. May be called at any time. \note Some of these pairs may be marked invalid using getShapeFlags() & NX_SF_IS_INVALID, so the effective number may be lower. goNextPair() will automatically skip these! \return The number of pairs in the struct (including invalid pairs). @see goNextPair() */ NX_INLINE NxU32 getNumPairs(); /** \brief Retrieves the shapes for the current pair. May be called after goNextPair() returned true. ShapeIndex is 0 or 1. Fluid actor contact stream: getShape(1) always returns NULL. \param[in] shapeIndex Used to choose which of the pair of shapes to retrieve(set to 0 or 1). \return The shape specified by shapeIndex. @see goNextPair() NxShape */ NX_INLINE NxShape * getShape(NxU32 shapeIndex); /** \brief Retrieves the shape flags for the current pair. May be called after goNextPair() returned true /return The shape flags for the current pair. See #NxShapeFlag. @see NxShapeFlag NxShape goNextPair() */ NX_INLINE NxU16 getShapeFlags(); /** \brief Retrieves the number of patches for the current pair. May be called after goNextPair() returned true /return The number of patches in this pair. @see goNextPatch() */ NX_INLINE NxU32 getNumPatches(); /** \brief Retrieves the number of remaining patches. May be called after goNextPair() returned true \return The number of patches remaining in this pair. @see goNextPatch() getNumPatches() */ NX_INLINE NxU32 getNumPatchesRemaining(); /** \brief Retrieves the patch normal. May be called after goNextPatch() returned true \return The patch normal. @see goNextPatch() */ NX_INLINE const NxVec3 & getPatchNormal(); /** \brief Retrieves the number of points in the current patch. May be called after goNextPatch() returned true \return The number of points in the current patch. @see goNextPoint() getNumPointsRemaining() */ NX_INLINE NxU32 getNumPoints(); /** \brief Retrieves the number of points remaining in the current patch. May be called after goNextPatch() returned true \return The number of points remaining in the current patch. @see goNextPoint() getNumPoints() */ NX_INLINE NxU32 getNumPointsRemaining(); /** \brief Returns the contact point position. May be called after goNextPoint() returned true Fluid actor contact stream: If getShapeFlags()&NX_SF_HAS_FEATURES_PER_POINT is specified, this returns the barycentric coordinates within the contact triangle. In this case the z coordinate is 0.0. \return the current contact point (or in the case of fluids the barycentric coordinate) @see getShapeFlags() goNextPoint() getNumPoints() getSeparation() getFeatureIndex0() */ NX_INLINE const NxVec3 & getPoint(); /** \brief Return the separation for the contact point. May be called after goNextPoint() returned true Fluid actor contact stream: always returns 0.0f. \return the seperation distance for the current point. @see goNextPoint() getPoint() */ NX_INLINE NxReal getSeparation(); /** \brief Retrieves the feature index. May be called after goNextPoint() returned true If getShapeFlags()&NX_SF_HAS_FEATURES_PER_POINT is specified, this method returns a feature belonging to shape 0, Fluid actor contact stream: returns the triangle index if shape 0 is a mesh shape. \return The feature index on shape 0 for the current point. @see NX_SF_FEATURE_INDICES goNextPoint() getPoint() getSeparation() getFeatureIndex1() */ NX_INLINE NxU32 getFeatureIndex0(); /** \brief Retrieves the feature index. may be called after goNextPoint() returned true If getShapeFlags()&NX_SF_HAS_FEATURES_PER_POINT is specified, this method returns a feature belonging to shape 1, Fluid actor contact stream: always returns 0.0f. \return The feature index on shape1 for the current point. @see NX_SF_FEATURE_INDICES goNextPoint() getPoint() getSeparation() getFeatureIndex0() */ NX_INLINE NxU32 getFeatureIndex1(); /** \brief Internal. */ NX_INLINE NxU32 getExtData(); /** \brief Retrieves the point normal force. May be called after goNextPoint() returned true If getShapeFlags()&NX_SF_POINT_CONTACT_FORCE is true (this is the case if this flag is raised for either shape in the pair), this method returns the contact force at this contact point. Returns 0 otherwise. \return The contact force for the current point. @see getShapeFlags goNextPoint() getPoint() */ NX_INLINE NxReal getPointNormalForce(); private: //iterator variables -- are only initialized by stream iterator calls: //Note: structs are used so that we can leave the iterators vars on the stack as they were //and the user's iteration code doesn't have to change when we add members. NxU32 numPairs; //current pair properties: NxShape * shapes[2]; NxU16 shapeFlags; NxU16 numPatches; //current patch properties: const NxVec3 * patchNormal; NxU32 numPoints; //current point properties: const NxVec3 * point; NxReal separation; NxU32 featureIndex0; NxU32 featureIndex1; NxU32 extData; //only exists if (shapeFlags & NX_SF_HAS_MATS_PER_POINT) NxU32 numPairsRemaining, numPatchesRemaining, numPointsRemaining; protected: const NxReal * pointNormalForce; //only exists if (shapeFlags & NX_SF_POINT_CONTACT_FORCE) NxConstContactStream stream; }; NX_INLINE NxContactStreamIterator::NxContactStreamIterator(NxConstContactStream s) { stream = s; numPairsRemaining = numPairs = stream ? *stream++ : 0; } NX_INLINE NxU32 NxContactStreamIterator::getNumPairs() { return numPairs; } NX_INLINE NxShape * NxContactStreamIterator::getShape(NxU32 shapeIndex) { NX_ASSERT(shapeIndex<=1); return shapes[shapeIndex]; } NX_INLINE NxU16 NxContactStreamIterator::getShapeFlags() { return shapeFlags; } NX_INLINE NxU32 NxContactStreamIterator::getNumPatches() { return numPatches; } NX_INLINE NxU32 NxContactStreamIterator::getNumPatchesRemaining() { return numPatchesRemaining; } NX_INLINE const NxVec3 & NxContactStreamIterator::getPatchNormal() { return *patchNormal; } NX_INLINE NxU32 NxContactStreamIterator::getNumPoints() { return numPoints; } NX_INLINE NxU32 NxContactStreamIterator::getNumPointsRemaining() { return numPointsRemaining; } NX_INLINE const NxVec3 & NxContactStreamIterator::getPoint() { return *point; } NX_INLINE NxReal NxContactStreamIterator::getSeparation() { return separation; } NX_INLINE NxU32 NxContactStreamIterator::getFeatureIndex0() { return featureIndex0; } NX_INLINE NxU32 NxContactStreamIterator::getFeatureIndex1() { return featureIndex1; } NX_INLINE NxU32 NxContactStreamIterator::getExtData() { return extData; } NX_INLINE NxReal NxContactStreamIterator::getPointNormalForce() { return pointNormalForce ? *pointNormalForce : 0; } NX_INLINE bool NxContactStreamIterator::goNextPair() { while (numPairsRemaining--) { #ifdef NX32 size_t bin0 = *stream++; size_t bin1 = *stream++; shapes[0] = (NxShape*)bin0; shapes[1] = (NxShape*)bin1; // shapes[0] = (NxShape*)*stream++; // shapes[1] = (NxShape*)*stream++; #else NxU64 low = (NxU64)*stream++; NxU64 high = (NxU64)*stream++; NxU64 bits = low|(high<<32); shapes[0] = (NxShape*)bits; low = (NxU64)*stream++; high = (NxU64)*stream++; bits = low|(high<<32); shapes[1] = (NxShape*)bits; #endif NxU32 t = *stream++; numPatchesRemaining = numPatches = t & 0xffff; shapeFlags = t >> 16; if (!(shapeFlags & NX_SF_IS_INVALID)) { return true; } else { while(goNextPatch()) { while(goNextPoint()) ; } } } return false; } NX_INLINE bool NxContactStreamIterator::goNextPatch() { if (numPatchesRemaining--) { patchNormal = reinterpret_cast(stream); stream += 3; numPointsRemaining = numPoints = *stream++; return true; } else return false; } NX_INLINE bool NxContactStreamIterator::goNextPoint() { if (numPointsRemaining--) { // Get contact point point = reinterpret_cast(stream); stream += 3; // Get separation NxU32 binary = *stream++; NxU32 is32bits = binary & NX_SIGN_BITMASK; binary |= NX_SIGN_BITMASK; // PT: separation is always negative, but the sign bit is used // for other purposes in the stream. separation = NX_FR(binary); // Get extra data if (shapeFlags & NX_SF_HAS_MATS_PER_POINT) extData = *stream++; else extData = 0xffffffff; //means that there is no ext data. if (shapeFlags & NX_SF_POINT_CONTACT_FORCE) pointNormalForce = reinterpret_cast(stream++); else pointNormalForce = 0; //there is no contact force. if (shapeFlags & NX_SF_HAS_FEATURES_PER_POINT) { if(is32bits) { featureIndex0 = *stream++; featureIndex1 = *stream++; } else { featureIndex0 = *stream++; featureIndex1 = featureIndex0>>16; featureIndex0 &= 0xffff; } } else { featureIndex0 = 0xffffffff; featureIndex1 = 0xffffffff; } //bind = *stream++; //materialIDs[0] = bind & 0xffff; //materialIDs[1] = bind >> 16; return true; } else return false; } /** @} */ #endif //AGCOPYRIGHTBEGIN /////////////////////////////////////////////////////////////////////////// // Copyright © 2005 AGEIA Technologies. // All rights reserved. www.ageia.com /////////////////////////////////////////////////////////////////////////// //AGCOPYRIGHTEND