Shape fixes;

- Collider always has Shape now.  When left off or set to null, it's a
  tiny sphere (representing a point).
- Preserve shape offset when changing shape.
This commit is contained in:
bjorn 2024-04-05 18:40:23 -07:00
parent f82715d402
commit 24708f7114
1 changed files with 46 additions and 30 deletions

View File

@ -43,6 +43,7 @@ struct Joint {
static struct { static struct {
bool initialized; bool initialized;
Shape* pointShape;
JPH_Shape* queryBox; JPH_Shape* queryBox;
JPH_Shape* querySphere; JPH_Shape* querySphere;
JPH_AllHit_CastShapeCollector* castShapeCollector; JPH_AllHit_CastShapeCollector* castShapeCollector;
@ -69,14 +70,16 @@ static uint32_t findTag(World* world, const char* name) {
bool lovrPhysicsInit(void) { bool lovrPhysicsInit(void) {
if (state.initialized) return false; if (state.initialized) return false;
JPH_Init(32 * 1024 * 1024); JPH_Init(32 * 1024 * 1024);
state.castShapeCollector = JPH_AllHit_CastShapeCollector_Create(); state.pointShape = lovrSphereShapeCreate(FLT_EPSILON);
state.querySphere = (JPH_Shape*) JPH_SphereShape_Create(1.f); state.querySphere = (JPH_Shape*) JPH_SphereShape_Create(1.f);
state.queryBox = (JPH_Shape*) JPH_BoxShape_Create(&(const JPH_Vec3) { .5, .5f, .5f }, 0.f); state.queryBox = (JPH_Shape*) JPH_BoxShape_Create(&(const JPH_Vec3) { .5, .5f, .5f }, 0.f);
state.castShapeCollector = JPH_AllHit_CastShapeCollector_Create();
return state.initialized = true; return state.initialized = true;
} }
void lovrPhysicsDestroy(void) { void lovrPhysicsDestroy(void) {
if (!state.initialized) return; if (!state.initialized) return;
lovrRelease(state.pointShape, lovrShapeDestroy);
JPH_Shutdown(); JPH_Shutdown();
state.initialized = false; state.initialized = false;
} }
@ -320,23 +323,26 @@ Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float
uint32_t limit = JPH_PhysicsSystem_GetMaxBodies(world->system); uint32_t limit = JPH_PhysicsSystem_GetMaxBodies(world->system);
lovrCheck(count < limit, "Too many colliders!"); lovrCheck(count < limit, "Too many colliders!");
if (!shape) shape = state.pointShape;
Collider* collider = lovrCalloc(sizeof(Collider)); Collider* collider = lovrCalloc(sizeof(Collider));
collider->ref = 1; collider->ref = 1;
collider->world = world; collider->world = world;
collider->shape = shape;
collider->tag = UNTAGGED; collider->tag = UNTAGGED;
JPH_MotionType motionType = JPH_MotionType_Dynamic;
JPH_ObjectLayer objectLayer = UNTAGGED * 2 + 1;
const JPH_RVec3 position = { x, y, z }; const JPH_RVec3 position = { x, y, z };
const JPH_Quat rotation = { 0.f, 0.f, 0.f, 1.f }; const JPH_Quat rotation = { 0.f, 0.f, 0.f, 1.f };
// todo: a placeholder querySphere shape is used in collider, then replaced in lovrColliderAddShape JPH_MotionType type = JPH_MotionType_Dynamic;
JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3( JPH_ObjectLayer objectLayer = UNTAGGED * 2 + 1;
shape ? shape->shape : state.querySphere, &position, &rotation, motionType, objectLayer); JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3(shape->shape, &position, &rotation, type, objectLayer);
collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings); collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings);
JPH_BodyCreationSettings_Destroy(settings);
collider->id = JPH_Body_GetID(collider->body); collider->id = JPH_Body_GetID(collider->body);
JPH_BodyCreationSettings_Destroy(settings);
JPH_BodyInterface_AddBody(world->bodies, collider->id, JPH_Activation_Activate); JPH_BodyInterface_AddBody(world->bodies, collider->id, JPH_Activation_Activate);
JPH_BodyInterface_SetUserData(world->bodies, collider->id, (uint64_t) collider); JPH_BodyInterface_SetUserData(world->bodies, collider->id, (uint64_t) collider);
lovrColliderSetLinearDamping(collider, world->defaultLinearDamping, 0.f); lovrColliderSetLinearDamping(collider, world->defaultLinearDamping, 0.f);
lovrColliderSetAngularDamping(collider, world->defaultAngularDamping, 0.f); lovrColliderSetAngularDamping(collider, world->defaultAngularDamping, 0.f);
lovrColliderSetSleepingAllowed(collider, world->defaultIsSleepingAllowed); lovrColliderSetSleepingAllowed(collider, world->defaultIsSleepingAllowed);
@ -352,8 +358,8 @@ Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float
world->head = collider; world->head = collider;
} }
// The world owns a reference to the collider lovrRetain(collider->shape);
lovrRetain(collider); lovrRetain(collider); // The world owns a reference to the collider
return collider; return collider;
} }
@ -406,22 +412,35 @@ Collider* lovrColliderGetNext(Collider* collider) {
} }
Shape* lovrColliderGetShape(Collider* collider) { Shape* lovrColliderGetShape(Collider* collider) {
return collider->shape; return collider->shape == state.pointShape ? NULL : collider->shape;
} }
void lovrColliderSetShape(Collider* collider, Shape* shape) { void lovrColliderSetShape(Collider* collider, Shape* shape) {
if (shape != collider->shape) { shape = shape ? shape : state.pointShape;
lovrRelease(collider->shape, lovrShapeDestroy);
collider->shape = shape;
lovrRetain(shape);
bool updateMass = true; if (shape == collider->shape) {
if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) { return;
lovrColliderSetKinematic(collider, true); }
updateMass = false;
}
JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, updateMass, JPH_Activation_Activate); float position[3], orientation[4];
const JPH_Shape* parent = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id);
bool hasOffset = JPH_Shape_GetSubType(parent) == JPH_ShapeSubType_RotatedTranslated;
if (hasOffset) lovrColliderGetShapeOffset(collider, position, orientation);
lovrRelease(collider->shape, lovrShapeDestroy);
collider->shape = shape;
lovrRetain(shape);
bool updateMass = true;
if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) {
lovrColliderSetKinematic(collider, true);
updateMass = false;
}
JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, updateMass, JPH_Activation_Activate);
if (hasOffset) {
lovrColliderSetShapeOffset(collider, position, orientation);
} }
} }
@ -451,7 +470,7 @@ void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orie
JPH_Vec3 jposition = { position[0], position[1], position[2] }; JPH_Vec3 jposition = { position[0], position[1], position[2] };
JPH_Quat jrotation = { orientation[0], orientation[1], orientation[2], orientation[3] }; JPH_Quat jrotation = { orientation[0], orientation[1], orientation[2], orientation[3] };
shape = (JPH_Shape*) JPH_RotatedTranslatedShape_Create(&jposition, &jrotation, collider->shape->shape); shape = (JPH_Shape*) JPH_RotatedTranslatedShape_Create(&jposition, &jrotation, collider->shape->shape);
bool updateMass = collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN; bool updateMass = collider->shape && (collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN);
JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape, updateMass, JPH_Activation_Activate); JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape, updateMass, JPH_Activation_Activate);
} }
@ -557,20 +576,17 @@ void lovrColliderSetAwake(Collider* collider, bool awake) {
} }
float lovrColliderGetMass(Collider* collider) { float lovrColliderGetMass(Collider* collider) {
if (!collider->shape) return 0.f;
JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body);
return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties); return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties);
} }
void lovrColliderSetMass(Collider* collider, float mass) { void lovrColliderSetMass(Collider* collider, float mass) {
if (collider->shape) { JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body);
JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); Shape* shape = collider->shape;
Shape* shape = collider->shape; JPH_MassProperties* massProperties;
JPH_MassProperties* massProperties; JPH_Shape_GetMassProperties(shape->shape, massProperties);
JPH_Shape_GetMassProperties(shape->shape, massProperties); JPH_MassProperties_ScaleToMass(massProperties, mass);
JPH_MassProperties_ScaleToMass(massProperties, mass); JPH_MotionProperties_SetMassProperties(motionProperties, JPH_AllowedDOFs_All, massProperties);
JPH_MotionProperties_SetMassProperties(motionProperties, JPH_AllowedDOFs_All, massProperties);
}
} }
void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]) { void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {