diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.h | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.h')
| -rw-r--r-- | PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.h | 1520 |
1 files changed, 1520 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.h b/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.h new file mode 100644 index 00000000..4cc9c6ba --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.h @@ -0,0 +1,1520 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef GU_HEIGHTFIELD_H +#define GU_HEIGHTFIELD_H + +#include "PsUserAllocated.h" +#include "CmRefCountable.h" +#include "PsMathUtils.h" +#include "GuSphere.h" +#include "PxHeightFieldSample.h" +#include "PxHeightFieldDesc.h" +#include "GuHeightFieldData.h" +#include "PxHeightField.h" + +//#define PX_HEIGHTFIELD_VERSION 0 +#define PX_HEIGHTFIELD_VERSION 1 // tiled version that was needed for PS3 only has been removed + +namespace physx +{ + +class GuMeshFactory; +class PxHeightFieldDesc; + +} + +namespace physx +{ +namespace Gu +{ +class HeightField : public PxHeightField, public Ps::UserAllocated, public Cm::RefCountable +{ +//= ATTENTION! ===================================================================================== +// Changing the data layout of this class breaks the binary serialization format. See comments for +// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData +// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION +// accordingly. +//================================================================================================== +public: +// PX_SERIALIZATION + HeightField(PxBaseFlags baseFlags) : PxHeightField(baseFlags), Cm::RefCountable(PxEmpty), mData(PxEmpty), mModifyCount(0) {} + + PX_PHYSX_COMMON_API virtual void exportExtraData(PxSerializationContext&); + PX_PHYSX_COMMON_API void importExtraData(PxDeserializationContext& context); + PX_FORCE_INLINE void setMeshFactory(GuMeshFactory* f) { mMeshFactory = f; } + PX_PHYSX_COMMON_API static HeightField* createObject(PxU8*& address, PxDeserializationContext& context); + PX_PHYSX_COMMON_API static void getBinaryMetaData(PxOutputStream& stream); + void resolveReferences(PxDeserializationContext&) {} + virtual void requires(PxProcessPxBaseCallback&){} +//~PX_SERIALIZATION + PX_PHYSX_COMMON_API HeightField(GuMeshFactory* meshFactory); + PX_PHYSX_COMMON_API HeightField(GuMeshFactory& factory, Gu::HeightFieldData& data); + + // PxHeightField + PX_PHYSX_COMMON_API virtual void release(); + PX_PHYSX_COMMON_API virtual PxU32 saveCells(void* destBuffer, PxU32 destBufferSize) const; + PX_PHYSX_COMMON_API virtual bool modifySamples(PxI32 startCol, PxI32 startRow, const PxHeightFieldDesc& subfieldDesc, bool shrinkBounds); + PX_PHYSX_COMMON_API virtual PxU32 getNbRows() const { return mData.rows; } + PX_PHYSX_COMMON_API virtual PxU32 getNbColumns() const { return mData.columns; } + PX_PHYSX_COMMON_API virtual PxHeightFieldFormat::Enum getFormat() const { return mData.format; } + PX_PHYSX_COMMON_API virtual PxU32 getSampleStride() const { return sizeof(PxHeightFieldSample); } + PX_PHYSX_COMMON_API virtual PxReal getThickness() const { return mData.thickness; } + PX_PHYSX_COMMON_API virtual PxReal getConvexEdgeThreshold() const { return mData.convexEdgeThreshold; } + PX_PHYSX_COMMON_API virtual PxHeightFieldFlags getFlags() const { return mData.flags; } + PX_PHYSX_COMMON_API virtual PxReal getHeight(PxReal x, PxReal z) const { return getHeightInternal(x, z); } + + PX_PHYSX_COMMON_API virtual void acquireReference(); + PX_PHYSX_COMMON_API virtual PxU32 getReferenceCount() const; + //~PxHeightField + + // RefCountable + PX_PHYSX_COMMON_API virtual void onRefCountZero(); + //~RefCountable + PX_PHYSX_COMMON_API virtual PxMaterialTableIndex getTriangleMaterialIndex(PxTriangleID triangleIndex) const + { + return getTriangleMaterial(triangleIndex); + } + PX_PHYSX_COMMON_API virtual PxVec3 getTriangleNormal(PxTriangleID triangleIndex) const + { + return getTriangleNormalInternal(triangleIndex); + } + + /** + \brief Returns the number of times the heightfield data has been modified + + Each time the heightfield is changed via 'modifySamples' this increments a counter. This method will return + the number of times the heightfield has been modified so that rendering code can know whether or not it needs to + rebuild the graphics representation of the mesh. + + \return the number of times the heightfield sample data has been modified. + */ + PX_PHYSX_COMMON_API virtual PxU32 getTimestamp() const + { + return mModifyCount; + } + + PX_PHYSX_COMMON_API bool loadFromDesc(const PxHeightFieldDesc&); + PX_PHYSX_COMMON_API bool load(PxInputStream&); + + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getNbRowsFast() const { return mData.rows; } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getNbColumnsFast() const { return mData.columns; } + PX_FORCE_INLINE PxHeightFieldFormat::Enum getFormatFast() const { return mData.format; } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getThicknessFast() const { return mData.thickness; } + PX_FORCE_INLINE PxU32 getFlagsFast() const { return mData.flags; } + + PX_FORCE_INLINE bool isDeltaHeightInsideExtent(PxReal dy, PxReal eps = 0.0f) const + { + return (mData.thickness <= 0.0f && dy <= eps && dy >= mData.thickness) || + (mData.thickness > 0.0f && dy > -eps && dy < mData.thickness); + } + + PX_FORCE_INLINE bool isDeltaHeightOppositeExtent(PxReal dy) const + { + return (mData.thickness <= 0.0f && dy > 0.0f) || (mData.thickness > 0.0f && dy < 0.0f); + } + + PX_CUDA_CALLABLE PX_FORCE_INLINE bool isZerothVertexShared(PxU32 vertexIndex) const + { +// return (getSample(vertexIndex).tessFlag & PxHeightFieldTessFlag::e0TH_VERTEX_SHARED); + return getSample(vertexIndex).tessFlag() != 0; + } + + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getMaterialIndex0(PxU32 vertexIndex) const { return getSample(vertexIndex).materialIndex0; } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getMaterialIndex1(PxU32 vertexIndex) const { return getSample(vertexIndex).materialIndex1; } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMaterialIndex01(PxU32 vertexIndex) const + { + const PxHeightFieldSample& sample = getSample(vertexIndex); + return PxU32(sample.materialIndex0 | (sample.materialIndex1 << 16)); + } + + PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal getHeight(PxU32 vertexIndex) const + { + return PxReal(getSample(vertexIndex).height); + } + + PX_INLINE PxReal getHeightInternal2(PxU32 vertexIndex, PxReal fracX, PxReal fracZ) const; + PX_FORCE_INLINE PxReal getHeightInternal(PxReal x, PxReal z) const + { + PxReal fracX, fracZ; + const PxU32 vertexIndex = computeCellCoordinates(x, z, fracX, fracZ); + + return getHeightInternal2(vertexIndex, fracX, fracZ); + } + + PX_FORCE_INLINE bool isValidVertex(PxU32 vertexIndex) const { return vertexIndex < mData.rows*mData.columns; } + + PX_INLINE PxVec3 getVertex(PxU32 vertexIndex) const; + PX_INLINE bool isConvexVertex(PxU32 vertexIndex, PxU32 row, PxU32 column) const; + + PX_INLINE bool isValidEdge(PxU32 edgeIndex) const; + PX_INLINE PxU32 getEdgeTriangleIndices(PxU32 edgeIndex, PxU32 triangleIndices[2]) const; + PX_INLINE PxU32 getEdgeTriangleIndices(PxU32 edgeIndex, PxU32 triangleIndices[2], PxU32 cell, PxU32 row, PxU32 column) const; + PX_INLINE void getEdgeVertexIndices(PxU32 edgeIndex, PxU32& vertexIndex0, PxU32& vertexIndex1) const; +// PX_INLINE bool isConvexEdge(PxU32 edgeIndex) const; + PX_INLINE bool isConvexEdge(PxU32 edgeIndex, PxU32 cell, PxU32 row, PxU32 column) const; + PX_FORCE_INLINE bool isConvexEdge(PxU32 edgeIndex) const + { + const PxU32 cell = edgeIndex / 3; + const PxU32 row = cell / mData.columns; + const PxU32 column = cell % mData.columns; + return isConvexEdge(edgeIndex, cell, row, column); + } + +// PX_INLINE void computeCellCoordinates(PxReal x, PxReal z, PxU32& row, PxU32& column, PxReal& fracX, PxReal& fracZ) const; +// PX_INLINE PxU32 computeCellCoordinates(PxReal x, PxReal z, PxU32 nbColumns, PxReal& fracX, PxReal& fracZ) const; + PX_PHYSX_COMMON_API PxU32 computeCellCoordinates(PxReal x, PxReal z, PxReal& fracX, PxReal& fracZ) const; + + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMinRow(PxReal x) const { return PxU32(PxClamp(PxI32(Ps::floor(x)), PxI32(0), PxI32(mData.rows-2))); } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMaxRow(PxReal x) const { return PxU32(PxClamp(PxI32(Ps::ceil(x)), PxI32(0), PxI32(mData.rows-1))); } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMinColumn(PxReal z) const { return PxU32(PxClamp(PxI32(Ps::floor(z)), PxI32(0), PxI32(mData.columns-2))); } + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getMaxColumn(PxReal z) const { return PxU32(PxClamp(PxI32(Ps::ceil(z)), PxI32(0), PxI32(mData.columns-1))); } + + PX_CUDA_CALLABLE PX_INLINE bool isValidTriangle(PxU32 triangleIndex) const; + PX_CUDA_CALLABLE PX_FORCE_INLINE bool isFirstTriangle(PxU32 triangleIndex) const { return ((triangleIndex & 0x1) == 0); } + + PX_CUDA_CALLABLE PX_FORCE_INLINE PxU16 getTriangleMaterial(PxU32 triangleIndex) const + { + return isFirstTriangle(triangleIndex) ? getMaterialIndex0(triangleIndex >> 1) : getMaterialIndex1(triangleIndex >> 1); + } + + PX_CUDA_CALLABLE PX_INLINE void getTriangleVertexIndices(PxU32 triangleIndex, PxU32& vertexIndex0, PxU32& vertexIndex1, PxU32& vertexIndex2) const; + PX_CUDA_CALLABLE PX_INLINE PxVec3 getTriangleNormalInternal(PxU32 triangleIndex) const; + PX_INLINE void getTriangleAdjacencyIndices(PxU32 triangleIndex,PxU32 vertexIndex0, PxU32 vertexIndex1, PxU32 vertexIndex2, PxU32& adjacencyIndex0, PxU32& adjacencyIndex1, PxU32& adjacencyIndex2) const; + + PX_INLINE PxVec3 getNormal_2(PxU32 vertexIndex, PxReal fracX, PxReal fracZ, PxReal xcoeff, PxReal ycoeff, PxReal zcoeff) const; + PX_FORCE_INLINE PxVec3 getNormal_(PxReal x, PxReal z, PxReal xcoeff, PxReal ycoeff, PxReal zcoeff) const + { + PxReal fracX, fracZ; + const PxU32 vertexIndex = computeCellCoordinates(x, z, fracX, fracZ); + + return getNormal_2(vertexIndex, fracX, fracZ, xcoeff, ycoeff, zcoeff); + } + + PX_INLINE PxU32 getTriangleIndex(PxReal x, PxReal z) const; + PX_INLINE PxU32 getTriangleIndex2(PxU32 cell, PxReal fracX, PxReal fracZ) const; + PX_FORCE_INLINE PxU16 getMaterial(PxReal x, PxReal z) const + { + return getTriangleMaterial(getTriangleIndex(x, z)); + } + + PX_FORCE_INLINE PxReal getMinHeight() const { return mMinHeight; } + PX_FORCE_INLINE PxReal getMaxHeight() const { return mMaxHeight; } + + PX_FORCE_INLINE const Gu::HeightFieldData& getData() const { return mData; } + + PX_CUDA_CALLABLE PX_FORCE_INLINE void getTriangleVertices(PxU32 triangleIndex, PxU32 row, PxU32 column, PxVec3& v0, PxVec3& v1, PxVec3& v2) const; + + // checks if current vertex is solid or not + bool isSolidVertex(PxU32 vertexIndex, PxU32 row, PxU32 coloumn, PxU16 holeMaterialIndex, + bool& nbSolid) const; + + // if precomputed bitmap define is used, the collision vertex information + // is precomputed during create height field and stored as a bit in materialIndex1 + PX_PHYSX_COMMON_API bool isCollisionVertexPreca(PxU32 vertexIndex, PxU32 row, PxU32 column, PxU16 holeMaterialIndex) const; + PX_FORCE_INLINE bool isCollisionVertex(PxU32 vertexIndex, PxU32, PxU32, PxU16) const + { + return getSample(vertexIndex).materialIndex1.isBitSet()!=0; + } + void parseTrianglesForCollisionVertices(PxU16 holeMaterialIndex); + + PX_PHYSX_COMMON_API PxReal computeExtreme(PxU32 minRow, PxU32 maxRow, PxU32 minColumn, PxU32 maxColumn) const; + + PX_FORCE_INLINE + PX_CUDA_CALLABLE const PxHeightFieldSample& getSample(PxU32 vertexIndex) const + { + PX_ASSERT(isValidVertex(vertexIndex)); + return mData.samples[vertexIndex]; + } + +#ifdef __CUDACC__ + PX_CUDA_CALLABLE void setSamplePtr(PxHeightFieldSample* s) { mData.samples = s; } +#endif + + Gu::HeightFieldData mData; + PxU32 mSampleStride; + PxU32 mNbSamples; // PT: added for platform conversion. Try to remove later. + PxReal mMinHeight; + PxReal mMaxHeight; + PxU32 mModifyCount; + // methods + PX_PHYSX_COMMON_API void releaseMemory(); + + PX_PHYSX_COMMON_API virtual ~HeightField(); + +private: + GuMeshFactory* mMeshFactory; // PT: changed to pointer for serialization +}; + +} // namespace Gu + + + +PX_INLINE PxVec3 Gu::HeightField::getVertex(PxU32 vertexIndex) const +{ + const PxU32 row = vertexIndex / mData.columns; + const PxU32 column = vertexIndex % mData.columns; +// return PxVec3(PxReal(row), getHeight(row * mData.columns + column), PxReal(column)); + return PxVec3(PxReal(row), getHeight(vertexIndex), PxReal(column)); +} + +// PT: only called from "isCollisionVertex", should move +PX_INLINE bool Gu::HeightField::isConvexVertex(PxU32 vertexIndex, PxU32 row, PxU32 column) const +{ +#ifdef PX_HEIGHTFIELD_DEBUG + PX_ASSERT(isValidVertex(vertexIndex)); +#endif + PX_ASSERT((vertexIndex / mData.columns)==row); + PX_ASSERT((vertexIndex % mData.columns)==column); + +// PxReal h0 = PxReal(2) * getHeight(vertexIndex); + PxI32 h0 = getSample(vertexIndex).height; + h0 += h0; + + bool definedInX, definedInZ; + PxI32 convexityX, convexityZ; + + if ((row > 0) && (row < mData.rows - 1)) + { +// convexityX = h0 - getHeight(vertexIndex + mData.columns) - getHeight(vertexIndex - mData.columns); + convexityX = h0 - getSample(vertexIndex + mData.columns).height - getSample(vertexIndex - mData.columns).height; + definedInX = true; + } + else + { + convexityX = 0; + definedInX = false; + } + + if ((column > 0) && (column < mData.columns - 1)) + { +// convexityZ = h0 - getHeight(vertexIndex + 1) - getHeight(vertexIndex - 1); + convexityZ = h0 - getSample(vertexIndex + 1).height - getSample(vertexIndex - 1).height; + definedInZ = true; + } + else + { + convexityZ = 0; + definedInZ = false; + } + + if(definedInX || definedInZ) + { + // PT: use XOR here + // saddle points +/* if ((convexityX > 0) && (convexityZ < 0)) + return false; + if ((convexityX < 0) && (convexityZ > 0)) + return false;*/ + if(((convexityX ^ convexityZ) & 0x80000000)==0) + return false; + + // inequality depends on thickness and offset by threshold. + const PxReal value = PxReal(convexityX + convexityZ); + // PT: thickness is always the same for a given heightfield so the comparison shouldn't be here + if (mData.thickness <= 0) + return value > mData.convexEdgeThreshold; + else + return value < -mData.convexEdgeThreshold; + } + + // this has to be one of the two corner vertices + return true; +} + + +PX_INLINE bool Gu::HeightField::isValidEdge(PxU32 edgeIndex) const +{ + const PxU32 cell = (edgeIndex / 3); + const PxU32 row = cell / mData.columns; + const PxU32 column = cell % mData.columns; +// switch (edgeIndex % 3) + switch (edgeIndex - cell*3) + { + case 0: + if (row > mData.rows - 1) return false; + if (column >= mData.columns - 1) return false; + break; + case 1: + if (row >= mData.rows - 1) return false; + if (column >= mData.columns - 1) return false; + break; + case 2: + if (row >= mData.rows - 1) return false; + if (column > mData.columns - 1) return false; + break; + } + return true; +} + + +PX_INLINE PxU32 Gu::HeightField::getEdgeTriangleIndices(PxU32 edgeIndex, PxU32 triangleIndices[2]) const +{ + const PxU32 cell = edgeIndex / 3; + const PxU32 row = cell / mData.columns; + const PxU32 column = cell % mData.columns; + PxU32 count = 0; +// switch (edgeIndex % 3) + switch (edgeIndex - cell*3) + { + case 0: + if (column < mData.columns - 1) + { + if (row > 0) + { +/* if (isZerothVertexShared(cell - mData.columns)) + triangleIndices[count++] = ((cell - mData.columns) << 1); + else + triangleIndices[count++] = ((cell - mData.columns) << 1) + 1;*/ + triangleIndices[count++] = ((cell - mData.columns) << 1) + 1 - isZerothVertexShared(cell - mData.columns); + } + if (row < mData.rows - 1) + { +/* if (isZerothVertexShared(cell)) + triangleIndices[count++] = (cell << 1) + 1; + else + triangleIndices[count++] = cell << 1;*/ + triangleIndices[count++] = (cell << 1) + isZerothVertexShared(cell); + } + } + break; + case 1: + if ((row < mData.rows - 1) && (column < mData.columns - 1)) + { + triangleIndices[count++] = cell << 1; + triangleIndices[count++] = (cell << 1) + 1; + } + break; + case 2: + if (row < mData.rows - 1) + { + if (column > 0) + triangleIndices[count++] = ((cell - 1) << 1) + 1; + if (column < mData.columns - 1) + triangleIndices[count++] = cell << 1; + } + break; + } + return count; +} + +PX_INLINE PxU32 Gu::HeightField::getEdgeTriangleIndices(PxU32 edgeIndex, PxU32 triangleIndices[2], PxU32 cell, PxU32 row, PxU32 column) const +{ +// const PxU32 cell = edgeIndex / 3; +// const PxU32 row = cell / mData.columns; +// const PxU32 column = cell % mData.columns; + PxU32 count = 0; +// switch (edgeIndex % 3) + switch (edgeIndex - cell*3) + { + case 0: + if (column < mData.columns - 1) + { + if (row > 0) + { +/* if (isZerothVertexShared(cell - mData.columns)) + triangleIndices[count++] = ((cell - mData.columns) << 1); + else + triangleIndices[count++] = ((cell - mData.columns) << 1) + 1;*/ + triangleIndices[count++] = ((cell - mData.columns) << 1) + 1 - isZerothVertexShared(cell - mData.columns); + } + if (row < mData.rows - 1) + { +/* if (isZerothVertexShared(cell)) + triangleIndices[count++] = (cell << 1) + 1; + else + triangleIndices[count++] = cell << 1;*/ + triangleIndices[count++] = (cell << 1) + isZerothVertexShared(cell); + } + } + break; + case 1: + if ((row < mData.rows - 1) && (column < mData.columns - 1)) + { + triangleIndices[count++] = cell << 1; + triangleIndices[count++] = (cell << 1) + 1; + } + break; + case 2: + if (row < mData.rows - 1) + { + if (column > 0) + triangleIndices[count++] = ((cell - 1) << 1) + 1; + if (column < mData.columns - 1) + triangleIndices[count++] = cell << 1; + } + break; + } + return count; +} + + +PX_INLINE void Gu::HeightField::getEdgeVertexIndices(PxU32 edgeIndex, PxU32& vertexIndex0, PxU32& vertexIndex1) const +{ + const PxU32 cell = edgeIndex / 3; +// switch (edgeIndex % 3) + switch (edgeIndex - cell*3) + { + case 0: + vertexIndex0 = cell; + vertexIndex1 = cell + 1; + break; + case 1: + { +/* if (isZerothVertexShared(cell)) + { + vertexIndex0 = cell; + vertexIndex1 = cell + mData.columns + 1; + } + else + { + vertexIndex0 = cell + 1; + vertexIndex1 = cell + mData.columns; + }*/ + const bool b = isZerothVertexShared(cell); + vertexIndex0 = cell + 1 - b; + vertexIndex1 = cell + mData.columns + b; + } + break; + case 2: + vertexIndex0 = cell; + vertexIndex1 = cell + mData.columns; + break; + } +} + +#ifdef REMOVED +PX_INLINE bool Gu::HeightField::isConvexEdge(PxU32 edgeIndex) const +{ + const PxU32 cell = edgeIndex / 3; + + const PxU32 row = cell / mData.columns; + if (row > mData.rows-2) return false; + + const PxU32 column = cell % mData.columns; + if (column > mData.columns-2) return false; + +// PxReal h0 = 0, h1 = 0, h2 = 0, h3 = 0; +// PxReal convexity = 0; + PxI32 h0 = 0, h1 = 0, h2 = 0, h3 = 0; + PxI32 convexity = 0; + +// switch (edgeIndex % 3) + switch (edgeIndex - cell*3) + { + case 0: + if (row < 1) return false; +/* if(isZerothVertexShared(cell - mData.columns)) + { + // <------ COL + // +----+ 0 R + // | / /# O + // | / / # W + // | / / # | + // |/ / # | + // + +====1 | + // | + // | + // | + // | + // | + // | + // V + // +// h0 = getHeight(cell - mData.columns); +// h1 = getHeight(cell); + h0 = getSample(cell - mData.columns).height; + h1 = getSample(cell).height; + } + else + { + // <------ COL + // 0 +----+ R + // #\ \ | O + // # \ \ | W + // # \ \ | | + // # \ \| | + // 1====+ + | + // | + // | + // | + // | + // | + // | + // V + // +// h0 = getHeight(cell - mData.columns + 1); +// h1 = getHeight(cell + 1); + h0 = getSample(cell - mData.columns + 1).height; + h1 = getSample(cell + 1).height; + }*/ + const bool b0 = !isZerothVertexShared(cell - mData.columns); + h0 = getSample(cell - mData.columns + b0).height; + h1 = getSample(cell + b0).height; + +/* if(isZerothVertexShared(cell)) + { + // <------ COL + // R + // O + // W + // | + // | + // | + // 2====+ 0 | + // # / /| | + // # / / | | + // # / / | | + // #/ / | | + // 3 +----+ | + // V + // +// h2 = getHeight(cell + 1); +// h3 = getHeight(cell + mData.columns + 1); + h2 = getSample(cell + 1).height; + h3 = getSample(cell + mData.columns + 1).height; + } + else + { + // <------ COL + // R + // O + // W + // | + // | + // | + // + +====2 | + // |\ \ # | + // | \ \ # | + // | \ \ # | + // | \ \# | + // +----+ 3 | + // V + // +// h2 = getHeight(cell); +// h3 = getHeight(cell + mData.columns); + h2 = getSample(cell).height; + h3 = getSample(cell + mData.columns).height; + }*/ + const bool b1 = isZerothVertexShared(cell); + h2 = getSample(cell + b1).height; + h3 = getSample(cell + mData.columns + b1).height; + + //convex = (h3-h2) < (h1-h0); + convexity = (h1-h0) - (h3-h2); + break; + case 1: +// h0 = getHeight(cell); +// h1 = getHeight(cell + 1); +// h2 = getHeight(cell + mData.columns); +// h3 = getHeight(cell + mData.columns + 1); + h0 = getSample(cell).height; + h1 = getSample(cell + 1).height; + h2 = getSample(cell + mData.columns).height; + h3 = getSample(cell + mData.columns + 1).height; + if (isZerothVertexShared(cell)) + //convex = (h0 + h3) > (h1 + h2); + convexity = (h0 + h3) - (h1 + h2); + else + //convex = (h2 + h1) > (h0 + h3); + convexity = (h2 + h1) - (h0 + h3); + break; + case 2: + if (column < 1) return false; +/* if(isZerothVertexShared(cell-1)) + { + // <-------------- COL + // 1====0 + R + // + / /| O + // + / / | W + // + / / | | + // +/ / | | + // + +----+ V + // +// h0 = getHeight(cell - 1); +// h1 = getHeight(cell); + h0 = getSample(cell - 1).height; + h1 = getSample(cell).height; + } + else + { + // <-------------- COL + // + +----+ R + // +\ \ | O + // + \ \ | W + // + \ \ | | + // + \ \| | + // 1====0 + V + // +// h0 = getHeight(cell - 1 + mData.columns); +// h1 = getHeight(cell + mData.columns); + h0 = getSample(cell - 1 + mData.columns).height; + h1 = getSample(cell + mData.columns).height; + }*/ + const PxU32 offset0 = isZerothVertexShared(cell-1) ? 0 : mData.columns; + h0 = getSample(cell - 1 + offset0).height; + h1 = getSample(cell + offset0).height; + +/* if(isZerothVertexShared(cell)) + { + // <-------------- COL + // +----+ + R + // | / /+ O + // | / / + W + // | / / + | + // |/ / + | + // + 3====2 V + // +// h2 = getHeight(cell + mData.columns); +// h3 = getHeight(cell + mData.columns + 1); + h2 = getSample(cell + mData.columns).height; + h3 = getSample(cell + mData.columns + 1).height; + } + else + { + // <-------------- COL + // + 3====2 R + // |\ \ + O + // | \ \ + W + // | \ \ + | + // | \ \+ | + // +----+ + V + // +// h2 = getHeight(cell); +// h3 = getHeight(cell + 1); + h2 = getSample(cell).height; + h3 = getSample(cell + 1).height; + }*/ + const PxU32 offset1 = isZerothVertexShared(cell) ? mData.columns : 0; + h2 = getSample(cell + offset1).height; + h3 = getSample(cell + offset1 + 1).height; + + //convex = (h3-h2) < (h1-h0); + convexity = (h1-h0) - (h3-h2); + break; + } + + const PxI32 threshold = PxI32(mData.convexEdgeThreshold); + if (mData.thickness <= 0) + { +// return convexity > mData.convexEdgeThreshold; + return convexity > threshold; + } + else + { +// return convexity < -mData.convexEdgeThreshold; + return convexity < -threshold; + } +} +#endif + +PX_INLINE bool Gu::HeightField::isConvexEdge(PxU32 edgeIndex, PxU32 cell, PxU32 row, PxU32 column) const +{ +// const PxU32 cell = edgeIndex / 3; + PX_ASSERT(cell == edgeIndex / 3); + +// const PxU32 row = cell / mData.columns; + PX_ASSERT(row == cell / mData.columns); + if (row > mData.rows-2) return false; + +// const PxU32 column = cell % mData.columns; + PX_ASSERT(column == cell % mData.columns); + if (column > mData.columns-2) return false; + +// PxReal h0 = 0, h1 = 0, h2 = 0, h3 = 0; +// PxReal convexity = 0; + PxI32 h0 = 0, h1 = 0, h2 = 0, h3 = 0; + PxI32 convexity = 0; + +// switch (edgeIndex % 3) + switch (edgeIndex - cell*3) + { + case 0: + { + if (row < 1) return false; +/* if(isZerothVertexShared(cell - mData.columns)) + { + // <------ COL + // +----+ 0 R + // | / /# O + // | / / # W + // | / / # | + // |/ / # | + // + +====1 | + // | + // | + // | + // | + // | + // | + // V + // +// h0 = getHeight(cell - mData.columns); +// h1 = getHeight(cell); + h0 = getSample(cell - mData.columns).height; + h1 = getSample(cell).height; + } + else + { + // <------ COL + // 0 +----+ R + // #\ \ | O + // # \ \ | W + // # \ \ | | + // # \ \| | + // 1====+ + | + // | + // | + // | + // | + // | + // | + // V + // +// h0 = getHeight(cell - mData.columns + 1); +// h1 = getHeight(cell + 1); + h0 = getSample(cell - mData.columns + 1).height; + h1 = getSample(cell + 1).height; + }*/ + const bool b0 = !isZerothVertexShared(cell - mData.columns); + h0 = getSample(cell - mData.columns + b0).height; + h1 = getSample(cell + b0).height; + +/* if(isZerothVertexShared(cell)) + { + // <------ COL + // R + // O + // W + // | + // | + // | + // 2====+ 0 | + // # / /| | + // # / / | | + // # / / | | + // #/ / | | + // 3 +----+ | + // V + // +// h2 = getHeight(cell + 1); +// h3 = getHeight(cell + mData.columns + 1); + h2 = getSample(cell + 1).height; + h3 = getSample(cell + mData.columns + 1).height; + } + else + { + // <------ COL + // R + // O + // W + // | + // | + // | + // + +====2 | + // |\ \ # | + // | \ \ # | + // | \ \ # | + // | \ \# | + // +----+ 3 | + // V + // +// h2 = getHeight(cell); +// h3 = getHeight(cell + mData.columns); + h2 = getSample(cell).height; + h3 = getSample(cell + mData.columns).height; + }*/ + const bool b1 = isZerothVertexShared(cell); + h2 = getSample(cell + b1).height; + h3 = getSample(cell + mData.columns + b1).height; + + //convex = (h3-h2) < (h1-h0); + convexity = (h1-h0) - (h3-h2); + } + break; + case 1: +// h0 = getHeight(cell); +// h1 = getHeight(cell + 1); +// h2 = getHeight(cell + mData.columns); +// h3 = getHeight(cell + mData.columns + 1); + h0 = getSample(cell).height; + h1 = getSample(cell + 1).height; + h2 = getSample(cell + mData.columns).height; + h3 = getSample(cell + mData.columns + 1).height; + if (isZerothVertexShared(cell)) + //convex = (h0 + h3) > (h1 + h2); + convexity = (h0 + h3) - (h1 + h2); + else + //convex = (h2 + h1) > (h0 + h3); + convexity = (h2 + h1) - (h0 + h3); + break; + case 2: + { + if (column < 1) return false; +/* if(isZerothVertexShared(cell-1)) + { + // <-------------- COL + // 1====0 + R + // + / /| O + // + / / | W + // + / / | | + // +/ / | | + // + +----+ V + // +// h0 = getHeight(cell - 1); +// h1 = getHeight(cell); + h0 = getSample(cell - 1).height; + h1 = getSample(cell).height; + } + else + { + // <-------------- COL + // + +----+ R + // +\ \ | O + // + \ \ | W + // + \ \ | | + // + \ \| | + // 1====0 + V + // +// h0 = getHeight(cell - 1 + mData.columns); +// h1 = getHeight(cell + mData.columns); + h0 = getSample(cell - 1 + mData.columns).height; + h1 = getSample(cell + mData.columns).height; + }*/ + const PxU32 offset0 = isZerothVertexShared(cell-1) ? 0 : mData.columns; + h0 = getSample(cell - 1 + offset0).height; + h1 = getSample(cell + offset0).height; + +/* if(isZerothVertexShared(cell)) + { + // <-------------- COL + // +----+ + R + // | / /+ O + // | / / + W + // | / / + | + // |/ / + | + // + 3====2 V + // +// h2 = getHeight(cell + mData.columns); +// h3 = getHeight(cell + mData.columns + 1); + h2 = getSample(cell + mData.columns).height; + h3 = getSample(cell + mData.columns + 1).height; + } + else + { + // <-------------- COL + // + 3====2 R + // |\ \ + O + // | \ \ + W + // | \ \ + | + // | \ \+ | + // +----+ + V + // +// h2 = getHeight(cell); +// h3 = getHeight(cell + 1); + h2 = getSample(cell).height; + h3 = getSample(cell + 1).height; + }*/ + const PxU32 offset1 = isZerothVertexShared(cell) ? mData.columns : 0; + h2 = getSample(cell + offset1).height; + h3 = getSample(cell + offset1 + 1).height; + + //convex = (h3-h2) < (h1-h0); + convexity = (h1-h0) - (h3-h2); + } + break; + } + + const PxI32 threshold = PxI32(mData.convexEdgeThreshold); + if (mData.thickness <= 0) + { +// return convexity > mData.convexEdgeThreshold; + return convexity > threshold; + } + else + { +// return convexity < -mData.convexEdgeThreshold; + return convexity < -threshold; + } +} +#ifdef REMOVED +PX_INLINE void Gu::HeightField::computeCellCoordinates(PxReal x, PxReal z, PxU32& _row, PxU32& _column, PxReal& _fracX, PxReal& _fracZ) const +{ + x = physx::intrinsics::selectMax(x, 0.0f); + z = physx::intrinsics::selectMax(z, 0.0f); + + PxU32 row = (PxU32)x; + PxReal fracX = x - PxReal(row); + if (row > mData.rows - 2) + { + row = mData.rows - 2; + fracX = PxReal(1); + } + + PxU32 column = (PxU32)z; + PxReal fracZ = z - PxReal(column); + if (column > mData.columns - 2) + { + column = mData.columns - 2; + fracZ = PxReal(1); + } + + _row = row; + _column = column; + _fracX = fracX; + _fracZ = fracZ; +} +#endif + +PX_INLINE bool Gu::HeightField::isValidTriangle(PxU32 triangleIndex) const +{ + const PxU32 cell = triangleIndex >> 1; + const PxU32 row = cell / mData.columns; + if (row >= (mData.rows - 1)) return false; + const PxU32 column = cell % mData.columns; + if (column >= (mData.columns - 1)) return false; + return true; +} + + + + +PX_INLINE void Gu::HeightField::getTriangleVertexIndices(PxU32 triangleIndex, PxU32& vertexIndex0, PxU32& vertexIndex1, PxU32& vertexIndex2) const +{ + const PxU32 cell = triangleIndex >> 1; + if (isZerothVertexShared(cell)) + { + // <---- COL + // 0----2 1 R + // | 1 / /| O + // | / / | W + // | / / | | + // |/ / 0 | | + // 1 2----0 V + // + if (isFirstTriangle(triangleIndex)) + { + vertexIndex0 = cell + mData.columns; + vertexIndex1 = cell; + vertexIndex2 = cell + mData.columns + 1; + } + else + { + vertexIndex0 = cell + 1; + vertexIndex1 = cell + mData.columns + 1; + vertexIndex2 = cell; + } + } + else + { + // <---- COL + // 2 1----0 R + // |\ \ 0 | O + // | \ \ | W + // | \ \ | | + // | 1 \ \| | + // 0----1 2 V + // + if (isFirstTriangle(triangleIndex)) + { + vertexIndex0 = cell; + vertexIndex1 = cell + 1; + vertexIndex2 = cell + mData.columns; + } + else + { + vertexIndex0 = cell + mData.columns + 1; + vertexIndex1 = cell + mData.columns; + vertexIndex2 = cell + 1; + } + } +} + +PX_INLINE void Gu::HeightField::getTriangleAdjacencyIndices(PxU32 triangleIndex, PxU32 vertexIndex0, PxU32 vertexIndex1, PxU32 vertexIndex2, PxU32& adjacencyIndex0, PxU32& adjacencyIndex1, PxU32& adjacencyIndex2) const +{ + PX_UNUSED(vertexIndex0); + PX_UNUSED(vertexIndex1); + PX_UNUSED(vertexIndex2); + + const PxU32 cell = triangleIndex >> 1; + if (isZerothVertexShared(cell)) + { + // <---- COL + // 0----2 1 R + // | 1 / /| O + // | / / | W + // | / / | | + // |/ / 0 | | + // 1 2----0 V + // + if (isFirstTriangle(triangleIndex)) + { + adjacencyIndex0 = 0xFFFFFFFF; + adjacencyIndex1 = triangleIndex + 1; + adjacencyIndex2 = 0xFFFFFFFF; + + if((cell % (mData.columns) != 0)) + { + adjacencyIndex0 = triangleIndex - 1; + } + + if((cell / mData.columns != mData.rows - 2)) + { + adjacencyIndex2 = ((cell + mData.columns) * 2) + 1; + } + } + else + { + adjacencyIndex0 = 0xFFFFFFFF; + adjacencyIndex1 = triangleIndex - 1; + adjacencyIndex2 = 0xFFFFFFFF; + + if(cell % (mData.columns) < (mData.columns - 2)) + { + adjacencyIndex0 = triangleIndex + 1; + } + + if(cell >= mData.columns - 1) + { + adjacencyIndex2 = (cell - mData.columns) * 2; + } + } + } + else + { + // <---- COL + // 2 1----0 R + // |\ \ 0 | O + // | \ \ | W + // | \ \ | | + // | 1 \ \| | + // 0----1 2 V + // + if (isFirstTriangle(triangleIndex)) + { + adjacencyIndex0 = 0xFFFFFFFF; + adjacencyIndex1 = triangleIndex + 1; + adjacencyIndex2 = 0xFFFFFFFF; + + if(cell >= mData.columns - 1) + { + adjacencyIndex0 = ((cell - (mData.columns)) * 2) + 1; + } + + if((cell % (mData.columns) != 0)) + { + adjacencyIndex2 = triangleIndex - 1; + } + } + else + { + adjacencyIndex0 = 0xFFFFFFFF; + adjacencyIndex1 = triangleIndex - 1; + adjacencyIndex2 = 0xFFFFFFFF; + + if((cell / mData.columns != mData.rows - 2)) + { + adjacencyIndex0 = (cell + (mData.columns)) * 2; + } + + if(cell % (mData.columns) < (mData.columns - 2)) + { + adjacencyIndex2 = triangleIndex + 1; + } + } + } +} + +PX_INLINE PxVec3 Gu::HeightField::getTriangleNormalInternal(PxU32 triangleIndex) const +{ + PxU32 v0, v1, v2; + getTriangleVertexIndices(triangleIndex, v0, v1, v2); + +// const PxReal h0 = getHeight(v0); +// const PxReal h1 = getHeight(v1); +// const PxReal h2 = getHeight(v2); + const PxI32 h0 = getSample(v0).height; + const PxI32 h1 = getSample(v1).height; + const PxI32 h2 = getSample(v2).height; + + // Fix for NvBug 685420 +// if(mThickness>0.0f) +// n = -n; + const PxReal coeff = physx::intrinsics::fsel(mData.thickness, -1.0f, 1.0f); + +// PxVec3 n(0,1,0); + const PxU32 cell = triangleIndex >> 1; + if (isZerothVertexShared(cell)) + { + // <---- COL + // 0----2 1 R + // | 1 / /| O + // | / / | W + // | / / | | + // |/ / 0 | | + // 1 2----0 V + // + if (isFirstTriangle(triangleIndex)) + { +// n.x = -(h0-h1); +// n.z = -(h2-h0); + return PxVec3(coeff*PxReal(h1-h0), coeff, coeff*PxReal(h0-h2)); + } + else + { +// n.x = -(h1-h0); +// n.z = -(h0-h2); + return PxVec3(coeff*PxReal(h0-h1), coeff, coeff*PxReal(h2-h0)); + } + } + else + { + // <---- COL + // 2 1----0 R + // |\ \ 0 | O + // | \ \ | W + // | \ \ | | + // | 1 \ \| | + // 0----1 2 V + // + if (isFirstTriangle(triangleIndex)) + { +// n.x = -(h2-h0); +// n.z = -(h1-h0); + return PxVec3(coeff*PxReal(h0-h2), coeff, coeff*PxReal(h0-h1)); + } + else + { +// n.x = -(h0-h2); +// n.z = -(h0-h1); + return PxVec3(coeff*PxReal(h2-h0), coeff, coeff*PxReal(h1-h0)); + } + } +// return n; +} + +PX_INLINE PxReal Gu::HeightField::getHeightInternal2(PxU32 vertexIndex, PxReal fracX, PxReal fracZ) const +{ + if (isZerothVertexShared(vertexIndex)) + { + // <----Z---+ + // +----+ | + // | /| | + // | / | X + // | / | | + // |/ | | + // +----+ | + // V + const PxReal h0 = getHeight(vertexIndex); + const PxReal h2 = getHeight(vertexIndex + mData.columns + 1); + if (fracZ > fracX) + { + // <----Z---+ + // 1----0 | + // | / | + // | / X + // | / | + // |/ | + // 2 | + // V + const PxReal h1 = getHeight(vertexIndex + 1); + return h0 + fracZ*(h1-h0) + fracX*(h2-h1); + } + else + { + // <----Z---+ + // 0 | + // /| | + // / | X + // / | | + // / | | + // 2----1 | + // V + const PxReal h1 = getHeight(vertexIndex + mData.columns); + return h0 + fracX*(h1-h0) + fracZ*(h2-h1); + } + } + else + { + // <----Z---+ + // +----+ | + // |\ | | + // | \ | X + // | \ | | + // | \| | + // +----+ | + // V + const PxReal h2 = getHeight(vertexIndex + mData.columns); + const PxReal h1 = getHeight(vertexIndex + 1); + if (fracX + fracZ < 1.0f) + { + // <----Z---+ + // 1----0 | + // \ | | + // \ | X + // \ | | + // \| | + // 2 | + // V + const PxReal h0 = getHeight(vertexIndex); + return h0 + fracZ*(h1-h0) + fracX*(h2-h0); + } + else + { + // <----Z---+ + // 1 | + // |\ | + // | \ X + // | \ | + // | \ | + // 0----2 | + // V + // + // Note that we need to flip fracX and fracZ since we are moving the origin + const PxReal h0 = getHeight(vertexIndex + mData.columns + 1); + return h0 + (1.0f - fracZ)*(h2-h0) + (1.0f - fracX)*(h1-h0); + } + } +} + +PX_INLINE PxVec3 Gu::HeightField::getNormal_2(PxU32 vertexIndex, PxReal fracX, PxReal fracZ, PxReal xcoeff, PxReal ycoeff, PxReal zcoeff) const +{ + PxVec3 normal; + if (isZerothVertexShared(vertexIndex)) + { + // <----Z---+ + // +----+ | + // | /| | + // | / | X + // | / | | + // |/ | | + // +----+ | + // V +// const PxReal h0 = getHeight(vertexIndex); +// const PxReal h2 = getHeight(vertexIndex + mData.columns + 1); + const PxI32 ih0 = getSample(vertexIndex).height; + const PxI32 ih2 = getSample(vertexIndex + mData.columns + 1).height; + if (fracZ >= fracX) + { + // <----Z---+ + // 1----0 | + // | / | + // | / X + // | / | + // |/ | + // 2 | + // V +// const PxReal h0 = getHeight(vertexIndex); +// const PxReal h1 = getHeight(vertexIndex + 1); +// const PxReal h2 = getHeight(vertexIndex + mData.columns + 1); +// normal.set(-(h2-h1), 1.0f, -(h1-h0)); + const PxI32 ih1 = getSample(vertexIndex + 1).height; + normal = PxVec3(PxReal(ih1 - ih2)*xcoeff, ycoeff, PxReal(ih0 - ih1)*zcoeff); + } + else + { + // <----Z---+ + // 0 | + // /| | + // / | X + // / | | + // / | | + // 2----1 | + // V +// const PxReal h0 = getHeight(vertexIndex); +// const PxReal h1 = getHeight(vertexIndex + mData.columns); +// const PxReal h2 = getHeight(vertexIndex + mData.columns + 1); +// normal.set(-(h1-h0), 1.0f, -(h2-h1)); + const PxI32 ih1 = getSample(vertexIndex + mData.columns).height; + normal = PxVec3(PxReal(ih0 - ih1)*xcoeff, ycoeff, PxReal(ih1 - ih2)*zcoeff); + } + } + else + { + // <----Z---+ + // +----+ | + // |\ | | + // | \ | X + // | \ | | + // | \| | + // +----+ | + // V + const PxI32 ih1 = getSample(vertexIndex + 1).height; + const PxI32 ih2 = getSample(vertexIndex + mData.columns).height; + if (fracX + fracZ <= PxReal(1)) + { + // <----Z---+ + // 1----0 | + // \ | | + // \ | X + // \ | | + // \| | + // 2 | + // V +// const PxReal h0 = getHeight(vertexIndex); +// const PxReal h1 = getHeight(vertexIndex + 1); +// const PxReal h2 = getHeight(vertexIndex + mData.columns); +// normal.set(-(h2-h0), 1.0f, -(h1-h0)); + const PxI32 ih0 = getSample(vertexIndex).height; +// const PxI32 ih1 = getSample(vertexIndex + 1).height; +// const PxI32 ih2 = getSample(vertexIndex + mData.columns).height; + normal = PxVec3(PxReal(ih0 - ih2)*xcoeff, ycoeff, PxReal(ih0 - ih1)*zcoeff); + } + else + { + // <----Z---+ + // 2 | + // |\ | + // | \ X + // | \ | + // | \ | + // 0----1 | + // V + // + // Note that we need to flip fracX and fracZ since we are moving the origin +// const PxReal h2 = getHeight(vertexIndex + 1); +// const PxReal h1 = getHeight(vertexIndex + mData.columns); +// const PxReal h0 = getHeight(vertexIndex + mData.columns + 1); +// normal.set(-(h0-h2), 1.0f, -(h0-h1)); +// const PxI32 ih2 = getSample(vertexIndex + 1).height; +// const PxI32 ih1 = getSample(vertexIndex + mData.columns).height; + const PxI32 ih0 = getSample(vertexIndex + mData.columns + 1).height; +// normal.set(PxReal(ih2 - ih0), 1.0f, PxReal(ih1b - ih0)); + normal = PxVec3(PxReal(ih1 - ih0)*xcoeff, ycoeff, PxReal(ih2 - ih0)*zcoeff); + } + } + return (mData.thickness <= 0.0f) ? normal : -normal; +} + +PX_INLINE PxU32 Gu::HeightField::getTriangleIndex2(PxU32 cell, PxReal fracX, PxReal fracZ) const +{ + if (isZerothVertexShared(cell)) + return (fracZ > fracX) ? (cell << 1) + 1 : (cell << 1); + else + return (fracX + fracZ > 1) ? (cell << 1) + 1 : (cell << 1); +} + +PX_INLINE PxU32 Gu::HeightField::getTriangleIndex(PxReal x, PxReal z) const +{ + PxReal fracX, fracZ; + const PxU32 cell = computeCellCoordinates(x, z, fracX, fracZ); + + return getTriangleIndex2(cell, fracX, fracZ); +} + +/** +Although inefficient, this is used for particles (PxcHeightFieldAabbTest.h). +*/ +PX_FORCE_INLINE void Gu::HeightField::getTriangleVertices(PxU32 triangleIndex, PxU32 row, PxU32 column, PxVec3& v0, PxVec3& v1, PxVec3& v2) const +{ + PxU32 cell = triangleIndex >> 1; + PX_ASSERT(row * getNbColumnsFast() + column == cell); + + PxReal h0 = getHeight(cell); + PxReal h1 = getHeight(cell + 1); + PxReal h2 = getHeight(cell + getNbColumnsFast()); + PxReal h3 = getHeight(cell + getNbColumnsFast() + 1); + + if (isFirstTriangle(triangleIndex)) + { + if (isZerothVertexShared(cell)) + { + // <---- COL + // 1 R + // /| O + // / | W + // / | | + // / 0 | | + // 2----0 V + // + v0 = PxVec3(PxReal(row + 1), h2, PxReal(column )); + v1 = PxVec3(PxReal(row ), h0, PxReal(column )); + v2 = PxVec3(PxReal(row + 1), h3, PxReal(column + 1)); + } + else + { + // <---- COL + // 1----0 R + // \ 0 | O + // \ | W + // \ | | + // \| | + // 2 V + // + v0 = PxVec3(PxReal(row ), h0, PxReal(column )); + v1 = PxVec3(PxReal(row ), h1, PxReal(column + 1)); + v2 = PxVec3(PxReal(row + 1), h2, PxReal(column )); + } + } + else + { + if (isZerothVertexShared(cell)) + { + // <---- COL + // 0----2 R + // | 1 / O + // | / W + // | / | + // |/ | + // 1 V + // + v0 = PxVec3(PxReal(row ), h1, PxReal(column + 1)); + v1 = PxVec3(PxReal(row + 1), h3, PxReal(column + 1)); + v2 = PxVec3(PxReal(row ), h0, PxReal(column )); + } + else + { + // <---- COL + // 2 R + // |\ O + // | \ W + // | \ | + // | 1 \ | + // 0----1 V + // + v0 = PxVec3(PxReal(row + 1), h3, PxReal(column + 1)); + v1 = PxVec3(PxReal(row + 1), h2, PxReal(column )); + v2 = PxVec3(PxReal(row ), h1, PxReal(column + 1)); + } + } +} + +struct EdgeData +{ + PxU32 edgeIndex; + PxU32 cell; + PxU32 row; + PxU32 column; +}; +PX_PHYSX_COMMON_API PxU32 getVertexEdgeIndices(const Gu::HeightField& heightfield, PxU32 vertexIndex, PxU32 row, PxU32 column, EdgeData edgeIndices[8]); +PX_PHYSX_COMMON_API PxU32 getEdgeTriangleIndices(const Gu::HeightField& heightfield, const EdgeData& edgeData, PxU32* PX_RESTRICT triangleIndices); + +} + +#endif |