Browse Source

Allowing negative stride when getting/setting height field shape heights or materials (#1087)

Jorrit Rouwe 1 year ago
parent
commit
6b7681d920

+ 11 - 9
Jolt/Physics/Collision/Shape/HeightFieldShape.cpp

@@ -199,7 +199,7 @@ uint32 HeightFieldShapeSettings::CalculateBitsPerSampleForError(float inMaxError
 	return bits_per_sample;
 	return bits_per_sample;
 }
 }
 
 
-void HeightFieldShape::CalculateActiveEdges(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStartX, uint inHeightsStartY, uint inHeightsStride, float inHeightsScale, float inActiveEdgeCosThresholdAngle, TempAllocator &inAllocator)
+void HeightFieldShape::CalculateActiveEdges(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStartX, uint inHeightsStartY, intptr_t inHeightsStride, float inHeightsScale, float inActiveEdgeCosThresholdAngle, TempAllocator &inAllocator)
 {
 {
 	// Allocate temporary buffer for normals
 	// Allocate temporary buffer for normals
 	uint normals_size = 2 * inSizeX * inSizeY * sizeof(Vec3);
 	uint normals_size = 2 * inSizeX * inSizeY * sizeof(Vec3);
@@ -834,7 +834,7 @@ bool HeightFieldShape::ProjectOntoSurface(Vec3Arg inLocalPosition, Vec3 &outSurf
 	}
 	}
 }
 }
 
 
-void HeightFieldShape::GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, float *outHeights, uint inHeightsStride) const
+void HeightFieldShape::GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, float *outHeights, intptr_t inHeightsStride) const
 {
 {
 	if (inSizeX == 0 || inSizeY == 0)
 	if (inSizeX == 0 || inSizeY == 0)
 		return;
 		return;
@@ -895,7 +895,7 @@ void HeightFieldShape::GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 	}
 	}
 }
 }
 
 
