From 26db9cf10111273749cbede3ebd6e7f18a5b0467 Mon Sep 17 00:00:00 2001 From: James Lambert Date: Tue, 3 Jan 2023 22:12:25 -0700 Subject: [PATCH] Get animatable colliders working --- src/levels/level_definition.h | 11 ++++ src/levels/levels.c | 1 + src/scene/scene.c | 56 +++++++++++++++++-- src/scene/scene.h | 1 + src/scene/scene_animator.c | 15 +++++ src/scene/scene_animator.h | 2 + tools/export_level.lua | 3 + .../dynamic_collision_export.lua | 50 +++++++++++++++++ 8 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 tools/level_scripts/dynamic_collision_export.lua diff --git a/src/levels/level_definition.h b/src/levels/level_definition.h index 7415fcf..f4e57a9 100644 --- a/src/levels/level_definition.h +++ b/src/levels/level_definition.h @@ -9,6 +9,7 @@ #include "../math/range.h" #include "../sk64/skelatool_clip.h" #include "../sk64/skelatool_armature.h" +#include "../physics/collision_box.h" #define NO_TRANSFORM_INDEX 0xFF @@ -197,6 +198,14 @@ struct AnimationInfo { short clipCount; }; +struct DynamicBoxDefinition { + struct CollisionBox box; + struct Vector3 position; + struct Quaternion rotation; + short roomIndex; + short transformIndex; +}; + struct LevelDefinition { struct CollisionObject* collisionQuads; struct StaticContentElement *staticContent; @@ -221,6 +230,7 @@ struct LevelDefinition { struct BoxDropperDefinition* boxDroppers; struct AnimationInfo* animations; struct SwitchDefinition* switches; + struct DynamicBoxDefinition* dynamicBoxes; short collisionQuadCount; short staticContentCount; short portalSurfaceCount; @@ -238,6 +248,7 @@ struct LevelDefinition { short boxDropperCount; short animationInfoCount; short switchCount; + short dynamicBoxCount; short startLocation; }; diff --git a/src/levels/levels.c b/src/levels/levels.c index a29451a..c243882 100644 --- a/src/levels/levels.c +++ b/src/levels/levels.c @@ -83,6 +83,7 @@ struct LevelDefinition* levelFixPointers(struct LevelDefinition* from, int point result->signage = ADJUST_POINTER_POS(result->signage, pointerOffset); result->boxDroppers = ADJUST_POINTER_POS(result->boxDroppers, pointerOffset); result->switches = ADJUST_POINTER_POS(result->switches, pointerOffset); + result->dynamicBoxes = ADJUST_POINTER_POS(result->dynamicBoxes, pointerOffset); result->animations = ADJUST_POINTER_POS(result->animations, pointerOffset); diff --git a/src/scene/scene.c b/src/scene/scene.c index f3e6224..fbefd84 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -38,6 +38,30 @@ Lights1 gSceneLights = gdSPDefLights1(128, 128, 128, 128, 128, 128, 0, 127, 0); void sceneUpdateListeners(struct Scene* scene); +void sceneInitDynamicColliders(struct Scene* scene) { + int boxCount = gCurrentLevel->dynamicBoxCount; + + struct CollisionObject* colliders = malloc(sizeof(struct CollisionObject) * boxCount); + struct ColliderTypeData* colliderType = malloc(sizeof(struct ColliderTypeData) * boxCount); + struct RigidBody* body = malloc(sizeof(struct RigidBody) * boxCount); + + for (int i = 0; i < boxCount; ++i) { + colliderType[i].type = CollisionShapeTypeBox; + colliderType[i].data = &gCurrentLevel->dynamicBoxes[i].box; + colliderType[i].bounce = 0.5f; + colliderType[i].friction = 0.5f; + colliderType[i].callbacks = &gCollisionBoxCallbacks; + collisionObjectInit(&colliders[i], &colliderType[i], &body[i], 1.0f, COLLISION_LAYERS_TANGIBLE); + rigidBodyMarkKinematic(&body[i]); + + body[i].currentRoom = gCurrentLevel->dynamicBoxes[i].roomIndex; + + collisionSceneAddDynamicObject(&colliders[i]); + } + + scene->dynamicColliders = colliders; +} + void sceneInit(struct Scene* scene) { signalsInit(1); @@ -125,6 +149,8 @@ void sceneInit(struct Scene* scene) { scene->freeCameraOffset = gZeroVec; + sceneInitDynamicColliders(scene); + sceneAnimatorInit(&scene->animator, gCurrentLevel->animations, gCurrentLevel->animationInfoCount); } @@ -345,10 +371,31 @@ void sceneUpdate(struct Scene* scene) { for (int i = 0; i < scene->boxDropperCount; ++i) { boxDropperUpdate(&scene->boxDroppers[i]); } + + sceneAnimatorUpdate(&scene->animator); + + for (int i = 0; i < gCurrentLevel->dynamicBoxCount; ++i) { + struct DynamicBoxDefinition* boxDef = &gCurrentLevel->dynamicBoxes[i]; + struct Transform* baseTransform = sceneAnimatorTransformForIndex(&scene->animator, boxDef->transformIndex); + + if (!baseTransform) { + continue; + } + + struct Transform baseTransformUnscaled = *baseTransform; + vector3Scale(&baseTransformUnscaled.position, &baseTransformUnscaled.position, 1.0f / SCENE_SCALE); + struct Transform relativeTransform; + relativeTransform.position = boxDef->position; + relativeTransform.rotation = boxDef->rotation; + relativeTransform.scale = gOneVec; + + transformConcat(&baseTransformUnscaled, &relativeTransform, &scene->dynamicColliders[i].body->transform); + + collisionObjectUpdateBB(&scene->dynamicColliders[i]); + } collisionSceneUpdateDynamics(); - sceneAnimatorUpdate(&scene->animator); levelCheckTriggers(&scene->player.lookTransform.position); cutscenesUpdate(); @@ -399,8 +446,7 @@ void sceneUpdate(struct Scene* scene) { } } -int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, int quadIndex, int roomIndex) { - struct PortalSurfaceMappingRange surfaceMapping = gCurrentLevel->portalSurfaceMappingRange[quadIndex]; +int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, struct PortalSurfaceMappingRange surfaceMapping, struct CollisionObject* collisionObject, int roomIndex) { for (int indexIndex = surfaceMapping.minPortalIndex; indexIndex < surfaceMapping.maxPortalIndex; ++indexIndex) { int surfaceIndex = gCurrentLevel->portalSurfaceMappingIndices[indexIndex]; @@ -423,7 +469,7 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, portal->opacity = 0.0f; } - contactSolverCheckPortalContacts(&gContactSolver, &gCurrentLevel->collisionQuads[quadIndex]); + contactSolverCheckPortalContacts(&gContactSolver, collisionObject); return 1; } } @@ -468,7 +514,7 @@ int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* player quatLook(&hitDirection, &upDir, &portalLocation.rotation); } - return sceneOpenPortal(scene, &portalLocation, portalIndex, quadIndex, hit.roomIndex); + return sceneOpenPortal(scene, &portalLocation, portalIndex, gCurrentLevel->portalSurfaceMappingRange[quadIndex], &gCurrentLevel->collisionQuads[quadIndex], hit.roomIndex); } void sceneClosePortal(struct Scene* scene, int portalIndex) { diff --git a/src/scene/scene.h b/src/scene/scene.h index 5661281..2778767 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -34,6 +34,7 @@ struct Scene { struct Switch* switches; struct Vector3 freeCameraOffset; struct SceneAnimator animator; + struct CollisionObject* dynamicColliders; OSTime cpuTime; OSTime lastFrameStart; OSTime lastFrameTime; diff --git a/src/scene/scene_animator.c b/src/scene/scene_animator.c index dcbcde6..faecd1c 100644 --- a/src/scene/scene_animator.c +++ b/src/scene/scene_animator.c @@ -29,6 +29,21 @@ void sceneAnimatorUpdate(struct SceneAnimator* sceneAnimator) { } } +struct Transform* sceneAnimatorTransformForIndex(struct SceneAnimator* sceneAnimator, int index) { + if (index < 0) { + return NULL; + } + + for (int i = 0; i < sceneAnimator->animatorCount; ++i) { + if (index < sceneAnimator->armatures[i].numberOfBones) { + return &sceneAnimator->armatures[i].pose[index]; + } + + index -= sceneAnimator->armatures[i].numberOfBones; + } + + return NULL; +} Mtx* sceneAnimatorBuildTransforms(struct SceneAnimator* sceneAnimator, struct RenderState* renderState) { Mtx* result = renderStateRequestMatrices(renderState, sceneAnimator->boneCount); diff --git a/src/scene/scene_animator.h b/src/scene/scene_animator.h index 05c1480..c8a8655 100644 --- a/src/scene/scene_animator.h +++ b/src/scene/scene_animator.h @@ -21,6 +21,8 @@ void sceneAnimatorInit(struct SceneAnimator* sceneAnimator, struct AnimationInfo void sceneAnimatorUpdate(struct SceneAnimator* sceneAnimator); +struct Transform* sceneAnimatorTransformForIndex(struct SceneAnimator* sceneAnimator, int index); + Mtx* sceneAnimatorBuildTransforms(struct SceneAnimator* sceneAnimator, struct RenderState* renderState); void sceneAnimatorPlay(struct SceneAnimator* sceneAnimator, int animatorIndex, int animationIndex, float speed); diff --git a/tools/export_level.lua b/tools/export_level.lua index d408f23..2380e31 100644 --- a/tools/export_level.lua +++ b/tools/export_level.lua @@ -9,6 +9,7 @@ local world = require('tools.level_scripts.world') local entities = require('tools.level_scripts.entities') local signals = require('tools.level_scripts.signals') local animation = require('tools.level_scripts.animation') +local dynamic_collision = require('tools.level_scripts.dynamic_collision_export') sk_definition_writer.add_definition("level", "struct LevelDefinition", "_geo", { collisionQuads = sk_definition_writer.reference_to(collision_export.collision_objects, 1), @@ -51,4 +52,6 @@ sk_definition_writer.add_definition("level", "struct LevelDefinition", "_geo", { animationInfoCount = #animation.animated_nodes, switches = sk_definition_writer.reference_to(entities.switches, 1), switchCount = #entities.switches, + dynamicBoxes = sk_definition_writer.reference_to(dynamic_collision.dynamic_boxes, 1), + dynamicBoxCount = #dynamic_collision.dynamic_boxes, }) \ No newline at end of file diff --git a/tools/level_scripts/dynamic_collision_export.lua b/tools/level_scripts/dynamic_collision_export.lua new file mode 100644 index 0000000..68ec717 --- /dev/null +++ b/tools/level_scripts/dynamic_collision_export.lua @@ -0,0 +1,50 @@ +local sk_definition_writer = require('sk_definition_writer') +local sk_scene = require('sk_scene') +local animation = require('tools.level_scripts.animation') +local room_export = require('tools.level_scripts.room_export') + +local dynamic_boxes = {} + +local function build_dynamic_box(box) + local parent_node_index = animation.get_bone_index_for_node(box.node) + + if not parent_node_index then + return nil + end + + local parent_node = animation.get_bone_for_index(parent_node_index) + + if not parent_node then + return nil + end + + local relative_transform = parent_node.full_transformation:inverse() * box.node.full_transformation + + local mesh_bb = box.node.meshes[1].bb + + local _, rotation = relative_transform:decompose() + local pos = relative_transform * mesh_bb:lerp(0.5) + + return { + {(mesh_bb.max - mesh_bb.min) * 0.5}, + pos, + rotation, + room_export.node_nearest_room_index(box.node), + parent_node_index - 1, + } +end + +for _, box in pairs(sk_scene.nodes_for_type('@dynamic_box')) do + local dynamic_box = build_dynamic_box(box) + + if dynamic_box then + table.insert(dynamic_boxes, dynamic_box) + end + +end + +sk_definition_writer.add_definition('dynamic_boxes', 'struct DynamicBoxDefinition[]', '_geo', dynamic_boxes) + +return { + dynamic_boxes = dynamic_boxes, +} \ No newline at end of file