Start work on portal animation

This commit is contained in:
James Lambert 2022-07-09 21:47:40 -06:00
parent 7e9843f439
commit a1d670faf6
15 changed files with 119 additions and 39 deletions

View file

@ -95,6 +95,7 @@ src/models/sphere.h src/models/sphere_geo.inc.h: assets/fbx/Sphere.fbx
portal_pak_dir: vpk/portal_pak_dir.vpk
vpk -x portal_pak_dir vpk/portal_pak_dir.vpk
vpk -x portal_pak_dir vpk/hl2/hl2_sound_misc_dir.vpk
TEXTURE_SCRIPTS = $(shell find assets/ -type f -name '*.ims')
@ -164,9 +165,11 @@ MODEL_LIST = assets/models/cube/cube.blend \
assets/models/props/round_elevator_collision.blend \
assets/models/portal/portal_blue.blend \
assets/models/portal/portal_blue_filled.blend \
assets/models/portal/portal_blue_face.blend \
assets/models/portal/portal_orange.blend \
assets/models/portal/portal_orange_filled.blend \
assets/models/portal/portal_face.blend
assets/models/portal/portal_orange_face.blend
MODEL_HEADERS = $(MODEL_LIST:%.blend=build/%.h)
MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o)

View file

@ -84,12 +84,14 @@ Where `/home/james/Blender/blender-2.93.1-linux-x64` is the folder where Blender
## Current TODO list
- [x] Implement "Elevator"
- [ ] Turn level indicator board into a game object
- [ ] Presort portal gun polygon order
- [ ] Implement level transitions
- Implement loading levels from the cartridge
- [x] Implement "Emancipation grid"
- [ ] Change the way player standing logic works
- [x] Cut holes in portal walls
- [ ] Cube dispenser
- [ ] NAN in overlap
- [ ] Get an optimized build working
- [x] Implement "Elevator"
- [x] Implement "Emancipation grid"
- [x] Cut holes in portal walls
- [x] Get an optimized build working

View file

@ -364,10 +364,14 @@ materials:
clear: [G_CULL_BACK, G_CULL_FRONT]
z_update:
gDPSetCycleType: G_CYC_1CYCLE
gDPSetCombineMode:
color: ["0", "0", "0", "PRIMITIVE"]
alpha: ["0", "0", "0", "PRIMITIVE"]
color: ["0", "0", "0", "SHADE"]
alpha: ["0", "0", "0", "ENVIRONMENT"]
gSPGeometryMode:
clear: [G_LIGHTING]
set: [G_SHADE]
gDPSetRenderMode:
flags:
- Z_CMP

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
-m assets/materials/static.skm.yaml

View file

