diff --git a/src/player/grab_rotation.c b/src/player/grab_rotation.c new file mode 100644 index 00000000..e459eaeb --- /dev/null +++ b/src/player/grab_rotation.c @@ -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); +} diff --git a/src/player/grab_rotation.h b/src/player/grab_rotation.h new file mode 100644 index 00000000..7d43bcdd --- /dev/null +++ b/src/player/grab_rotation.h @@ -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 diff --git a/src/player/player.c b/src/player/player.c index 44015dca..31f8667e 100644 --- a/src/player/player.c +++ b/src/player/player.c @@ -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); } }