aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.cpp
downloadphysx-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.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.cpp814
1 files changed, 814 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.cpp b/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.cpp
new file mode 100644
index 00000000..d376715c
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/hf/GuHeightField.cpp
@@ -0,0 +1,814 @@
+// 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.
+
+
+#include "foundation/PxMemory.h"
+#include "PsIntrinsics.h"
+#include "GuHeightField.h"
+#include "PsAllocator.h"
+#include "PsUtilities.h"
+#include "GuMeshFactory.h"
+#include "GuSerialize.h"
+#include "CmUtils.h"
+#include "CmBitMap.h"
+#include "PsFoundation.h"
+
+using namespace physx;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Gu::HeightField::HeightField(GuMeshFactory* meshFactory)
+: PxHeightField(PxConcreteType::eHEIGHTFIELD, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
+, mSampleStride (0)
+, mNbSamples (0)
+, mMinHeight (0.0f)
+, mMaxHeight (0.0f)
+, mModifyCount (0)
+, mMeshFactory (meshFactory)
+{
+ mData.format = PxHeightFieldFormat::eS16_TM;
+ mData.rows = 0;
+ mData.columns = 0;
+ mData.convexEdgeThreshold = 0;
+ mData.flags = PxHeightFieldFlags();
+ mData.samples = NULL;
+ mData.thickness = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Gu::HeightField::HeightField(GuMeshFactory& factory, Gu::HeightFieldData& data)
+: PxHeightField(PxConcreteType::eHEIGHTFIELD, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
+, mSampleStride (0)
+, mNbSamples (0)
+, mMinHeight (0.0f)
+, mMaxHeight (0.0f)
+, mModifyCount (0)
+, mMeshFactory (&factory)
+{
+ mData = data;
+ data.samples = NULL; // set to null so that we don't release the memory
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Gu::HeightField::~HeightField()
+{
+ releaseMemory();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// PX_SERIALIZATION
+void Gu::HeightField::onRefCountZero()
+{
+ PX_ASSERT(mMeshFactory);
+ if(mMeshFactory->removeHeightField(*this))
+ {
+ GuMeshFactory* mf = mMeshFactory;
+ Cm::deletePxBase(this);
+ mf->notifyFactoryListener(this, PxConcreteType::eHEIGHTFIELD);
+ return;
+ }
+
+ // PT: if we reach this point, we didn't find the mesh in the Physics object => don't delete!
+ // This prevents deleting the object twice.
+ Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Gu::HeightField::onRefCountZero: double deletion detected!");
+}
+
+void Gu::HeightField::exportExtraData(PxSerializationContext& stream)
+{
+ // PT: warning, order matters for the converter. Needs to export the base stuff first
+ const PxU32 size = mData.rows * mData.columns * sizeof(PxHeightFieldSample);
+ stream.alignData(PX_SERIAL_ALIGN); // PT: generic align within the generic allocator
+ stream.writeData(mData.samples, size);
+}
+
+void Gu::HeightField::importExtraData(PxDeserializationContext& context)
+{
+ mData.samples = context.readExtraData<PxHeightFieldSample, PX_SERIAL_ALIGN>(mData.rows * mData.columns);
+}
+
+Gu::HeightField* Gu::HeightField::createObject(PxU8*& address, PxDeserializationContext& context)
+{
+ HeightField* obj = new (address) HeightField(PxBaseFlag::eIS_RELEASABLE);
+ address += sizeof(HeightField);
+ obj->importExtraData(context);
+ obj->resolveReferences(context);
+ return obj;
+}
+
+//~PX_SERIALIZATION
+
+void Gu::HeightField::release()
+{
+ decRefCount();
+}
+
+void Gu::HeightField::acquireReference()
+{
+ incRefCount();
+}
+
+PxU32 Gu::HeightField::getReferenceCount() const
+{
+ return getRefCount();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool Gu::HeightField::modifySamples(PxI32 startCol, PxI32 startRow, const PxHeightFieldDesc& desc, bool shrinkBounds)
+{
+ const PxU32 nbCols = getNbColumns();
+ const PxU32 nbRows = getNbRows();
+ PX_CHECK_AND_RETURN_NULL(desc.format == mData.format, "Gu::HeightField::modifySamples: desc.format mismatch");
+ //PX_CHECK_AND_RETURN_NULL(startCol + desc.nbColumns <= nbCols,
+ // "Gu::HeightField::modifySamples: startCol + nbColumns out of range");
+ //PX_CHECK_AND_RETURN_NULL(startRow + desc.nbRows <= nbRows,
+ // "Gu::HeightField::modifySamples: startRow + nbRows out of range");
+ //PX_CHECK_AND_RETURN_NULL(desc.samples.stride == mSampleStride, "Gu::HeightField::modifySamples: desc.samples.stride mismatch");
+
+ // by default bounds don't shrink since the whole point of this function is to avoid modifying the whole HF
+ // unless shrinkBounds is specified. then the bounds will be fully recomputed later
+ PxReal minHeight = mMinHeight;
+ PxReal maxHeight = mMaxHeight;
+ PxU32 hiRow = PxMin(PxU32(PxMax(0, startRow + PxI32(desc.nbRows))), nbRows);
+ PxU32 hiCol = PxMin(PxU32(PxMax(0, startCol + PxI32(desc.nbColumns))), nbCols);
+ for (PxU32 row = PxU32(PxMax(startRow, 0)); row < hiRow; row++)
+ {
+ for (PxU32 col = PxU32(PxMax(startCol, 0)); col < hiCol; col++)
+ {
+ const PxU32 vertexIndex = col + row*nbCols;
+ PxHeightFieldSample* targetSample = &mData.samples[vertexIndex];
+
+ // update target sample from source sample
+ const PxHeightFieldSample& sourceSample =
+ (reinterpret_cast<const PxHeightFieldSample*>(desc.samples.data))[col - startCol + (row - startRow) * desc.nbColumns];
+ *targetSample = sourceSample;
+
+ if(isCollisionVertexPreca(vertexIndex, row, col, PxHeightFieldMaterial::eHOLE))
+ targetSample->materialIndex1.setBit();
+ else
+ targetSample->materialIndex1.clearBit();
+
+ // grow (but not shrink) the height extents
+ const PxReal h = getHeight(vertexIndex);
+ minHeight = physx::intrinsics::selectMin(h, minHeight);
+ maxHeight = physx::intrinsics::selectMax(h, maxHeight);
+ }
+ }
+
+ if (shrinkBounds)
+ {
+ // do a full recompute on vertical bounds to allow shrinking
+ minHeight = PX_MAX_REAL;
+ maxHeight = -PX_MAX_REAL;
+ // have to recompute the min&max from scratch...
+ for (PxU32 vertexIndex = 0; vertexIndex < nbRows * nbCols; vertexIndex ++)
+ {
+ // update height extents
+ const PxReal h = getHeight(vertexIndex);
+ minHeight = physx::intrinsics::selectMin(h, minHeight);
+ maxHeight = physx::intrinsics::selectMax(h, maxHeight);
+ }
+ }
+ mMinHeight = minHeight;
+ mMaxHeight = maxHeight;
+
+ // update local space aabb
+ CenterExtents& bounds = mData.mAABB;
+ bounds.mCenter.y = (maxHeight + minHeight)*0.5f;
+ bounds.mExtents.y = (maxHeight - minHeight)*0.5f;
+
+ mModifyCount++;
+
+ return true;
+}
+
+bool Gu::HeightField::load(PxInputStream& stream)
+{
+ // release old memory
+ releaseMemory();
+
+ // Import header
+ PxU32 version;
+ bool endian;
+ if(!readHeader('H', 'F', 'H', 'F', version, endian, stream))
+ return false;
+
+ // load mData
+ mData.rows = readDword(endian, stream);
+ mData.columns = readDword(endian, stream);
+ mData.rowLimit = readFloat(endian, stream);
+ mData.colLimit = readFloat(endian, stream);
+ mData.nbColumns = readFloat(endian, stream);
+ mData.thickness = readFloat(endian, stream);
+ mData.convexEdgeThreshold = readFloat(endian, stream);
+
+ PxU16 flags = readWord(endian, stream);
+ mData.flags = PxHeightFieldFlags(flags);
+
+ PxU32 format = readDword(endian, stream);
+ mData.format = PxHeightFieldFormat::Enum(format);
+
+ PxBounds3 minMaxBounds;
+ minMaxBounds.minimum.x = readFloat(endian, stream);
+ minMaxBounds.minimum.y = readFloat(endian, stream);
+ minMaxBounds.minimum.z = readFloat(endian, stream);
+ minMaxBounds.maximum.x = readFloat(endian, stream);
+ minMaxBounds.maximum.y = readFloat(endian, stream);
+ minMaxBounds.maximum.z = readFloat(endian, stream);
+ mData.mAABB = CenterExtents(minMaxBounds);
+
+ mSampleStride = readDword(endian, stream);
+ mNbSamples = readDword(endian, stream);
+ mMinHeight = readFloat(endian, stream);
+ mMaxHeight = readFloat(endian, stream);
+
+ // allocate height samples
+ mData.samples = NULL;
+ const PxU32 nbVerts = mData.rows * mData.columns;
+ if (nbVerts > 0)
+ {
+ mData.samples = reinterpret_cast<PxHeightFieldSample*>(PX_ALLOC(nbVerts*sizeof(PxHeightFieldSample), "PxHeightFieldSample"));
+ if (mData.samples == NULL)
+ {
+ Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "Gu::HeightField::load: PX_ALLOC failed!");
+ return false;
+ }
+ stream.read(mData.samples, mNbSamples*sizeof(PxHeightFieldSample));
+ if (endian)
+ for(PxU32 i = 0; i < mNbSamples; i++)
+ {
+ PxHeightFieldSample& s = mData.samples[i];
+ PX_ASSERT(sizeof(PxU16) == sizeof(s.height));
+ flip(s.height);
+ }
+ }
+
+ return true;
+}
+
+bool Gu::HeightField::loadFromDesc(const PxHeightFieldDesc& desc)
+{
+ // verify descriptor
+ PX_CHECK_AND_RETURN_NULL(desc.isValid(), "Gu::HeightField::loadFromDesc: desc.isValid() failed!");
+
+ // release old memory
+ releaseMemory();
+
+ // copy trivial data
+ mData.format = desc.format;
+ mData.rows = desc.nbRows;
+ mData.columns = desc.nbColumns;
+ mData.thickness = desc.thickness;
+ mData.convexEdgeThreshold = desc.convexEdgeThreshold;
+ mData.flags = desc.flags;
+ mSampleStride = desc.samples.stride;
+
+ // PT: precompute some data - mainly for Xbox
+ mData.rowLimit = float(mData.rows - 2);
+ mData.colLimit = float(mData.columns - 2);
+ mData.nbColumns = float(desc.nbColumns);
+
+ // allocate and copy height samples
+ // compute extents too
+ mData.samples = NULL;
+ const PxU32 nbVerts = desc.nbRows * desc.nbColumns;
+ mMinHeight = PX_MAX_REAL;
+ mMaxHeight = -PX_MAX_REAL;
+
+ if (nbVerts > 0)
+ {
+ mData.samples = reinterpret_cast<PxHeightFieldSample*>(PX_ALLOC(nbVerts*sizeof(PxHeightFieldSample), "PxHeightFieldSample"));
+ if (mData.samples == NULL)
+ {
+ Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, "Gu::HeightField::load: PX_ALLOC failed!");
+ return false;
+ }
+ const PxU8* PX_RESTRICT src = reinterpret_cast<const PxU8*>(desc.samples.data);
+ PxHeightFieldSample* PX_RESTRICT dst = mData.samples;
+ PxI16 minHeight = PX_MAX_I16;
+ PxI16 maxHeight = PX_MIN_I16;
+ for(PxU32 i=0;i<nbVerts;i++)
+ {
+ const PxHeightFieldSample& sample = *reinterpret_cast<const PxHeightFieldSample*>(src);
+ *dst++ = sample;
+ const PxI16 height = sample.height;
+ minHeight = height < minHeight ? height : minHeight;
+ maxHeight = height > maxHeight ? height : maxHeight;
+ src += desc.samples.stride;
+ }
+ mMinHeight = PxReal(minHeight);
+ mMaxHeight = PxReal(maxHeight);
+ }
+
+ PX_ASSERT(mMaxHeight >= mMinHeight);
+
+ parseTrianglesForCollisionVertices(PxHeightFieldMaterial::eHOLE);
+
+// PT: "mNbSamples" only used by binary converter
+ mNbSamples = mData.rows * mData.columns;
+
+ //Compute local space aabb.
+ PxBounds3 bounds;
+ bounds.minimum.y = getMinHeight();
+ bounds.maximum.y = getMaxHeight();
+
+ bounds.minimum.x = 0;
+ bounds.maximum.x = PxReal(getNbRowsFast() - 1);
+ bounds.minimum.z = 0;
+ bounds.maximum.z = PxReal(getNbColumnsFast() - 1);
+ mData.mAABB=bounds;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+PxU32 Gu::HeightField::saveCells(void* destBuffer, PxU32 destBufferSize) const
+{
+ PxU32 n = mData.columns * mData.rows * sizeof(PxHeightFieldSample);
+ if (n > destBufferSize) n = destBufferSize;
+ PxMemCopy(destBuffer, mData.samples, n);
+
+ return n;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+PX_PHYSX_COMMON_API void Gu::HeightField::releaseMemory()
+{
+// PX_SERIALIZATION
+ if(getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)
+//~PX_SERIALIZATION
+ {
+ PX_FREE(mData.samples);
+ mData.samples = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// PT: TODO: use those faster functions everywhere
+namespace physx
+{
+
+PX_PHYSX_COMMON_API PxU32 getVertexEdgeIndices(const Gu::HeightField& heightfield, PxU32 vertexIndex, PxU32 row, PxU32 column, EdgeData edgeIndices[8])
+{
+ const PxU32 nbColumns = heightfield.getData().columns;
+ const PxU32 nbRows = heightfield.getData().rows;
+ PX_ASSERT((vertexIndex / nbColumns)==row);
+ PX_ASSERT((vertexIndex % nbColumns)==column);
+
+ PxU32 count = 0;
+
+ if (row > 0)
+ {
+// edgeIndices[count++] = 3 * (vertexIndex - nbColumns) + 2;
+ const PxU32 cell = vertexIndex - nbColumns;
+ edgeIndices[count].edgeIndex = 3 * cell + 2;
+ edgeIndices[count].cell = cell;
+ edgeIndices[count].row = row-1;
+ edgeIndices[count].column = column;
+ count++;
+ }
+
+ if (column < nbColumns-1)
+ {
+ if (row > 0)
+ {
+ if (!heightfield.isZerothVertexShared(vertexIndex - nbColumns))
+ {
+// edgeIndices[count++] = 3 * (vertexIndex - nbColumns) + 1;
+ const PxU32 cell = vertexIndex - nbColumns;
+ edgeIndices[count].edgeIndex = 3 * cell + 1;
+ edgeIndices[count].cell = cell;
+ edgeIndices[count].row = row-1;
+ edgeIndices[count].column = column;
+ count++;
+ }
+ }
+// edgeIndices[count++] = 3 * vertexIndex;
+ edgeIndices[count].edgeIndex = 3 * vertexIndex;
+ edgeIndices[count].cell = vertexIndex;
+ edgeIndices[count].row = row;
+ edgeIndices[count].column = column;
+ count++;
+
+ if (row < nbRows - 1)
+ {
+ if (heightfield.isZerothVertexShared(vertexIndex))
+ {
+// edgeIndices[count++] = 3 * vertexIndex + 1;
+ edgeIndices[count].edgeIndex = 3 * vertexIndex + 1;
+ edgeIndices[count].cell = vertexIndex;
+ edgeIndices[count].row = row;
+ edgeIndices[count].column = column;
+ count++;
+ }
+ }
+ }
+
+ if (row < nbRows - 1)
+ {
+// edgeIndices[count++] = 3 * vertexIndex + 2;
+ edgeIndices[count].edgeIndex = 3 * vertexIndex + 2;
+ edgeIndices[count].cell = vertexIndex;
+ edgeIndices[count].row = row;
+ edgeIndices[count].column = column;
+ count++;
+ }
+
+ if (column > 0)
+ {
+ if (row < nbRows - 1)
+ {
+ if (!heightfield.isZerothVertexShared(vertexIndex - 1))
+ {
+// edgeIndices[count++] = 3 * (vertexIndex - 1) + 1;
+ const PxU32 cell = vertexIndex - 1;
+ edgeIndices[count].edgeIndex = 3 * cell + 1;
+ edgeIndices[count].cell = cell;
+ edgeIndices[count].row = row;
+ edgeIndices[count].column = column-1;
+ count++;
+ }
+ }
+// edgeIndices[count++] = 3 * (vertexIndex - 1);
+ const PxU32 cell = vertexIndex - 1;
+ edgeIndices[count].edgeIndex = 3 * cell;
+ edgeIndices[count].cell = cell;
+ edgeIndices[count].row = row;
+ edgeIndices[count].column = column-1;
+ count++;
+ if (row > 0)
+ {
+ if (heightfield.isZerothVertexShared(vertexIndex - nbColumns - 1))
+ {
+// edgeIndices[count++] = 3 * (vertexIndex - nbColumns - 1) + 1;
+ const PxU32 cell1 = vertexIndex - nbColumns - 1;
+ edgeIndices[count].edgeIndex = 3 * cell1 + 1;
+ edgeIndices[count].cell = cell1;
+ edgeIndices[count].row = row-1;
+ edgeIndices[count].column = column-1;
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+PX_PHYSX_COMMON_API PxU32 getEdgeTriangleIndices(const Gu::HeightField& heightfield, const EdgeData& edgeData, PxU32* PX_RESTRICT triangleIndices)
+{
+ const PxU32 nbColumns = heightfield.getData().columns;
+ const PxU32 nbRows = heightfield.getData().rows;
+
+ const PxU32 edgeIndex = edgeData.edgeIndex;
+ const PxU32 cell = edgeData.cell;
+ const PxU32 row = edgeData.row;
+ const PxU32 column = edgeData.column;
+ PX_ASSERT(cell==edgeIndex / 3);
+ PX_ASSERT(row==cell / nbColumns);
+ PX_ASSERT(column==cell % nbColumns);
+ PxU32 count = 0;
+ switch (edgeIndex - cell*3)
+ {
+ case 0:
+ if (column < nbColumns - 1)
+ {
+ if (row > 0)
+ {
+ if (heightfield.isZerothVertexShared(cell - nbColumns))
+ triangleIndices[count++] = ((cell - nbColumns) << 1);
+ else
+ triangleIndices[count++] = ((cell - nbColumns) << 1) + 1;
+ }
+ if (row < nbRows - 1)
+ {
+ if (heightfield.isZerothVertexShared(cell))
+ triangleIndices[count++] = (cell << 1) + 1;
+ else
+ triangleIndices[count++] = cell << 1;
+ }
+ }
+ break;
+ case 1:
+ if ((row < nbRows - 1) && (column < nbColumns - 1))
+ {
+ triangleIndices[count++] = cell << 1;
+ triangleIndices[count++] = (cell << 1) + 1;
+ }
+ break;
+ case 2:
+ if (row < nbRows - 1)
+ {
+ if (column > 0)
+ {
+ triangleIndices[count++] = ((cell - 1) << 1) + 1;
+ }
+ if (column < nbColumns - 1)
+ {
+ triangleIndices[count++] = cell << 1;
+ }
+ }
+ break;
+ }
+
+ return count;
+}
+
+}
+
+PX_FORCE_INLINE PxU32 anyHole(PxU32 doubleMatIndex, PxU16 holeMaterialIndex)
+{
+ return PxU32((doubleMatIndex & 0xFFFF) == holeMaterialIndex) | (PxU32(doubleMatIndex >> 16) == holeMaterialIndex);
+}
+
+void Gu::HeightField::parseTrianglesForCollisionVertices(PxU16 holeMaterialIndex)
+{
+ const PxU32 nbColumns = getNbColumnsFast();
+ const PxU32 nbRows = getNbRowsFast();
+
+ Cm::BitMap rowHoles[2];
+ rowHoles[0].resizeAndClear(nbColumns + 1);
+ rowHoles[1].resizeAndClear(nbColumns + 1);
+
+ for (PxU32 iCol = 0; iCol < nbColumns; iCol++)
+ {
+ if (anyHole(getMaterialIndex01(iCol), holeMaterialIndex))
+ {
+ rowHoles[0].set(iCol);
+ rowHoles[0].set(iCol + 1);
+ }
+ PxU32 vertIndex = iCol;
+ if(isCollisionVertexPreca(vertIndex, 0, iCol, holeMaterialIndex))
+ mData.samples[vertIndex].materialIndex1.setBit();
+ else
+ mData.samples[vertIndex].materialIndex1.clearBit();
+ }
+
+ PxU32 nextRow = 1, currentRow = 0;
+ for (PxU32 iRow = 1; iRow < nbRows; iRow++)
+ {
+ PxU32 rowOffset = iRow*nbColumns;
+ for (PxU32 iCol = 0; iCol < nbColumns; iCol++)
+ {
+ const PxU32 vertIndex = rowOffset + iCol; // column index plus current row offset (vertex/cell index)
+ if(anyHole(getMaterialIndex01(vertIndex), holeMaterialIndex))
+ {
+ rowHoles[currentRow].set(iCol);
+ rowHoles[currentRow].set(iCol + 1);
+ rowHoles[nextRow].set(iCol);
+ rowHoles[nextRow].set(iCol + 1);
+ }
+
+ if ((iCol == 0) || (iCol == nbColumns - 1) || (iRow == nbRows - 1) || rowHoles[currentRow].test(iCol))
+ {
+ if(isCollisionVertexPreca(vertIndex, iRow, iCol, holeMaterialIndex))
+ mData.samples[vertIndex].materialIndex1.setBit();
+ else
+ mData.samples[vertIndex].materialIndex1.clearBit();
+ } else
+ {
+ if (isConvexVertex(vertIndex, iRow, iCol))
+ mData.samples[vertIndex].materialIndex1.setBit();
+ }
+ }
+
+ rowHoles[currentRow].clear();
+
+ // swap prevRow and prevPrevRow
+ nextRow ^= 1; currentRow ^= 1;
+ }
+}
+
+bool Gu::HeightField::isSolidVertex(PxU32 vertexIndex, PxU32 row, PxU32 column, PxU16 holeMaterialIndex, bool& nbSolid) const
+{
+ // check if solid and boundary
+ // retrieve edge indices for current vertexIndex
+ EdgeData edgeIndices[8];
+ const PxU32 edgeCount = ::getVertexEdgeIndices(*this, vertexIndex, row, column, edgeIndices);
+
+ PxU32 faceCounts[8];
+ PxU32 faceIndices[2 * 8];
+ PxU32* dst = faceIndices;
+ for (PxU32 i = 0; i < edgeCount; i++)
+ {
+ faceCounts[i] = ::getEdgeTriangleIndices(*this, edgeIndices[i], dst);
+ dst += 2;
+ }
+
+ nbSolid = false;
+ const PxU32* currentfaceIndices = faceIndices; // parallel array of pairs of face indices per edge index
+ for (PxU32 i = 0; i < edgeCount; i++)
+ {
+ if (faceCounts[i] > 1)
+ {
+ const PxU16& material0 = getTriangleMaterial(currentfaceIndices[0]);
+ const PxU16& material1 = getTriangleMaterial(currentfaceIndices[1]);
+ // ptchernev TODO: this is a bit arbitrary
+ if (material0 != holeMaterialIndex)
+ {
+ nbSolid = true;
+ if (material1 == holeMaterialIndex)
+ return true; // edge between solid and hole => return true
+ }
+ if (material1 != holeMaterialIndex)
+ {
+ nbSolid = true;
+ if (material0 == holeMaterialIndex)
+ return true; // edge between hole and solid => return true
+ }
+ }
+ else
+ {
+ if (getTriangleMaterial(currentfaceIndices[0]) != holeMaterialIndex)
+ return true;
+ }
+ currentfaceIndices += 2; // 2 face indices per edge
+ }
+ return false;
+}
+
+bool Gu::HeightField::isCollisionVertexPreca(PxU32 vertexIndex, PxU32 row, PxU32 column, PxU16 holeMaterialIndex) const
+{
+#ifdef PX_HEIGHTFIELD_DEBUG
+ PX_ASSERT(isValidVertex(vertexIndex));
+#endif
+ PX_ASSERT((vertexIndex / getNbColumnsFast()) == row);
+ PX_ASSERT((vertexIndex % getNbColumnsFast()) == column);
+
+ // check boundary conditions - boundary edges shouldn't produce collision with eNO_BOUNDARY_EDGES flag
+ if(mData.flags & PxHeightFieldFlag::eNO_BOUNDARY_EDGES)
+ if ((row == 0) || (column == 0) || (row >= mData.rows-1) || (column >= mData.columns-1))
+ return false;
+
+ bool nbSolid;
+ if(isSolidVertex(vertexIndex, row, column, holeMaterialIndex, nbSolid))
+ return true;
+
+ // return true if it is boundary or solid and convex
+ return (nbSolid && isConvexVertex(vertexIndex, row, column));
+}
+
+
+/*struct int64
+{
+ int a,b;
+};*/
+
+#ifdef REMOVED
+// PT: special version computing vertex index directly
+PxU32 Gu::HeightField::computeCellCoordinates(PxReal x, PxReal z, PxU32 nbColumns, PxReal& fracX, PxReal& fracZ) const
+{
+ x = physx::intrinsics::selectMax(x, 0.0f);
+ z = physx::intrinsics::selectMax(z, 0.0f);
+
+ PxU32 row = (PxU32)x;
+ PxU32 column = (PxU32)z;
+
+/*int64 tmp_x, tmp_z;
+_asm lwz r11, x
+_asm lfs fr0, 0(r11)
+_asm fctiwz fr13, fr0
+_asm stfd fr13, tmp_x
+
+_asm lwz r11, z
+_asm lfs fr0, 0(r11)
+_asm fctiwz fr13, fr0
+_asm stfd fr13, tmp_z
+
+PxU32 row = tmp_x.b;
+PX_ASSERT(row==PxU32(x));*/
+ if (row > mData.rows - 2)
+ {
+ row = mData.rows - 2;
+ fracX = PxReal(1);
+ }
+ else
+ {
+ fracX = x - PxReal(row);
+ }
+
+//PxU32 column = tmp_z.b;
+//PX_ASSERT(column==PxU32(z));
+
+ if (column > mData.columns - 2)
+ {
+ column = mData.columns - 2;
+ fracZ = PxReal(1);
+ }
+ else
+ {
+ fracZ = z - PxReal(column);
+ }
+ const PxU32 vertexIndex = row * nbColumns + column;
+
+ return vertexIndex;
+}
+#endif
+
+// AP: this naming is confusing and inconsistent with return value. the function appears to compute vertex coord rather than cell coords
+// it would most likely be better to stay in cell coords instead, since fractional vertex coords just do not make any sense
+PxU32 Gu::HeightField::computeCellCoordinates(PxReal x, PxReal z,
+ PxReal& fracX, PxReal& fracZ) const
+{
+ namespace i = physx::intrinsics;
+
+ x = i::selectMax(x, 0.0f);
+ z = i::selectMax(z, 0.0f);
+#if 0 // validation code for scaled clamping epsilon computation
+ for (PxReal ii = 1.0f; ii < 100000.0f; ii+=1.0f)
+ {
+ PX_UNUSED(ii);
+ PX_ASSERT(PxFloor(ii+(1-1e-7f*ii)) == ii);
+ }
+#endif
+ PxF32 epsx = 1.0f - PxAbs(x+1.0f) * 1e-6f; // epsilon needs to scale with values of x,z...
+ PxF32 epsz = 1.0f - PxAbs(z+1.0f) * 1e-6f;
+ PxF32 x1 = i::selectMin(x, mData.rowLimit+epsx);
+ PxF32 z1 = i::selectMin(z, mData.colLimit+epsz);
+ x = PxFloor(x1);
+ fracX = x1 - x;
+ z = PxFloor(z1);
+ fracZ = z1 - z;
+ PX_ASSERT(x >= 0.0f && x < PxF32(mData.rows));
+ PX_ASSERT(z >= 0.0f && z < PxF32(mData.columns));
+
+ const PxU32 vertexIndex = PxU32(x * (mData.nbColumns) + z);
+ PX_ASSERT(vertexIndex < (mData.rows)*(mData.columns));
+
+ return vertexIndex;
+}
+
+PxReal Gu::HeightField::computeExtreme(PxU32 minRow, PxU32 maxRow, PxU32 minColumn, PxU32 maxColumn) const
+{
+ const bool thicknessNegOrNull = (getThicknessFast() <= 0.0f);
+
+// PxReal hfExtreme = thicknessNegOrNull ? -PX_MAX_REAL : PX_MAX_REAL;
+ PxI32 hfExtreme = thicknessNegOrNull ? PX_MIN_I32 : PX_MAX_I32;
+
+/* for(PxU32 row = minRow; row <= maxRow; row++)
+ {
+ for(PxU32 column = minColumn; column <= maxColumn; column++)
+ {
+ const PxReal h = getHeight(row * getNbColumnsFast() + column);
+ hfExtreme = thicknessNegOrNull ? PxMax(hfExtreme, h) : PxMin(hfExtreme, h);
+ }
+ }*/
+
+ if(thicknessNegOrNull)
+ {
+ for(PxU32 row = minRow; row <= maxRow; row++)
+ {
+ for(PxU32 column = minColumn; column <= maxColumn; column++)
+ {
+// const PxReal h = getHeight(row * getNbColumnsFast() + column);
+ const PxI32 h = getSample(row * getNbColumnsFast() + column).height;
+ hfExtreme = PxMax(hfExtreme, h);
+ }
+ }
+ }
+ else
+ {
+ for(PxU32 row = minRow; row <= maxRow; row++)
+ {
+ for(PxU32 column = minColumn; column <= maxColumn; column++)
+ {
+// const PxReal h = getHeight(row * getNbColumnsFast() + column);
+ const PxI32 h = getSample(row * getNbColumnsFast() + column).height;
+ hfExtreme = PxMin(hfExtreme, h);
+ }
+ }
+ }
+
+// return hfExtreme;
+ return PxReal(hfExtreme);
+}