@ -3,6 +3,7 @@
#include "../scene/camera.h"
#include "../math/vector4.h"
#include "../math/matrix.h"
#include "../math/mathf.h"
#include "./graphics.h"
#include <math.h>
@ -86,6 +87,9 @@ unsigned screenClipperClipBoundary(struct ScreenClipper* clipper, struct Vector4
return outputPointCount;
}
// 6 is actually 1.5 pixels since it is a fixed point number with 2 decimal points
#define PIXEL_EXPAND_COUNT 6
void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3* input, unsigned pointCount, struct Box2D* output) {
vector2Scale(&gOneVec2, -1.0f, &output->max);
output->min = gOneVec2;
@ -115,7 +119,32 @@ void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3*
clipper->nearPolygon[i].y = (short)(point->y * invW * (SCREEN_HT << 1) + (SCREEN_HT << 1));
}
// TODO expand the polygon a few pixels
// expand the polygon a few pixels
for (int i = 0; i < clipper->nearPolygonCount; ++i) {
struct Vector2s16* curr = &clipper->nearPolygon[i];
struct Vector2s16* next = &clipper->nearPolygon[(i + 1) % clipper->nearPolygonCount];
struct Vector2s16 offset;
vector2s16Sub(next, curr, &offset);
if (abs(offset.x) > abs(offset.y)) {
if (curr->x < next->x) {
curr->x -= PIXEL_EXPAND_COUNT;
next->x += PIXEL_EXPAND_COUNT;
} else {
curr->x += PIXEL_EXPAND_COUNT;
next->y -= PIXEL_EXPAND_COUNT;
}
} else {
if (curr->y < next->y) {
curr->y -= PIXEL_EXPAND_COUNT;
next->y += PIXEL_EXPAND_COUNT;
} else {
curr->y += PIXEL_EXPAND_COUNT;
curr->y -= PIXEL_EXPAND_COUNT;
}
}
}
for (unsigned i = 0; i < pointCount; ++i) {
screenClipperIncludePoint(&clipBuffer[i], output);

View file

@ -6,8 +6,6 @@
#include "../graphics/render_scene.h"
#include "../math/mathf.h"
int gForceRenderStaticIndex = -1;
void staticRenderPopulateRooms(struct FrustrumCullingInformation* cullingInfo, struct RenderScene* renderScene) {
int currentRoom = 0;
@ -20,7 +18,7 @@ void staticRenderPopulateRooms(struct FrustrumCullingInformation* cullingInfo, s
for (int i = staticRange.min; i < staticRange.max; ++i) {
struct BoundingBoxs16* box = &gCurrentLevel->staticBoundingBoxes[i];
if (i != gForceRenderStaticIndex && isOutsideFrustrum(cullingInfo, box)) {
if (isOutsideFrustrum(cullingInfo, box)) {
continue;
}

View file

@ -6,8 +6,6 @@
#include "scene/camera.h"
#include "../scene/dynamic_scene.h"
extern int gForceRenderStaticIndex;
void staticRenderDetermineVisibleRooms(struct FrustrumCullingInformation* cullingInfo, u16 currentRoom, u64* visitedRooms);
int staticRenderIsRoomVisible(u64 visibleRooms, u16 roomIndex);
void staticRender(struct Transform* cameraTransform, struct FrustrumCullingInformation* cullingInfo, u64 visibleRooms, struct RenderState* renderState);

View file

@ -32,7 +32,7 @@ struct CollisionQuad gPlayerColliderFaces[8];
struct CollisionCylinder gPlayerCollider = {
0.25f,
0.7f,
0.5f,
gPlayerColliderEdgeVectors,
sizeof(gPlayerColliderEdgeVectors) / sizeof(*gPlayerColliderEdgeVectors),
gPlayerColliderFaces,

View file

@ -8,19 +8,18 @@
#include "../physics/collision_scene.h"
#include "../math/mathf.h"
#include "../math/vector2s16.h"
#include "../util/time.h"
#include "../build/assets/models/portal/portal_blue.h"
#include "../build/assets/models/portal/portal_orange.h"
#include "../build/assets/models/portal/portal_blue_filled.h"
#include "../build/assets/models/portal/portal_blue_face.h"
#include "../build/assets/models/portal/portal_orange.h"
#include "../build/assets/models/portal/portal_orange_face.h"
#include "../build/assets/models/portal/portal_orange_filled.h"
#include "../build/assets/models/portal/portal_face.h"
#define CALC_SCREEN_SPACE(clip_space, screen_size) ((clip_space + 1.0f) * ((screen_size) / 2))
#define PORTAL_SCALE_Y 0.8f
#define PORTAL_SCALE_X 0.95f
#define PORTAL_COVER_HEIGHT 0.708084f
#define PORTAL_COVER_WIDTH 0.84085f
@ -35,15 +34,18 @@ struct Vector3 gPortalOutline[PORTAL_LOOP_SIZE] = {
{-0.353553f * SCENE_SCALE * PORTAL_COVER_WIDTH, 0.707107f * SCENE_SCALE * PORTAL_COVER_HEIGHT, 0},
};
#define PORTAL_HOLE_SCALE_X 0.945f
#define PORTAL_HOLE_SCALE_Y 0.795f
struct Vector3 gPortalOutlineWorld[PORTAL_LOOP_SIZE] = {
{-0.353553f * PORTAL_SCALE_X, 0.707107f * PORTAL_SCALE_Y, 0.0f},
{-0.5f * PORTAL_SCALE_X, 0.0f, 0.0f},
{-0.353553f * PORTAL_SCALE_X, -0.707107f * PORTAL_SCALE_Y, 0.0f},
{0.0f, -1.0f * PORTAL_SCALE_Y, 0.0f},
{0.353553f * PORTAL_SCALE_X, -0.707107f * PORTAL_SCALE_Y, 0.0f},
{0.5f * PORTAL_SCALE_X, 0.0f, 0.0f},
{0.353553f * PORTAL_SCALE_X, 0.707107f * PORTAL_SCALE_Y, 0.0f},
{0.0f, 1.0f * PORTAL_SCALE_Y, 0.0f},
{-0.353553f * PORTAL_HOLE_SCALE_X, 0.707107f * PORTAL_HOLE_SCALE_Y, 0.0f},
{-0.5f * PORTAL_HOLE_SCALE_X, 0.0f, 0.0f},
{-0.353553f * PORTAL_HOLE_SCALE_X, -0.707107f * PORTAL_HOLE_SCALE_Y, 0.0f},
{0.0f, -1.0f * PORTAL_HOLE_SCALE_Y, 0.0f},
{0.353553f * PORTAL_HOLE_SCALE_X, -0.707107f * PORTAL_HOLE_SCALE_Y, 0.0f},
{0.5f * PORTAL_HOLE_SCALE_X, 0.0f, 0.0f},
{0.353553f * PORTAL_HOLE_SCALE_X, 0.707107f * PORTAL_HOLE_SCALE_Y, 0.0f},
{0.0f, 1.0f * PORTAL_HOLE_SCALE_Y, 0.0f},
};
#define SHOW_EXTERNAL_VIEW 0
@ -63,6 +65,11 @@ struct Quaternion gVerticalFlip = {0.0f, 1.0f, 0.0f, 0.0f};
#define CAMERA_CLIPPING_RADIUS 0.2f
#define PORTAL_CLIPPING_OFFSET 0.1f
#define PORTAL_OPACITY_FADE_TIME 0.6f
#define PORTAL_GROW_TIME 0.3f
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex) {
props->camera = *camera;
props->aspectRatio = aspectRatio;
@ -107,7 +114,7 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
if (collisionSceneIsTouchingSinglePortal(&projectedPoint, &portalNormal, gCollisionScene.portalTransforms[i], i)) {
planeInitWithNormalAndPoint(&props->cullingInfo.clippingPlanes[5], &portalNormal, &gCollisionScene.portalTransforms[i]->position);
props->cullingInfo.clippingPlanes[5].d *= SCENE_SCALE;
props->cullingInfo.clippingPlanes[5].d = (props->cullingInfo.clippingPlanes[5].d + PORTAL_CLIPPING_OFFSET) * SCENE_SCALE;
++props->cullingInfo.usedClippingPlaneCount;
props->clippingPortalIndex = i;
break;
@ -249,6 +256,28 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru
void portalInit(struct Portal* portal, enum PortalFlags flags) {
transformInitIdentity(&portal->transform);
portal->flags = flags;
portal->opacity = 1.0f;
portal->scale = 0.0f;
}
void portalUpdate(struct Portal* portal, int isOpen) {
if (isOpen && portal->opacity > 0.0f) {
portal->opacity -= FIXED_DELTA_TIME * (1.0f / PORTAL_OPACITY_FADE_TIME);
if (portal->opacity < 0.0f) {
portal->opacity = 0.0f;
}
} else if (!isOpen) {
portal->opacity = 1.0f;
}
if (portal->scale < 1.0f) {
portal->scale += FIXED_DELTA_TIME * (1.0f / PORTAL_GROW_TIME);
if (portal->scale > 1.0f) {
portal->scale = 1.0f;
}
}
}
void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct RenderProps* props, struct RenderState* renderState) {
@ -336,6 +365,8 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend
quatMultiply(&portal->transform.rotation, &gVerticalFlip, &finalTransform.rotation);
}
vector3Scale(&gOneVec, &finalTransform.scale, portal->scale);
transformToMatrix(&finalTransform, portalTransform, SCENE_SCALE);
if (props->currentDepth == 0 || !otherPortal) {
@ -391,14 +422,20 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend
guMtxF2L(portalTransform, matrix);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
gSPDisplayList(renderState->dl++, portal_portal_face_model_gfx);
portalRenderScreenCover(clipper.nearPolygon, clipper.nearPolygonCount, props, renderState);
gDPPipeSync(renderState->dl++);
gDPSetEnvColor(renderState->dl++, 255, 255, 255, portal->opacity < 0.0f ? 0 : (portal->opacity > 1.0f ? 255 : (u8)(portal->opacity * 255.0f)));
if (portal->flags & PortalFlagsOddParity) {
gSPDisplayList(renderState->dl++, portal_portal_blue_face_model_gfx);
portalRenderScreenCover(clipper.nearPolygon, clipper.nearPolygonCount, props, renderState);
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_blue_model_gfx);
} else {
gSPDisplayList(renderState->dl++, portal_portal_orange_face_model_gfx);
portalRenderScreenCover(clipper.nearPolygon, clipper.nearPolygonCount, props, renderState);
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_orange_model_gfx);
}

View file

@ -20,6 +20,8 @@ enum PortalFlags {
struct Portal {
struct Transform transform;
enum PortalFlags flags;
float opacity;
float scale;
};
struct RenderProps;
@ -53,7 +55,7 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState);
void portalInit(struct Portal* portal, enum PortalFlags flags);
void portalUpdate(struct Portal* portal, int isOpen);
void portalRender(struct Portal* portal, struct Portal* otherPortal, struct RenderProps* props, SceneRenderCallback sceneRenderer, void* data, struct RenderState* renderState);
#endif

View file

@ -118,13 +118,7 @@ void sceneRenderWithProperties(void* data, struct RenderProps* properties, struc
otherPortal = 1 - otherPortal;
}
if (properties->clippingPortalIndex != -1) {
gForceRenderStaticIndex = portalSurfaceStaticIndexForReplacement(properties->clippingPortalIndex);
}
staticRender(&properties->camera.transform, &properties->cullingInfo, visibleRooms, renderState);
gForceRenderStaticIndex = -1;
}
#define SOLID_COLOR 0, 0, 0, ENVIRONMENT, 0, 0, 0, ENVIRONMENT
@ -211,6 +205,11 @@ void sceneCheckPortals(struct Scene* scene) {
sceneClosePortal(scene, 1);
scene->player.body.flags &= ~RigidBodyFizzled;
}
int isOpen = collisionSceneIsPortalOpen();
portalUpdate(&scene->portals[0], isOpen);
portalUpdate(&scene->portals[1], isOpen);
}
void sceneUpdatePortalListener(struct Scene* scene, int portalIndex, int listenerIndex) {
@ -294,6 +293,13 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex,
gCollisionScene.portalTransforms[portalIndex] = &scene->portals[portalIndex].transform;
gCollisionScene.portalRooms[portalIndex] = roomIndex;
if (collisionSceneIsPortalOpen()) {
// the second portal is fully transparent right away
scene->portals[portalIndex].opacity = 0.0f;
}
scene->portals[portalIndex].scale = 0.0f;
contactSolverCheckPortalContacts(&gContactSolver, &gCurrentLevel->collisionQuads[quadIndex]);
return 1;
}