-void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStride, TempAllocator &inAllocator, float inActiveEdgeCosThresholdAngle)
+void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, intptr_t inHeightsStride, TempAllocator &inAllocator, float inActiveEdgeCosThresholdAngle)
 {
 {
 	if (inSizeX == 0 || inSizeY == 0)
 	if (inSizeX == 0 || inSizeY == 0)
 		return;
 		return;
@@ -922,12 +922,14 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 
 
 	// Get heights for affected area
 	// Get heights for affected area
 	const float *heights;
 	const float *heights;
+	intptr_t heights_stride;
 	float *temp_heights;
 	float *temp_heights;
 	if (need_temp_heights)
 	if (need_temp_heights)
 	{
 	{
 		// Fetch the surrounding height data (note we're forced to recompress this data with a potentially different range so there will be some precision loss here)
 		// Fetch the surrounding height data (note we're forced to recompress this data with a potentially different range so there will be some precision loss here)
 		temp_heights = (float *)inAllocator.Allocate(heights_size_x * heights_size_y * sizeof(float));
 		temp_heights = (float *)inAllocator.Allocate(heights_size_x * heights_size_y * sizeof(float));
 		heights = temp_heights;
 		heights = temp_heights;
+		heights_stride = heights_size_x;
 
 
 		// We need to fill in the following areas:
 		// We need to fill in the following areas:
 		//
 		//
@@ -971,7 +973,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 	{
 	{
 		// We can directly use the input buffer because there are no extra edges to take into account
 		// We can directly use the input buffer because there are no extra edges to take into account
 		heights = inHeights;
 		heights = inHeights;
-		heights_size_x = inHeightsStride;
+		heights_stride = inHeightsStride;
 		temp_heights = nullptr;
 		temp_heights = nullptr;
 	}
 	}
 
 
@@ -998,7 +1000,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 			for (uint sample_y = sample_start_y; sample_y < sample_y_end; ++sample_y)
 			for (uint sample_y = sample_start_y; sample_y < sample_y_end; ++sample_y)
 				for (uint sample_x = sample_start_x; sample_x < sample_x_end; ++sample_x)
 				for (uint sample_x = sample_start_x; sample_x < sample_x_end; ++sample_x)
 				{
 				{
-					float h = heights[sample_y * heights_size_x + sample_x];
+					float h = heights[sample_y * heights_stride + sample_x];
 					if (h != cNoCollisionValue)
 					if (h != cNoCollisionValue)
 					{
 					{
 						int quantized_height = Clamp((int)floor((h - mOffset.GetY()) / mScale.GetY()), 0, int(cMaxHeightValue16 - 1));
 						int quantized_height = Clamp((int)floor((h - mOffset.GetY()) / mScale.GetY()), 0, int(cMaxHeightValue16 - 1));
@@ -1031,7 +1033,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 				for (uint sample_x = sample_start_x; sample_x < sample_x_end; ++sample_x)
 				for (uint sample_x = sample_start_x; sample_x < sample_x_end; ++sample_x)
 				{
 				{
 					// Quantize height
 					// Quantize height
-					float h = heights[sample_y * heights_size_x + sample_x];
+					float h = heights[sample_y * heights_stride + sample_x];
 					uint8 quantized_height = h != cNoCollisionValue? uint8(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
 					uint8 quantized_height = h != cNoCollisionValue? uint8(Clamp((int)floor((h - offset) / scale), 0, int(mSampleMask) - 1)) : mSampleMask;
 
 
 					// Determine bit position of sample
 					// Determine bit position of sample
@@ -1056,7 +1058,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 	uint ae_y = inY > 1? inY - 2 : 0;
 	uint ae_y = inY > 1? inY - 2 : 0;
 	uint ae_sx = min(inX + inSizeX + 1, mSampleCount - 1) - ae_x;
 	uint ae_sx = min(inX + inSizeX + 1, mSampleCount - 1) - ae_x;
 	uint ae_sy = min(inY + inSizeY + 1, mSampleCount - 1) - ae_y;
 	uint ae_sy = min(inY + inSizeY + 1, mSampleCount - 1) - ae_y;
-	CalculateActiveEdges(ae_x, ae_y, ae_sx, ae_sy, heights, affected_x, affected_y, heights_size_x, 1.0f, inActiveEdgeCosThresholdAngle, inAllocator);
+	CalculateActiveEdges(ae_x, ae_y, ae_sx, ae_sy, heights, affected_x, affected_y, heights_stride, 1.0f, inActiveEdgeCosThresholdAngle, inAllocator);
 
 
 	// Free temporary buffer
 	// Free temporary buffer
 	if (temp_heights != nullptr)
 	if (temp_heights != nullptr)
@@ -1129,7 +1131,7 @@ void HeightFieldShape::SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY
 #endif
 #endif
 }
 }
 
 
-void HeightFieldShape::GetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, uint8 *outMaterials, uint inMaterialsStride) const
+void HeightFieldShape::GetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, uint8 *outMaterials, intptr_t inMaterialsStride) const
 {
 {
 	if (inSizeX == 0 || inSizeY == 0)
 	if (inSizeX == 0 || inSizeY == 0)
 		return;
 		return;
@@ -1179,7 +1181,7 @@ void HeightFieldShape::GetMaterials(uint inX, uint inY, uint inSizeX, uint inSiz
 	}
 	}
 }
 }
 
 
-bool HeightFieldShape::SetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, const uint8 *inMaterials, uint inMaterialsStride, const PhysicsMaterialList *inMaterialList, TempAllocator &inAllocator)
+bool HeightFieldShape::SetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, const uint8 *inMaterials, intptr_t inMaterialsStride, const PhysicsMaterialList *inMaterialList, TempAllocator &inAllocator)
 {
 {
 	if (inSizeX == 0 || inSizeY == 0)
 	if (inSizeX == 0 || inSizeY == 0)
 		return true;
 		return true;

+ 9 - 9
Jolt/Physics/Collision/Shape/HeightFieldShape.h

@@ -192,8 +192,8 @@ public:
 	/// @param inSizeX Number of samples in X direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inSizeX Number of samples in X direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inSizeY Number of samples in Y direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inSizeY Number of samples in Y direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param outHeights Returned height values, must be at least inSizeX * inSizeY floats. Values are returned in x-major order and can be cNoCollisionValue.
 	/// @param outHeights Returned height values, must be at least inSizeX * inSizeY floats. Values are returned in x-major order and can be cNoCollisionValue.
-	/// @param inHeightsStride Stride in floats between two consecutive rows of outHeights.
-	void							GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, float *outHeights, uint inHeightsStride) const;
+	/// @param inHeightsStride Stride in floats between two consecutive rows of outHeights (can be negative if the data is upside down).
+	void							GetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, float *outHeights, intptr_t inHeightsStride) const;
 
 
 	/// Set the height values of a block of data.
 	/// Set the height values of a block of data.
 	/// Note that this requires decompressing and recompressing a border of size mBlockSize in the negative x/y direction so will cause some precision loss.
 	/// Note that this requires decompressing and recompressing a border of size mBlockSize in the negative x/y direction so will cause some precision loss.
@@ -202,10 +202,10 @@ public:
 	/// @param inSizeX Number of samples in X direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inSizeX Number of samples in X direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inSizeY Number of samples in Y direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inSizeY Number of samples in Y direction, must be a multiple of mBlockSize and in the range [0, mSampleCount - inX]
 	/// @param inHeights The new height values to set, must be an array of inSizeX * inSizeY floats, can be cNoCollisionValue. Values outside of the range [GetMinHeightValue(), GetMaxHeightValue()] will be clamped.
 	/// @param inHeights The new height values to set, must be an array of inSizeX * inSizeY floats, can be cNoCollisionValue. Values outside of the range [GetMinHeightValue(), GetMaxHeightValue()] will be clamped.
-	/// @param inHeightsStride Stride in floats between two consecutive rows of outHeights.
+	/// @param inHeightsStride Stride in floats between two consecutive rows of outHeights (can be negative if the data is upside down).
 	/// @param inAllocator Allocator to use for temporary memory
 	/// @param inAllocator Allocator to use for temporary memory
 	/// @param inActiveEdgeCosThresholdAngle Cosine of the threshold angle (if the angle between the two triangles is bigger than this, the edge is active, note that a concave edge is always inactive).
 	/// @param inActiveEdgeCosThresholdAngle Cosine of the threshold angle (if the angle between the two triangles is bigger than this, the edge is active, note that a concave edge is always inactive).
-	void							SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStride, TempAllocator &inAllocator, float inActiveEdgeCosThresholdAngle = 0.996195f);
+	void							SetHeights(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, intptr_t inHeightsStride, TempAllocator &inAllocator, float inActiveEdgeCosThresholdAngle = 0.996195f);
 
 
 	/// Get the current list of materials, the indices returned by GetMaterials() will index into this list.
 	/// Get the current list of materials, the indices returned by GetMaterials() will index into this list.
 	const PhysicsMaterialList &		GetMaterialList() const						{ return mMaterials; }
 	const PhysicsMaterialList &		GetMaterialList() const						{ return mMaterials; }
@@ -216,8 +216,8 @@ public:
 	/// @param inSizeX Number of samples in X direction
 	/// @param inSizeX Number of samples in X direction
 	/// @param inSizeY Number of samples in Y direction
 	/// @param inSizeY Number of samples in Y direction
 	/// @param outMaterials Returned material indices, must be at least inSizeX * inSizeY uint8s. Values are returned in x-major order.
 	/// @param outMaterials Returned material indices, must be at least inSizeX * inSizeY uint8s. Values are returned in x-major order.
-	/// @param inMaterialsStride Stride in uint8s between two consecutive rows of outMaterials.
-	void							GetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, uint8 *outMaterials, uint inMaterialsStride) const;
+	/// @param inMaterialsStride Stride in uint8s between two consecutive rows of outMaterials (can be negative if the data is upside down).
+	void							GetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, uint8 *outMaterials, intptr_t inMaterialsStride) const;
 
 
 	/// Set the material indices of a block of data.
 	/// Set the material indices of a block of data.
 	/// @param inX Start X position, must in the range [0, mSampleCount - 1]
 	/// @param inX Start X position, must in the range [0, mSampleCount - 1]
@@ -225,11 +225,11 @@ public:
 	/// @param inSizeX Number of samples in X direction
 	/// @param inSizeX Number of samples in X direction
 	/// @param inSizeY Number of samples in Y direction
 	/// @param inSizeY Number of samples in Y direction
 	/// @param inMaterials The new material indices, must be at least inSizeX * inSizeY uint8s. Values are returned in x-major order.
 	/// @param inMaterials The new material indices, must be at least inSizeX * inSizeY uint8s. Values are returned in x-major order.
-	/// @param inMaterialsStride Stride in uint8s between two consecutive rows of inMaterials.
+	/// @param inMaterialsStride Stride in uint8s between two consecutive rows of inMaterials (can be negative if the data is upside down).
 	/// @param inMaterialList The material list to use for the new material indices or nullptr if the material list should not be updated
 	/// @param inMaterialList The material list to use for the new material indices or nullptr if the material list should not be updated
 	/// @param inAllocator Allocator to use for temporary memory
 	/// @param inAllocator Allocator to use for temporary memory
 	/// @return True if the material indices were set, false if the total number of materials exceeded 256
 	/// @return True if the material indices were set, false if the total number of materials exceeded 256
-	bool							SetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, const uint8 *inMaterials, uint inMaterialsStride, const PhysicsMaterialList *inMaterialList, TempAllocator &inAllocator);
+	bool							SetMaterials(uint inX, uint inY, uint inSizeX, uint inSizeY, const uint8 *inMaterials, intptr_t inMaterialsStride, const PhysicsMaterialList *inMaterialList, TempAllocator &inAllocator);
 
 
 	// See Shape
 	// See Shape
 	virtual void					SaveBinaryState(StreamOut &inStream) const override;
 	virtual void					SaveBinaryState(StreamOut &inStream) const override;
@@ -262,7 +262,7 @@ private:
 	void							CacheValues();
 	void							CacheValues();
 
 
 	/// Calculate bit mask for all active edges in the heightfield for a specific region
 	/// Calculate bit mask for all active edges in the heightfield for a specific region
-	void							CalculateActiveEdges(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStartX, uint inHeightsStartY, uint inHeightsStride, float inHeightsScale, float inActiveEdgeCosThresholdAngle, TempAllocator &inAllocator);
+	void							CalculateActiveEdges(uint inX, uint inY, uint inSizeX, uint inSizeY, const float *inHeights, uint inHeightsStartX, uint inHeightsStartY, intptr_t inHeightsStride, float inHeightsScale, float inActiveEdgeCosThresholdAngle, TempAllocator &inAllocator);
 
 
 	/// Calculate bit mask for all active edges in the heightfield
 	/// Calculate bit mask for all active edges in the heightfield
 	void							CalculateActiveEdges(const HeightFieldShapeSettings &inSettings);
 	void							CalculateActiveEdges(const HeightFieldShapeSettings &inSettings);