Start work on portal animation
This commit is contained in:
parent
7e9843f439
commit
a1d670faf6
5
Makefile
5
Makefile
|
@ -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)
|
||||
|
|
10
README.md
10
README.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
BIN
assets/models/portal/portal_blue_face.blend
Normal file
BIN
assets/models/portal/portal_blue_face.blend
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/models/portal/portal_orange_face.blend
Normal file
BIN
assets/models/portal/portal_orange_face.blend
Normal file
Binary file not shown.
1
assets/models/portal/portal_orange_face.flags
Normal file
1
assets/models/portal/portal_orange_face.flags
Normal file
|
@ -0,0 +1 @@
|
|||
-m assets/materials/static.skm.yaml
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct CollisionQuad gPlayerColliderFaces[8];
|
|||
|
||||
struct CollisionCylinder gPlayerCollider = {
|
||||
0.25f,
|
||||
0.7f,
|
||||
0.5f,
|
||||
gPlayerColliderEdgeVectors,
|
||||
sizeof(gPlayerColliderEdgeVectors) / sizeof(*gPlayerColliderEdgeVectors),
|
||||
gPlayerColliderFaces,
|
||||
|
|
|
@ -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) {
|
||||
|
@ -392,13 +423,19 @@ 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);
|
||||
gDPSetEnvColor(renderState->dl++, 255, 255, 255, portal->opacity < 0.0f ? 0 : (portal->opacity > 1.0f ? 255 : (u8)(portal->opacity * 255.0f)));
|
||||
|
||||
gDPPipeSync(renderState->dl++);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue