Grab rotation flags (#58)

* introduced "enum GrabRotationFlags" for type-based grab behavior and added grab_rotation.c/.h to offload grabRotation code from player.c

* grab_rotation snap cube normals fix

* grab_rotation: some cleanup

* grab_rotation.c: simplify grabRotationInitBase + some cleanup
This commit is contained in:
Deconimus 2024-04-23 00:44:18 +02:00 committed by GitHub
parent 86915350b8
commit 247e66fb62
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 138 additions and 42 deletions

101
src/player/grab_rotation.c Normal file
View file

@ -0,0 +1,101 @@
#include "grab_rotation.h"
#include "../player/player.h"
struct Vector3 gCubeSurfaceNormals[6] = {
{ 1.0f, 0.0f, 0.0f },
{ -1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, -1.0f }
};
enum GrabRotationFlags grabRotationFlagsForDecorId(const int decorId) {
enum GrabRotationFlags flags = 0;
// object specific flags
if (decorId == DECOR_TYPE_RADIO) {
flags |= GrabRotationTurnTowardsPlayer | GrabRotationUseZLookDirection;
}
else // default flags
{
flags |= GrabRotationSnapToCubeNormals;
}
return flags;
}
enum GrabRotationFlags grabRotationFlagsForDecorObjectDef(struct DecorObjectDefinition* decorObjectDef) {
return grabRotationFlagsForDecorId(decorIdForObjectDefinition(decorObjectDef));
}
enum GrabRotationFlags grabRotationFlagsForCollisionObject(struct CollisionObject* collisionObject) {
return grabRotationFlagsForDecorId(decorIdForCollisionObject(collisionObject)); // this will probably need to be replaced in the future
}
void grabRotationApplyTurnTowardsPlayer(struct Quaternion* grabRotationBaseOut) {
quatIdent(grabRotationBaseOut);
}
void grabRotationApplySnapToCubeNormals(struct Quaternion* forwardRotationIn, struct Quaternion* objectRotationIn, struct Quaternion* grabRotationBaseOut) {
struct Vector3 forward, up;
quatMultVector(forwardRotationIn, &gForward, &forward);
quatMultVector(forwardRotationIn, &gUp, &up);
int closestNormalTowards = 0, closestNormalUp = 0;
float closestNormalTowardsDot = 1.0f, closestNormalUpDot = -1.0f;
for (int i = 0; i < 6; ++i) {
struct Vector3 surfaceNormal;
quatMultVector(objectRotationIn, &gCubeSurfaceNormals[i], &surfaceNormal);
float dot = vector3Dot(&surfaceNormal, &forward);
if (dot < closestNormalTowardsDot) {
closestNormalTowardsDot = dot;
closestNormalTowards = i;
}
dot = vector3Dot(&surfaceNormal, &up);
if (dot > closestNormalUpDot) {
closestNormalUpDot = dot;
closestNormalUp = i;
}
}
struct Quaternion normalRotation;
quatLook(&gCubeSurfaceNormals[closestNormalTowards], &gCubeSurfaceNormals[closestNormalUp], &normalRotation);
quatConjugate(&normalRotation, grabRotationBaseOut);
}
void grabRotationApplyNoRotation(struct Quaternion* forwardRotationIn, struct Quaternion* objectRotationIn, struct Quaternion* grabRotationBaseOut) {
struct Quaternion forwardRotationInverted;
quatConjugate(forwardRotationIn, &forwardRotationInverted);
quatMultiply(&forwardRotationInverted, objectRotationIn, grabRotationBaseOut);
}
void grabRotationInitBase(const enum GrabRotationFlags flags, struct Quaternion* forwardRotationIn, struct Quaternion* objectRotationIn, struct Quaternion* grabRotationBaseOut) {
// modify object rotation according to flags
if (flags & GrabRotationTurnTowardsPlayer) {
grabRotationApplyTurnTowardsPlayer(grabRotationBaseOut);
} else if (flags & GrabRotationSnapToCubeNormals) {
grabRotationApplySnapToCubeNormals(forwardRotationIn, objectRotationIn, grabRotationBaseOut);
} else { // with no rotation modifier, object is not rotated on grab
grabRotationApplyNoRotation(forwardRotationIn, objectRotationIn, grabRotationBaseOut);
}
}
void grabRotationApplyUseZLookDirection(struct Quaternion* lookRotationDeltaIn, struct Quaternion* grabRotationBaseInOut) {
struct Quaternion tmp;
quatMultiply(lookRotationDeltaIn, grabRotationBaseInOut, &tmp);
*grabRotationBaseInOut = tmp;
}
void grabRotationUpdate(const enum GrabRotationFlags flags, struct Quaternion* lookRotationDeltaIn, struct Quaternion* forwardRotationIn, struct Quaternion* grabRotationBaseIn, struct Quaternion* grabRotationOut) {
// modify target object rotation in object-space
struct Quaternion grabRotationBase = *grabRotationBaseIn;
if (flags & GrabRotationUseZLookDirection) {
grabRotationApplyUseZLookDirection(lookRotationDeltaIn, &grabRotationBase);
}
// maintain object's relative rotation
quatMultiply(forwardRotationIn, &grabRotationBase, grabRotationOut);
}

View file

@ -0,0 +1,21 @@
#ifndef __GRAB_ROTATION_H__
#define __GRAB_ROTATION_H__
#include "../decor/decor_object_list.h"
#include "../physics/collision_object.h"
#include "../math/transform.h"
enum GrabRotationFlags {
GrabRotationSnapToCubeNormals = (1 << 0),
GrabRotationTurnTowardsPlayer = (1 << 1),
GrabRotationUseZLookDirection = (1 << 2),
};
enum GrabRotationFlags grabRotationFlagsForDecorId(const int decorId);
enum GrabRotationFlags grabRotationFlagsForDecorObjectDef(struct DecorObjectDefinition* decorObjectDef);
enum GrabRotationFlags grabRotationFlagsForCollisionObject(struct CollisionObject* collisionObject);
void grabRotationInitBase(const enum GrabRotationFlags flags, struct Quaternion* forwardRotationIn, struct Quaternion* objectRotationIn, struct Quaternion* grabRotationBaseOut);
void grabRotationUpdate(const enum GrabRotationFlags flags, struct Quaternion* lookRotationDeltaIn, struct Quaternion* forwardRotationIn, struct Quaternion* grabRotationBaseIn, struct Quaternion* grabRotationOut);
#endif

View file

@ -17,14 +17,15 @@
#include "../physics/contact_insertion.h"
#include "../scene/ball.h"
#include "../savefile/savefile.h"
#include "../player/grab_rotation.h"
#include "../build/assets/models/player/chell.h"
#include "../build/assets/materials/static.h"
#include "../build/assets/models/portal_gun/w_portalgun.h"
#define GRAB_RAYCAST_DISTANCE 2.5f
#define GRAB_MIN_OFFSET_Y -1.1f
#define GRAB_MAX_OFFSET_Y 1.25f
#define GRAB_MIN_OFFSET_Y -1.1f
#define GRAB_MAX_OFFSET_Y 1.25f
#define DROWN_TIME 2.0f
#define STEP_TIME 0.35f
@ -79,15 +80,6 @@ struct ColliderTypeData gPlayerColliderData = {
&gCollisionCapsuleCallbacks,
};
struct Vector3 gCubeNormals[6] = {
{ 1.0f, 0.0f, 0.0f },
{ -1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, -1.0f }
};
void playerRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState) {
struct Player* player = (struct Player*)data;
@ -284,36 +276,14 @@ void playerInitGrabRotationBase(struct Player* player) {
return;
}
struct Quaternion forwardRotation = player->lookTransform.rotation;
struct Vector3 forward, tmpVec, up;
struct Vector3 forward, tmpVec;
playerGetMoveBasis(&forwardRotation, &forward, &tmpVec);
vector3Negate(&forward, &tmpVec);
quatLook(&tmpVec, &gUp, &forwardRotation);
vector3Negate(&forward, &forward);
quatLook(&forward, &gUp, &forwardRotation);
playerPortalGrabTransform(player, NULL, &forwardRotation);
quatMultVector(&forwardRotation, &gForward, &forward);
quatMultVector(&forwardRotation, &gUp, &up);
struct Quaternion objectRotation = player->grabConstraint.object->body->transform.rotation;
// snap target rotation to nearest cube normals
int closestNormalUp = 0, closestNormalTowards = 0;
float closestNormalTowardsDot = 1.0f, closestNormalUpDot = -1.0f;
for (int i = 0; i < 6; ++i) {
struct Vector3 surfaceNormal;
quatMultVector(&objectRotation, &gCubeNormals[i], &surfaceNormal);
float dot = vector3Dot(&surfaceNormal, &forward);
if (dot < closestNormalTowardsDot) {
closestNormalTowardsDot = dot;
closestNormalTowards = i;
}
dot = vector3Dot(&surfaceNormal, &up);
if (dot > closestNormalUpDot) {
closestNormalUpDot = dot;
closestNormalUp = i;
}
}
quatLook(&gCubeNormals[closestNormalTowards], &gCubeNormals[closestNormalUp], &objectRotation);
quatConjugate(&objectRotation, &player->grabRotationBase);
enum GrabRotationFlags grabRotationFlags = grabRotationFlagsForCollisionObject(player->grabConstraint.object);
grabRotationInitBase(grabRotationFlags, &forwardRotation, &player->grabConstraint.object->body->transform.rotation, &player->grabRotationBase);
}
void playerShakeUpdate(struct Player* player) {
@ -488,7 +458,10 @@ void playerUpdateGrabbedObject(struct Player* player) {
vector3Add(&player->lookTransform.position, &grabPoint, &grabPoint);
grabPoint.y += grabY;
struct Quaternion grabRotation;
// remember delta between forwardRotation and lookTransform.rotation
struct Quaternion lookRotationDelta, forwardRotationInv;
quatConjugate(&forwardRotation, &forwardRotationInv);
quatMultiply(&forwardRotationInv, &player->lookTransform.rotation, &lookRotationDelta);
if (player->grabbingThroughPortal != PLAYER_GRABBING_THROUGH_NOTHING) {
if (!collisionSceneIsPortalOpen()) {
@ -500,9 +473,10 @@ void playerUpdateGrabbedObject(struct Player* player) {
playerPortalGrabTransform(player, &grabPoint, &forwardRotation);
}
// maintain object's relative rotation
quatMultiply(&forwardRotation, &player->grabRotationBase, &grabRotation);
struct Quaternion grabRotation;
enum GrabRotationFlags grabRotationFlags = grabRotationFlagsForCollisionObject(player->grabConstraint.object);
grabRotationUpdate(grabRotationFlags, &lookRotationDelta, &forwardRotation, &player->grabRotationBase, &grabRotation);
pointConstraintUpdateTarget(&player->grabConstraint, &grabPoint, &grabRotation);
}
}