Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/Shape.h
9913 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Physics/Body/MassProperties.h>
8
#include <Jolt/Physics/Collision/BackFaceMode.h>
9
#include <Jolt/Physics/Collision/CollisionCollector.h>
10
#include <Jolt/Physics/Collision/ShapeFilter.h>
11
#include <Jolt/Geometry/AABox.h>
12
#include <Jolt/Core/Reference.h>
13
#include <Jolt/Core/Color.h>
14
#include <Jolt/Core/Result.h>
15
#include <Jolt/Core/NonCopyable.h>
16
#include <Jolt/Core/UnorderedMap.h>
17
#include <Jolt/Core/UnorderedSet.h>
18
#include <Jolt/Core/StreamUtils.h>
19
#include <Jolt/ObjectStream/SerializableObject.h>
20
21
JPH_NAMESPACE_BEGIN
22
23
struct RayCast;
24
class RayCastSettings;
25
struct ShapeCast;
26
class ShapeCastSettings;
27
class RayCastResult;
28
class ShapeCastResult;
29
class CollidePointResult;
30
class CollideShapeResult;
31
class SubShapeIDCreator;
32
class SubShapeID;
33
class PhysicsMaterial;
34
class TransformedShape;
35
class Plane;
36
class CollideSoftBodyVertexIterator;
37
class Shape;
38
class StreamOut;
39
class StreamIn;
40
#ifdef JPH_DEBUG_RENDERER
41
class DebugRenderer;
42
#endif // JPH_DEBUG_RENDERER
43
44
using CastRayCollector = CollisionCollector<RayCastResult, CollisionCollectorTraitsCastRay>;
45
using CastShapeCollector = CollisionCollector<ShapeCastResult, CollisionCollectorTraitsCastShape>;
46
using CollidePointCollector = CollisionCollector<CollidePointResult, CollisionCollectorTraitsCollidePoint>;
47
using CollideShapeCollector = CollisionCollector<CollideShapeResult, CollisionCollectorTraitsCollideShape>;
48
using TransformedShapeCollector = CollisionCollector<TransformedShape, CollisionCollectorTraitsCollideShape>;
49
50
using ShapeRefC = RefConst<Shape>;
51
using ShapeList = Array<ShapeRefC>;
52
using PhysicsMaterialRefC = RefConst<PhysicsMaterial>;
53
using PhysicsMaterialList = Array<PhysicsMaterialRefC>;
54
55
/// Shapes are categorized in groups, each shape can return which group it belongs to through its Shape::GetType function.
56
enum class EShapeType : uint8
57
{
58
Convex, ///< Used by ConvexShape, all shapes that use the generic convex vs convex collision detection system (box, sphere, capsule, tapered capsule, cylinder, triangle)
59
Compound, ///< Used by CompoundShape
60
Decorated, ///< Used by DecoratedShape
61
Mesh, ///< Used by MeshShape
62
HeightField, ///< Used by HeightFieldShape
63
SoftBody, ///< Used by SoftBodyShape
64
65
// User defined shapes
66
User1,
67
User2,
68
User3,
69
User4,
70
71
Plane, ///< Used by PlaneShape
72
Empty, ///< Used by EmptyShape
73
};
74
75
/// This enumerates all shape types, each shape can return its type through Shape::GetSubType
76
enum class EShapeSubType : uint8
77
{
78
// Convex shapes
79
Sphere,
80
Box,
81
Triangle,
82
Capsule,
83
TaperedCapsule,
84
Cylinder,
85
ConvexHull,
86
87
// Compound shapes
88
StaticCompound,
89
MutableCompound,
90
91
// Decorated shapes
92
RotatedTranslated,
93
Scaled,
94
OffsetCenterOfMass,
95
96
// Other shapes
97
Mesh,
98
HeightField,
99
SoftBody,
100
101
// User defined shapes
102
User1,
103
User2,
104
User3,
105
User4,
106
User5,
107
User6,
108
User7,
109
User8,
110
111
// User defined convex shapes
112
UserConvex1,
113
UserConvex2,
114
UserConvex3,
115
UserConvex4,
116
UserConvex5,
117
UserConvex6,
118
UserConvex7,
119
UserConvex8,
120
121
// Other shapes
122
Plane,
123
TaperedCylinder,
124
Empty,
125
};
126
127
// Sets of shape sub types
128
static constexpr EShapeSubType sAllSubShapeTypes[] = { EShapeSubType::Sphere, EShapeSubType::Box, EShapeSubType::Triangle, EShapeSubType::Capsule, EShapeSubType::TaperedCapsule, EShapeSubType::Cylinder, EShapeSubType::ConvexHull, EShapeSubType::StaticCompound, EShapeSubType::MutableCompound, EShapeSubType::RotatedTranslated, EShapeSubType::Scaled, EShapeSubType::OffsetCenterOfMass, EShapeSubType::Mesh, EShapeSubType::HeightField, EShapeSubType::SoftBody, EShapeSubType::User1, EShapeSubType::User2, EShapeSubType::User3, EShapeSubType::User4, EShapeSubType::User5, EShapeSubType::User6, EShapeSubType::User7, EShapeSubType::User8, EShapeSubType::UserConvex1, EShapeSubType::UserConvex2, EShapeSubType::UserConvex3, EShapeSubType::UserConvex4, EShapeSubType::UserConvex5, EShapeSubType::UserConvex6, EShapeSubType::UserConvex7, EShapeSubType::UserConvex8, EShapeSubType::Plane, EShapeSubType::TaperedCylinder, EShapeSubType::Empty };
129
static constexpr EShapeSubType sConvexSubShapeTypes[] = { EShapeSubType::Sphere, EShapeSubType::Box, EShapeSubType::Triangle, EShapeSubType::Capsule, EShapeSubType::TaperedCapsule, EShapeSubType::Cylinder, EShapeSubType::ConvexHull, EShapeSubType::TaperedCylinder, EShapeSubType::UserConvex1, EShapeSubType::UserConvex2, EShapeSubType::UserConvex3, EShapeSubType::UserConvex4, EShapeSubType::UserConvex5, EShapeSubType::UserConvex6, EShapeSubType::UserConvex7, EShapeSubType::UserConvex8 };
130
static constexpr EShapeSubType sCompoundSubShapeTypes[] = { EShapeSubType::StaticCompound, EShapeSubType::MutableCompound };
131
static constexpr EShapeSubType sDecoratorSubShapeTypes[] = { EShapeSubType::RotatedTranslated, EShapeSubType::Scaled, EShapeSubType::OffsetCenterOfMass };
132
133
/// How many shape types we support
134
static constexpr uint NumSubShapeTypes = uint(std::size(sAllSubShapeTypes));
135
136
/// Names of sub shape types
137
static constexpr const char *sSubShapeTypeNames[] = { "Sphere", "Box", "Triangle", "Capsule", "TaperedCapsule", "Cylinder", "ConvexHull", "StaticCompound", "MutableCompound", "RotatedTranslated", "Scaled", "OffsetCenterOfMass", "Mesh", "HeightField", "SoftBody", "User1", "User2", "User3", "User4", "User5", "User6", "User7", "User8", "UserConvex1", "UserConvex2", "UserConvex3", "UserConvex4", "UserConvex5", "UserConvex6", "UserConvex7", "UserConvex8", "Plane", "TaperedCylinder", "Empty" };
138
static_assert(std::size(sSubShapeTypeNames) == NumSubShapeTypes);
139
140
/// Class that can construct shapes and that is serializable using the ObjectStream system.
141
/// Can be used to store shape data in 'uncooked' form (i.e. in a form that is still human readable and authorable).
142
/// Once the shape has been created using the Create() function, the data will be moved into the Shape class
143
/// in a form that is optimized for collision detection. After this, the ShapeSettings object is no longer needed
144
/// and can be destroyed. Each shape class has a derived class of the ShapeSettings object to store shape specific
145
/// data.
146
class JPH_EXPORT ShapeSettings : public SerializableObject, public RefTarget<ShapeSettings>
147
{
148
JPH_DECLARE_SERIALIZABLE_ABSTRACT(JPH_EXPORT, ShapeSettings)
149
150
public:
151
using ShapeResult = Result<Ref<Shape>>;
152
153
/// Create a shape according to the settings specified by this object.
154
virtual ShapeResult Create() const = 0;
155
156
/// When creating a shape, the result is cached so that calling Create() again will return the same shape.
157
/// If you make changes to the ShapeSettings you need to call this function to clear the cached result to allow Create() to build a new shape.
158
void ClearCachedResult() { mCachedResult.Clear(); }
159
160
/// User data (to be used freely by the application)
161
uint64 mUserData = 0;
162
163
protected:
164
mutable ShapeResult mCachedResult;
165
};
166
167
/// Function table for functions on shapes
168
class JPH_EXPORT ShapeFunctions
169
{
170
public:
171
/// Construct a shape
172
Shape * (*mConstruct)() = nullptr;
173
174
/// Color of the shape when drawing
175
Color mColor = Color::sBlack;
176
177
/// Get an entry in the registry for a particular sub type
178
static inline ShapeFunctions & sGet(EShapeSubType inSubType) { return sRegistry[int(inSubType)]; }
179
180
private:
181
static ShapeFunctions sRegistry[NumSubShapeTypes];
182
};
183
184
/// Base class for all shapes (collision volume of a body). Defines a virtual interface for collision detection.
185
class JPH_EXPORT Shape : public RefTarget<Shape>, public NonCopyable
186
{
187
public:
188
JPH_OVERRIDE_NEW_DELETE
189
190
using ShapeResult = ShapeSettings::ShapeResult;
191
192
/// Constructor
193
Shape(EShapeType inType, EShapeSubType inSubType) : mShapeType(inType), mShapeSubType(inSubType) { }
194
Shape(EShapeType inType, EShapeSubType inSubType, const ShapeSettings &inSettings, [[maybe_unused]] ShapeResult &outResult) : mUserData(inSettings.mUserData), mShapeType(inType), mShapeSubType(inSubType) { }
195
196
/// Destructor
197
virtual ~Shape() = default;
198
199
/// Get type
200
inline EShapeType GetType() const { return mShapeType; }
201
inline EShapeSubType GetSubType() const { return mShapeSubType; }
202
203
/// User data (to be used freely by the application)
204
uint64 GetUserData() const { return mUserData; }
205
void SetUserData(uint64 inUserData) { mUserData = inUserData; }
206
207
/// Check if this shape can only be used to create a static body or if it can also be dynamic/kinematic
208
virtual bool MustBeStatic() const { return false; }
209
210
/// All shapes are centered around their center of mass. This function returns the center of mass position that needs to be applied to transform the shape to where it was created.
211
virtual Vec3 GetCenterOfMass() const { return Vec3::sZero(); }
212
213
/// Get local bounding box including convex radius, this box is centered around the center of mass rather than the world transform
214
virtual AABox GetLocalBounds() const = 0;
215
216
/// Get the max number of sub shape ID bits that are needed to be able to address any leaf shape in this shape. Used mainly for checking that it is smaller or equal than SubShapeID::MaxBits.
217
virtual uint GetSubShapeIDBitsRecursive() const = 0;
218
219
/// Get world space bounds including convex radius.
220
/// This shape is scaled by inScale in local space first.
221
/// This function can be overridden to return a closer fitting world space bounding box, by default it will just transform what GetLocalBounds() returns.
222
virtual AABox GetWorldSpaceBounds(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale) const { return GetLocalBounds().Scaled(inScale).Transformed(inCenterOfMassTransform); }
223
224
/// Get world space bounds including convex radius.
225
AABox GetWorldSpaceBounds(DMat44Arg inCenterOfMassTransform, Vec3Arg inScale) const
226
{
227
// Use single precision version using the rotation only
228
AABox bounds = GetWorldSpaceBounds(inCenterOfMassTransform.GetRotation(), inScale);
229
230
// Apply translation
231
bounds.Translate(inCenterOfMassTransform.GetTranslation());
232
233
return bounds;
234
}
235
236
/// Returns the radius of the biggest sphere that fits entirely in the shape. In case this shape consists of multiple sub shapes, it returns the smallest sphere of the parts.
237
/// This can be used as a measure of how far the shape can be moved without risking going through geometry.
238
virtual float GetInnerRadius() const = 0;
239
240
/// Calculate the mass and inertia of this shape
241
virtual MassProperties GetMassProperties() const = 0;
242
243
/// Get the leaf shape for a particular sub shape ID.
244
/// @param inSubShapeID The full sub shape ID that indicates the path to the leaf shape
245
/// @param outRemainder What remains of the sub shape ID after removing the path to the leaf shape (could e.g. refer to a triangle within a MeshShape)
246
/// @return The shape or null if the sub shape ID is invalid
247
virtual const Shape * GetLeafShape([[maybe_unused]] const SubShapeID &inSubShapeID, SubShapeID &outRemainder) const;
248
249
/// Get the material assigned to a particular sub shape ID
250
virtual const PhysicsMaterial * GetMaterial(const SubShapeID &inSubShapeID) const = 0;
251
252
/// Get the surface normal of a particular sub shape ID and point on surface (all vectors are relative to center of mass for this shape).
253
/// Note: When you have a CollideShapeResult or ShapeCastResult you should use -mPenetrationAxis.Normalized() as contact normal as GetSurfaceNormal will only return face normals (and not vertex or edge normals).
254
virtual Vec3 GetSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inLocalSurfacePosition) const = 0;
255
256
/// Type definition for a supporting face
257
using SupportingFace = StaticArray<Vec3, 32>;
258
259
/// Get the vertices of the face that faces inDirection the most (includes any convex radius). Note that this function can only return faces of
260
/// convex shapes or triangles, which is why a sub shape ID to get to that leaf must be provided.
261
/// @param inSubShapeID Sub shape ID of target shape
262
/// @param inDirection Direction that the face should be facing (in local space to this shape)
263
/// @param inCenterOfMassTransform Transform to transform outVertices with
264
/// @param inScale Scale in local space of the shape (scales relative to its center of mass)
265
/// @param outVertices Resulting face. The returned face can be empty if the shape doesn't have polygons to return (e.g. because it's a sphere). The face will be returned in world space.
266
virtual void GetSupportingFace([[maybe_unused]] const SubShapeID &inSubShapeID, [[maybe_unused]] Vec3Arg inDirection, [[maybe_unused]] Vec3Arg inScale, [[maybe_unused]] Mat44Arg inCenterOfMassTransform, [[maybe_unused]] SupportingFace &outVertices) const { /* Nothing */ }
267
268
/// Get the user data of a particular sub shape ID. Corresponds with the value stored in Shape::GetUserData of the leaf shape pointed to by inSubShapeID.
269
virtual uint64 GetSubShapeUserData([[maybe_unused]] const SubShapeID &inSubShapeID) const { return mUserData; }
270
271
/// Get the direct child sub shape and its transform for a sub shape ID.
272
/// @param inSubShapeID Sub shape ID that indicates the path to the leaf shape
273
/// @param inPositionCOM The position of the center of mass of this shape
274
/// @param inRotation The orientation of this shape
275
/// @param inScale Scale in local space of the shape (scales relative to its center of mass)
276
/// @param outRemainder The remainder of the sub shape ID after removing the sub shape
277
/// @return Direct child sub shape and its transform, note that the body ID and sub shape ID will be invalid
278
virtual TransformedShape GetSubShapeTransformedShape(const SubShapeID &inSubShapeID, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, SubShapeID &outRemainder) const;
279
280
/// Gets the properties needed to do buoyancy calculations for a body using this shape
281
/// @param inCenterOfMassTransform Transform that takes this shape (centered around center of mass) to world space (or a desired other space)
282
/// @param inScale Scale in local space of the shape (scales relative to its center of mass)
283
/// @param inSurface The surface plane of the liquid relative to inCenterOfMassTransform
284
/// @param outTotalVolume On return this contains the total volume of the shape
285
/// @param outSubmergedVolume On return this contains the submerged volume of the shape
286
/// @param outCenterOfBuoyancy On return this contains the world space center of mass of the submerged volume
287
#ifdef JPH_DEBUG_RENDERER
288
/// @param inBaseOffset The offset to transform inCenterOfMassTransform to world space (in double precision mode this can be used to shift the whole operation closer to the origin). Only used for debug drawing.
289
#endif
290
virtual void GetSubmergedVolume(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const Plane &inSurface, float &outTotalVolume, float &outSubmergedVolume, Vec3 &outCenterOfBuoyancy
291
#ifdef JPH_DEBUG_RENDERER // Not using JPH_IF_DEBUG_RENDERER for Doxygen
292
, RVec3Arg inBaseOffset
293
#endif
294
) const = 0;
295
296
#ifdef JPH_DEBUG_RENDERER
297
/// Draw the shape at a particular location with a particular color (debugging purposes)
298
virtual void Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const = 0;
299
300
/// Draw the results of the GetSupportFunction with the convex radius added back on to show any errors introduced by this process (only relevant for convex shapes)
301
virtual void DrawGetSupportFunction([[maybe_unused]] DebugRenderer *inRenderer, [[maybe_unused]] RMat44Arg inCenterOfMassTransform, [[maybe_unused]] Vec3Arg inScale, [[maybe_unused]] ColorArg inColor, [[maybe_unused]] bool inDrawSupportDirection) const { /* Only implemented for convex shapes */ }
302
303
/// Draw the results of the GetSupportingFace function to show any errors introduced by this process (only relevant for convex shapes)
304
virtual void DrawGetSupportingFace([[maybe_unused]] DebugRenderer *inRenderer, [[maybe_unused]] RMat44Arg inCenterOfMassTransform, [[maybe_unused]] Vec3Arg inScale) const { /* Only implemented for convex shapes */ }
305
#endif // JPH_DEBUG_RENDERER
306
307
/// Cast a ray against this shape, returns true if it finds a hit closer than ioHit.mFraction and updates that fraction. Otherwise ioHit is left untouched and the function returns false.
308
/// Note that the ray should be relative to the center of mass of this shape (i.e. subtract Shape::GetCenterOfMass() from RayCast::mOrigin if you want to cast against the shape in the space it was created).
309
/// Convex objects will be treated as solid (meaning if the ray starts inside, you'll get a hit fraction of 0) and back face hits against triangles are returned.
310
/// If you want the surface normal of the hit use GetSurfaceNormal(ioHit.mSubShapeID2, inRay.GetPointOnRay(ioHit.mFraction)).
311
virtual bool CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const = 0;
312
313
/// Cast a ray against this shape. Allows returning multiple hits through ioCollector. Note that this version is more flexible but also slightly slower than the CastRay function that returns only a single hit.
314
/// If you want the surface normal of the hit use GetSurfaceNormal(collected sub shape ID, inRay.GetPointOnRay(collected faction)).
315
virtual void CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter = { }) const = 0;
316
317
/// Check if inPoint is inside this shape. For this tests all shapes are treated as if they were solid.
318
/// Note that inPoint should be relative to the center of mass of this shape (i.e. subtract Shape::GetCenterOfMass() from inPoint if you want to test against the shape in the space it was created).
319
/// For a mesh shape, this test will only provide sensible information if the mesh is a closed manifold.
320
/// For each shape that collides, ioCollector will receive a hit.
321
virtual void CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter = { }) const = 0;
322
323
/// Collides all vertices of a soft body with this shape and updates SoftBodyVertex::mCollisionPlane, SoftBodyVertex::mCollidingShapeIndex and SoftBodyVertex::mLargestPenetration if a collision with more penetration was found.
324
/// @param inCenterOfMassTransform Center of mass transform for this shape relative to the vertices.
325
/// @param inScale Scale in local space of the shape (scales relative to its center of mass)
326
/// @param inVertices The vertices of the soft body
327
/// @param inNumVertices The number of vertices in inVertices
328
/// @param inCollidingShapeIndex Value to store in CollideSoftBodyVertexIterator::mCollidingShapeIndex when a collision was found
329
virtual void CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const CollideSoftBodyVertexIterator &inVertices, uint inNumVertices, int inCollidingShapeIndex) const = 0;
330
331
/// Collect the leaf transformed shapes of all leaf shapes of this shape.
332
/// inBox is the world space axis aligned box which leaf shapes should collide with.
333
/// inPositionCOM/inRotation/inScale describes the transform of this shape.
334
/// inSubShapeIDCreator represents the current sub shape ID of this shape.
335
virtual void CollectTransformedShapes(const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) const;
336
337
/// Transforms this shape and all of its children with inTransform, resulting shape(s) are passed to ioCollector.
338
/// Note that not all shapes support all transforms (especially true for scaling), the resulting shape will try to match the transform as accurately as possible.
339
/// @param inCenterOfMassTransform The transform (rotation, translation, scale) that the center of mass of the shape should get
340
/// @param ioCollector The transformed shapes will be passed to this collector
341
virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const;
342
343
/// Scale this shape. Note that not all shapes support all scales, this will return a shape that matches the scale as accurately as possible. See Shape::IsValidScale for more information.
344
/// @param inScale The scale to use for this shape (note: this scale is applied to the entire shape in the space it was created, most other functions apply the scale in the space of the leaf shapes and from the center of mass!)
345
ShapeResult ScaleShape(Vec3Arg inScale) const;
346
347
/// An opaque buffer that holds shape specific information during GetTrianglesStart/Next.
348
struct alignas(16) GetTrianglesContext { uint8 mData[4288]; };
349
350
/// This is the minimum amount of triangles that should be requested through GetTrianglesNext.
351
static constexpr int cGetTrianglesMinTrianglesRequested = 32;
352
353
/// To start iterating over triangles, call this function first.
354
/// ioContext is a temporary buffer and should remain untouched until the last call to GetTrianglesNext.
355
/// inBox is the world space bounding in which you want to get the triangles.
356
/// inPositionCOM/inRotation/inScale describes the transform of this shape.
357
/// To get the actual triangles call GetTrianglesNext.
358
virtual void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const = 0;
359
360
/// Call this repeatedly to get all triangles in the box.
361
/// outTriangleVertices should be large enough to hold 3 * inMaxTriangleRequested entries.
362
/// outMaterials (if it is not null) should contain inMaxTrianglesRequested entries.
363
/// The function returns the amount of triangles that it found (which will be <= inMaxTrianglesRequested), or 0 if there are no more triangles.
364
/// Note that the function can return a value < inMaxTrianglesRequested and still have more triangles to process (triangles can be returned in blocks).
365
/// Note that the function may return triangles outside of the requested box, only coarse culling is performed on the returned triangles.
366
virtual int GetTrianglesNext(GetTrianglesContext &ioContext, int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials = nullptr) const = 0;
367
368
///@name Binary serialization of the shape. Note that this saves the 'cooked' shape in a format which will not be backwards compatible for newer library versions.
369
/// In this case you need to recreate the shape from the ShapeSettings object and save it again. The user is expected to call SaveBinaryState followed by SaveMaterialState and SaveSubShapeState.
370
/// The stream should be stored as is and the material and shape list should be saved using the applications own serialization system (e.g. by assigning an ID to each pointer).
371
/// When restoring data, call sRestoreFromBinaryState to get the shape and then call RestoreMaterialState and RestoreSubShapeState to restore the pointers to the external objects.
372
/// Alternatively you can use SaveWithChildren and sRestoreWithChildren to save and restore the shape and all its child shapes and materials in a single stream.
373
///@{
374
375
/// Saves the contents of the shape in binary form to inStream.
376
virtual void SaveBinaryState(StreamOut &inStream) const;
377
378
/// Creates a Shape of the correct type and restores its contents from the binary stream inStream.
379
static ShapeResult sRestoreFromBinaryState(StreamIn &inStream);
380
381
/// Outputs the material references that this shape has to outMaterials.
382
virtual void SaveMaterialState([[maybe_unused]] PhysicsMaterialList &outMaterials) const { /* By default do nothing */ }
383
384
/// Restore the material references after calling sRestoreFromBinaryState. Note that the exact same materials need to be provided in the same order as returned by SaveMaterialState.
385
virtual void RestoreMaterialState([[maybe_unused]] const PhysicsMaterialRefC *inMaterials, [[maybe_unused]] uint inNumMaterials) { JPH_ASSERT(inNumMaterials == 0); }
386
387
/// Outputs the shape references that this shape has to outSubShapes.
388
virtual void SaveSubShapeState([[maybe_unused]] ShapeList &outSubShapes) const { /* By default do nothing */ }
389
390
/// Restore the shape references after calling sRestoreFromBinaryState. Note that the exact same shapes need to be provided in the same order as returned by SaveSubShapeState.
391
virtual void RestoreSubShapeState([[maybe_unused]] const ShapeRefC *inSubShapes, [[maybe_unused]] uint inNumShapes) { JPH_ASSERT(inNumShapes == 0); }
392
393
using ShapeToIDMap = StreamUtils::ObjectToIDMap<Shape>;
394
using IDToShapeMap = StreamUtils::IDToObjectMap<Shape>;
395
using MaterialToIDMap = StreamUtils::ObjectToIDMap<PhysicsMaterial>;
396
using IDToMaterialMap = StreamUtils::IDToObjectMap<PhysicsMaterial>;
397
398
/// Save this shape, all its children and its materials. Pass in an empty map in ioShapeMap / ioMaterialMap or reuse the same map while saving multiple shapes to the same stream in order to avoid writing duplicates.
399
void SaveWithChildren(StreamOut &inStream, ShapeToIDMap &ioShapeMap, MaterialToIDMap &ioMaterialMap) const;
400
401
/// Restore a shape, all its children and materials. Pass in an empty map in ioShapeMap / ioMaterialMap or reuse the same map while reading multiple shapes from the same stream in order to restore duplicates.
402
static ShapeResult sRestoreWithChildren(StreamIn &inStream, IDToShapeMap &ioShapeMap, IDToMaterialMap &ioMaterialMap);
403
404
///@}
405
406
/// Class that holds information about the shape that can be used for logging / data collection purposes
407
struct Stats
408
{
409
Stats(size_t inSizeBytes, uint inNumTriangles) : mSizeBytes(inSizeBytes), mNumTriangles(inNumTriangles) { }
410
411
size_t mSizeBytes; ///< Amount of memory used by this shape (size in bytes)
412
uint mNumTriangles; ///< Number of triangles in this shape (when applicable)
413
};
414
415
/// Get stats of this shape. Use for logging / data collection purposes only. Does not add values from child shapes, use GetStatsRecursive for this.
416
virtual Stats GetStats() const = 0;
417
418
using VisitedShapes = UnorderedSet<const Shape *>;
419
420
/// Get the combined stats of this shape and its children.
421
/// @param ioVisitedShapes is used to track which shapes have already been visited, to avoid calculating the wrong memory size.
422
virtual Stats GetStatsRecursive(VisitedShapes &ioVisitedShapes) const;
423
424
///< Volume of this shape (m^3). Note that for compound shapes the volume may be incorrect since child shapes can overlap which is not accounted for.
425
virtual float GetVolume() const = 0;
426
427
/// Test if inScale is a valid scale for this shape. Some shapes can only be scaled uniformly, compound shapes cannot handle shapes
428
/// being rotated and scaled (this would cause shearing), scale can never be zero. When the scale is invalid, the function will return false.
429
///
430
/// Here's a list of supported scales:
431
/// * SphereShape: Scale must be uniform (signs of scale are ignored).
432
/// * BoxShape: Any scale supported (signs of scale are ignored).
433
/// * TriangleShape: Any scale supported when convex radius is zero, otherwise only uniform scale supported.
434
/// * CapsuleShape: Scale must be uniform (signs of scale are ignored).
435
/// * TaperedCapsuleShape: Scale must be uniform (sign of Y scale can be used to flip the capsule).
436
/// * CylinderShape: Scale must be uniform in XZ plane, Y can scale independently (signs of scale are ignored).
437
/// * RotatedTranslatedShape: Scale must not cause shear in the child shape.
438
/// * CompoundShape: Scale must not cause shear in any of the child shapes.
439
virtual bool IsValidScale(Vec3Arg inScale) const;
440
441
/// This function will make sure that if you wrap this shape in a ScaledShape that the scale is valid.
442
/// Note that this involves discarding components of the scale that are invalid, so the resulting scaled shape may be different than the requested scale.
443
/// Compare the return value of this function with the scale you passed in to detect major inconsistencies and possibly warn the user.
444
/// @param inScale Local space scale for this shape.
445
/// @return Scale that can be used to wrap this shape in a ScaledShape. IsValidScale will return true for this scale.
446
virtual Vec3 MakeScaleValid(Vec3Arg inScale) const;
447
448
#ifdef JPH_DEBUG_RENDERER
449
/// Debug helper which draws the intersection between water and the shapes, the center of buoyancy and the submerged volume
450
static bool sDrawSubmergedVolumes;
451
#endif // JPH_DEBUG_RENDERER
452
453
protected:
454
/// This function should not be called directly, it is used by sRestoreFromBinaryState.
455
virtual void RestoreBinaryState(StreamIn &inStream);
456
457
/// A fallback version of CollidePoint that uses a ray cast and counts the number of hits to determine if the point is inside the shape. Odd number of hits means inside, even number of hits means outside.
458
static void sCollidePointUsingRayCast(const Shape &inShape, Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter);
459
460
private:
461
uint64 mUserData = 0;
462
EShapeType mShapeType;
463
EShapeSubType mShapeSubType;
464
};
465
466
JPH_NAMESPACE_END
467
468