From abf2c858dbe2d4c6bd9a9069dd32b2df893e3c75 Mon Sep 17 00:00:00 2001 From: James Lambert Date: Wed, 6 Jul 2022 12:42:44 -0600 Subject: [PATCH] Implement special case logic when standing close to a portal --- README.md | 2 +- src/physics/collision_scene.h | 1 + src/scene/camera.c | 7 +-- src/scene/camera.h | 5 +- src/scene/portal.c | 89 +++++++++++++++++++++++++++-------- src/scene/portal.h | 2 + 6 files changed, 80 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 3f4dd6d..7226985 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender - Implement loading levels from the cartridge - [x] Implement "Emancipation grid" - [ ] Change the way player standing logic works -- [ ] Cut holes in portal walls +- [x] Cut holes in portal walls - [ ] Cube dispenser - [ ] NAN in overlap - [ ] Get an optimized build working diff --git a/src/physics/collision_scene.h b/src/physics/collision_scene.h index 735f3e1..610b037 100644 --- a/src/physics/collision_scene.h +++ b/src/physics/collision_scene.h @@ -27,6 +27,7 @@ extern struct CollisionScene gCollisionScene; void collisionSceneInit(struct CollisionScene* scene, struct CollisionObject* quads, int quadCount, struct World* world); void collisionObjectCollideWithScene(struct CollisionObject* object, struct CollisionScene* scene, struct ContactSolver* contactSolver); +int collisionSceneIsTouchingSinglePortal(struct Vector3* contactPoint, struct Vector3* contactNormal, struct Transform* portalTransform, int portalIndex); int collisionSceneIsTouchingPortal(struct Vector3* contactPoint, struct Vector3* contactNormal); int collisionSceneIsPortalOpen(); diff --git a/src/scene/camera.c b/src/scene/camera.c index a9f64fe..6a36046 100644 --- a/src/scene/camera.c +++ b/src/scene/camera.c @@ -5,7 +5,7 @@ #include "../graphics/graphics.h" int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingBoxs16* boundingBox) { - for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { + for (int i = 0; i < frustrum->usedClippingPlaneCount; ++i) { struct Vector3 closestPoint; struct Vector3* normal = &frustrum->clippingPlanes[i].normal; @@ -24,7 +24,7 @@ int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Boundi } int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct Vector3* scaledCenter, float scaledRadius) { - for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { + for (int i = 0; i < frustrum->usedClippingPlaneCount; ++i) { if (planePointDistance(&frustrum->clippingPlanes[i], scaledCenter) < -scaledRadius) { return 1; } @@ -34,7 +34,7 @@ int isSphereOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct } int isQuadOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct CollisionQuad* quad) { - for (int i = 0; i < CLIPPING_PLANE_COUNT; ++i) { + for (int i = 0; i < frustrum->usedClippingPlaneCount; ++i) { struct Vector3* normal = &frustrum->clippingPlanes[i].normal; float aLerp = vector3Dot(normal, &quad->edgeA) < 0.0f ? 0.0f : quad->edgeALength; float bLerp = vector3Dot(normal, &quad->edgeB) < 0.0f ? 0.0f : quad->edgeBLength; @@ -126,6 +126,7 @@ Mtx* cameraSetupMatrices(struct Camera* camera, struct RenderState* renderState, cameraExtractClippingPlane(combined, &clippingInfo->clippingPlanes[3], 1, -1.0f); cameraExtractClippingPlane(combined, &clippingInfo->clippingPlanes[4], 2, 1.0f); clippingInfo->cameraPos = camera->transform.position; + clippingInfo->usedClippingPlaneCount = 5; } gSPMatrix(renderState->dl++, osVirtualToPhysical(&viewProjMatrix[1]), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); diff --git a/src/scene/camera.h b/src/scene/camera.h index b25dff6..5fb8f7b 100644 --- a/src/scene/camera.h +++ b/src/scene/camera.h @@ -11,7 +11,7 @@ #include "../physics/collision_quad.h" #include "../math/boxs16.h" -#define CLIPPING_PLANE_COUNT 5 +#define MAX_CLIPPING_PLANE_COUNT 6 struct Camera { struct Transform transform; @@ -21,7 +21,8 @@ struct Camera { }; struct FrustrumCullingInformation { - struct Plane clippingPlanes[CLIPPING_PLANE_COUNT]; + struct Plane clippingPlanes[MAX_CLIPPING_PLANE_COUNT]; + short usedClippingPlaneCount; struct Vector3 cameraPos; }; diff --git a/src/scene/portal.c b/src/scene/portal.c index 37ebba5..baaf982 100644 --- a/src/scene/portal.c +++ b/src/scene/portal.c @@ -6,6 +6,7 @@ #include "../defs.h" #include "dynamic_scene.h" #include "../physics/collision_scene.h" +#include "../math/mathf.h" #define CALC_SCREEN_SPACE(clip_space, screen_size) ((clip_space + 1.0f) * ((screen_size) / 2)) @@ -48,6 +49,8 @@ struct Quaternion gVerticalFlip = {0.0f, 1.0f, 0.0f, 0.0f}; #define PORTAL_CLIPPING_PLANE_BIAS (SCENE_SCALE * 0.25f) +#define CAMERA_CLIPPING_RADIUS 0.2f + void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex) { props->camera = *camera; props->aspectRatio = aspectRatio; @@ -66,6 +69,40 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp props->perspectiveMatrix = cameraSetupMatrices(&externalCamera, renderState, aspectRatio, &props->perspectiveCorrect, &fullscreenViewport, NULL, 0.0f); #endif + props->clippingPortalIndex = -1; + + if (collisionSceneIsPortalOpen()) { + for (int i = 0; i < 2; ++i) { + struct Vector3 portalOffset; + + vector3Sub(&camera->transform.position, &gCollisionScene.portalTransforms[i]->position, &portalOffset); + + struct Vector3 portalNormal; + quatMultVector(&gCollisionScene.portalTransforms[i]->rotation, &gForward, &portalNormal); + struct Vector3 projectedPoint; + + if (i == 0) { + vector3Negate(&portalNormal, &portalNormal); + } + + float clippingDistnace = vector3Dot(&portalNormal, &portalOffset); + + if (fabsf(clippingDistnace) > CAMERA_CLIPPING_RADIUS) { + continue; + } + + vector3AddScaled(&camera->transform.position, &portalNormal, -clippingDistnace, &projectedPoint); + + if (collisionSceneIsTouchingSinglePortal(&projectedPoint, &portalNormal, gCollisionScene.portalTransforms[i], i)) { + vector3Negate(&portalNormal, &portalNormal); + planeInitWithNormalAndPoint(&props->cullingInfo.clippingPlanes[5], &portalNormal, &gCollisionScene.portalTransforms[i]->position); + ++props->cullingInfo.usedClippingPlaneCount; + props->clippingPortalIndex = i; + break; + } + } + } + props->minX = 0; props->minY = 0; props->maxX = SCREEN_WD; @@ -149,12 +186,15 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru next->perspectiveMatrix = cameraSetupMatrices(&externalCamera, renderState, (float)SCREEN_WD / (float)SCREEN_HT, &next->perspectiveCorrect, &fullscreenViewport, NULL, zBias); #endif - // set the near clipping plane to be the exit portal surface - quatMultVector(&toPortal->rotation, &gForward, &next->cullingInfo.clippingPlanes[4].normal); - if (toPortal < fromPortal) { - vector3Negate(&next->cullingInfo.clippingPlanes[4].normal, &next->cullingInfo.clippingPlanes[4].normal); + if (current->clippingPortalIndex != -1) { + // set the near clipping plane to be the exit portal surface + quatMultVector(&toPortal->rotation, &gForward, &next->cullingInfo.clippingPlanes[4].normal); + if (toPortal < fromPortal) { + vector3Negate(&next->cullingInfo.clippingPlanes[4].normal, &next->cullingInfo.clippingPlanes[4].normal); + } + next->cullingInfo.clippingPlanes[4].d = -vector3Dot(&next->cullingInfo.clippingPlanes[4].normal, &toPortal->position) * SCENE_SCALE - PORTAL_CLIPPING_PLANE_BIAS; } - next->cullingInfo.clippingPlanes[4].d = -vector3Dot(&next->cullingInfo.clippingPlanes[4].normal, &toPortal->position) * SCENE_SCALE - PORTAL_CLIPPING_PLANE_BIAS; + next->clippingPortalIndex = -1; next->currentDepth = current->currentDepth - 1; next->fromPortalIndex = toPortal < fromPortal ? 0 : 1; @@ -219,26 +259,35 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend return; } - screenClipperInitWithCamera(&clipper, &props->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform); - - struct Box2D clippingBounds; - - screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds); - struct RenderProps nextProps; - nextProps.minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD); - nextProps.maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD); - nextProps.minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT); - nextProps.maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT); + int portalIndex = portal < otherPortal ? 0 : 1; - nextProps.minX = MAX(nextProps.minX, props->minX); - nextProps.maxX = MIN(nextProps.maxX, props->maxX); - nextProps.minY = MAX(nextProps.minY, props->minY); - nextProps.maxY = MIN(nextProps.maxY, props->maxY); + if (props->clippingPortalIndex == portalIndex) { + nextProps.minX = props->minX; + nextProps.maxX = props->maxX; + nextProps.minY = props->minY; + nextProps.maxY = props->maxY; + } else { + screenClipperInitWithCamera(&clipper, &props->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform); + + struct Box2D clippingBounds; + + screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds); + + + nextProps.minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD); + nextProps.maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD); + nextProps.minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT); + nextProps.maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT); + + nextProps.minX = MAX(nextProps.minX, props->minX); + nextProps.maxX = MIN(nextProps.maxX, props->maxX); + nextProps.minY = MAX(nextProps.minY, props->minY); + nextProps.maxY = MIN(nextProps.maxY, props->maxY); + } if (nextProps.minX < nextProps.maxX && nextProps.minY < nextProps.maxY) { - renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, renderState); sceneRenderer(data, &nextProps, renderState); diff --git a/src/scene/portal.h b/src/scene/portal.h index 4a84162..1e04ce1 100644 --- a/src/scene/portal.h +++ b/src/scene/portal.h @@ -44,6 +44,8 @@ struct RenderProps { short minY; short maxX; short maxY; + + s8 clippingPortalIndex; }; void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex);