Finish out render plan code

This commit is contained in:
James Lambert 2022-11-13 19:48:40 -07:00
parent beadfaf2e0
commit 5db7dc544a
6 changed files with 309 additions and 19 deletions

View file

@ -201,6 +201,8 @@ build/src/scene/box_dropper.o: $(MODEL_HEADERS)
build/src/scene/pedestal.o: $(MODEL_HEADERS)
build/src/scene/render_plan.o: $(MODEL_HEADERS)
build/anims.ld: $(ANIM_LIST) tools/generate_animation_ld.js
@mkdir -p $(@D)
node tools/generate_animation_ld.js $@ $(ANIM_LIST)

View file

@ -57,7 +57,7 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
cameraApplyMatrices(renderState, &props->cameraMatrixInfo);
props->viewport = &fullscreenViewport;
props->currentDepth = STARTING_RENDER_DEPTH;
props->fromPortalIndex = NO_PORTAL;
props->exitPortalIndex = NO_PORTAL;
props->fromRoom = roomIndex;
props->clippingPortalIndex = -1;
@ -98,6 +98,10 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
props->minY = 0;
props->maxX = SCREEN_WD;
props->maxY = SCREEN_HT;
props->previousProperties = NULL;
props->portalRenderType = 0;
}
#define MIN_VP_WIDTH 64
@ -213,9 +217,8 @@ int renderPropsNext(struct RenderProps* current, struct RenderProps* next, struc
}
next->clippingPortalIndex = -1;
next->fromPortalIndex = toPortal < fromPortal ? 0 : 1;
// Gross
next->fromRoom = gCollisionScene.portalRooms[toPortal == gCollisionScene.portalTransforms[0] ? 0 : 1];
next->exitPortalIndex = toPortal < fromPortal ? 0 : 1;
next->fromRoom = gCollisionScene.portalRooms[next->exitPortalIndex];
gSPViewport(renderState->dl++, viewport);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, next->minX, next->minY, next->maxX, next->maxY);
@ -332,6 +335,19 @@ void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct R
gDPSetRenderMode(renderState->dl++, G_RM_ZB_OPA_SURF, G_RM_ZB_OPA_SURF2);
}
void portalDetermineTransform(struct Portal* portal, float portalTransform[4][4]) {
struct Transform finalTransform;
finalTransform = portal->transform;
if (portal->flags & PortalFlagsOddParity) {
quatMultiply(&portal->transform.rotation, &gVerticalFlip, &finalTransform.rotation);
}
vector3Scale(&gOneVec, &finalTransform.scale, portal->scale);
transformToMatrix(&finalTransform, portalTransform, SCENE_SCALE);
}
void portalRenderCover(struct Portal* portal, float portalTransform[4][4], struct RenderState* renderState) {
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
@ -369,17 +385,7 @@ void portalRender(struct Portal* portal, struct Portal* otherPortal, struct Rend
struct ScreenClipper clipper;
float portalTransform[4][4];
struct Transform finalTransform;
finalTransform = portal->transform;
if (portal->flags & PortalFlagsOddParity) {
quatMultiply(&portal->transform.rotation, &gVerticalFlip, &finalTransform.rotation);
}
vector3Scale(&gOneVec, &finalTransform.scale, portal->scale);
transformToMatrix(&finalTransform, portalTransform, SCENE_SCALE);
portalDetermineTransform(portal, portalTransform);
if (props->currentDepth == 0 || !otherPortal) {
portalRenderCover(portal, portalTransform, renderState);

View file

@ -8,6 +8,7 @@
#include "camera.h"
#include "static_scene.h"
#include "./portal_surface.h"
#include "../graphics/screen_clipper.h"
#define PORTAL_LOOP_SIZE 8
@ -34,6 +35,14 @@ typedef void SceneRenderCallback(void* data, struct RenderProps* properties, str
#define NO_PORTAL 0xFF
#define PORTAL_RENDER_TYPE_VISIBLE_0 (1 << 0)
#define PORTAL_RENDER_TYPE_VISIBLE_1 (1 << 1)
#define PORTAL_RENDER_TYPE_ENABLED_0 (1 << 2)
#define PORTAL_RENDER_TYPE_ENABLED_1 (1 << 3)
#define PORTAL_RENDER_TYPE_VISIBLE(portalIndex) (PORTAL_RENDER_TYPE_VISIBLE_0 << (portalIndex))
#define PORTAL_RENDER_TYPE_ENABLED(portalIndex) (PORTAL_RENDER_TYPE_ENABLED_0 << (portalIndex))
struct RenderProps {
struct Camera camera;
float aspectRatio;
@ -43,7 +52,9 @@ struct RenderProps {
Vp* viewport;
u8 currentDepth;
u8 fromPortalIndex;
u8 exitPortalIndex;
s8 clippingPortalIndex;
u8 portalRenderType;
u16 fromRoom;
@ -52,7 +63,10 @@ struct RenderProps {
short maxX;
short maxY;
s8 clippingPortalIndex;
u64 visiblerooms;
struct RenderProps* previousProperties;
struct ScreenClipper clipper;
};
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex);
@ -62,6 +76,8 @@ 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);
void portalDetermineTransform(struct Portal* portal, float portalTransform[4][4]);
int portalAttachToSurface(struct Portal* portal, struct PortalSurface* surface, int surfaceIndex, struct Transform* portalAt);
void portalCheckForHoles(struct Portal* portals);

249
src/scene/render_plan.c Normal file
View file

@ -0,0 +1,249 @@
#include "render_plan.h"
#include "../graphics/screen_clipper.h"
#include "../physics/collision_scene.h"
#include "../levels/static_render.h"
#include "../build/assets/models/portal/portal_blue.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"
Vp* renderPropsBuildViewport(struct RenderProps* props, struct RenderState* renderState);
void renderPlanFinishView(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderProps* properties, struct RenderState* renderState);
void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct RenderProps* props, struct RenderState* renderState);
void portalRenderCover(struct Portal* portal, float portalTransform[4][4], struct RenderState* renderState);
extern struct Quaternion gVerticalFlip;
extern struct Vector3 gPortalOutline[PORTAL_LOOP_SIZE];
#define CALC_SCREEN_SPACE(clip_space, screen_size) ((clip_space + 1.0f) * ((screen_size) / 2))
int renderPlanPortal(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderProps* current, int exitPortalIndex, struct RenderState* renderState) {
struct Portal* portal = &scene->portals[1 - exitPortalIndex];
struct Vector3 forward = gForward;
if (!(portal->flags & PortalFlagsOddParity)) {
forward.z = -1.0f;
}
struct Vector3 worldForward;
quatMultVector(&portal->transform.rotation, &forward, &worldForward);
struct Vector3 offsetFromCamera;
vector3Sub(&current->camera.transform.position, &portal->transform.position, &offsetFromCamera);
// don't render the portal if it is facing the wrong way
if (vector3Dot(&worldForward, &offsetFromCamera) < 0.0f) {
return 0;
}
float portalTransform[4][4];
struct Transform finalTransform;
finalTransform = portal->transform;
if (portal->flags & PortalFlagsOddParity) {
quatMultiply(&portal->transform.rotation, &gVerticalFlip, &finalTransform.rotation);
}
vector3Scale(&gOneVec, &finalTransform.scale, portal->scale);
transformToMatrix(&finalTransform, portalTransform, SCENE_SCALE);
int portalIndex = 1 - exitPortalIndex;
int flags = PORTAL_RENDER_TYPE_VISIBLE(portalIndex);
if (current->currentDepth == 0 || !collisionSceneIsPortalOpen() || renderPlan->stageCount >= MAX_PORTAL_STEPS) {
return flags;
}
struct RenderProps* next = &renderPlan->stageProps[renderPlan->stageCount];
screenClipperInitWithCamera(&next->clipper, &current->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct Box2D clippingBounds;
screenClipperBoundingPoints(&next->clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
if (current->clippingPortalIndex == portalIndex) {
next->minX = 0;
next->maxX = SCREEN_WD;
next->minY = 0;
next->maxY = SCREEN_HT;
} else {
next->minX = CALC_SCREEN_SPACE(clippingBounds.min.x, SCREEN_WD);
next->maxX = CALC_SCREEN_SPACE(clippingBounds.max.x, SCREEN_WD);
next->minY = CALC_SCREEN_SPACE(-clippingBounds.max.y, SCREEN_HT);
next->maxY = CALC_SCREEN_SPACE(-clippingBounds.min.y, SCREEN_HT);
next->minX = MAX(next->minX, current->minX);
next->maxX = MIN(next->maxX, current->maxX);
next->minY = MAX(next->minY, current->minY);
next->maxY = MIN(next->maxY, current->maxY);
}
if (next->minX >= next->maxX || next->minY >= next->maxY) {
return 0;
}
struct Transform* exitPortal = &scene->portals[exitPortalIndex].transform;
struct Transform* intoPortal = &scene->portals[1 - exitPortalIndex].transform;
struct Transform otherInverse;
transformInvert(exitPortal, &otherInverse);
struct Transform portalCombined;
transformConcat(intoPortal, &otherInverse, &portalCombined);
next->camera = current->camera;
next->aspectRatio = current->aspectRatio;
transformConcat(&portalCombined, &current->camera.transform, &next->camera.transform);
struct Vector3 portalOffset;
vector3Sub(&intoPortal->position, &next->camera.transform.position, &portalOffset);
struct Vector3 cameraForward;
quatMultVector(&next->camera.transform.rotation, &gForward, &cameraForward);
next->camera.nearPlane = (-vector3Dot(&portalOffset, &cameraForward)) * SCENE_SCALE;
if (next->camera.nearPlane < current->camera.nearPlane) {
next->camera.nearPlane = current->camera.nearPlane;
if (next->camera.nearPlane > next->camera.farPlane) {
next->camera.nearPlane = next->camera.farPlane;
}
}
next->currentDepth = current->currentDepth - 1;
next->viewport = renderPropsBuildViewport(next, renderState);
if (!next->viewport) {
return flags;
}
if (!cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, next->viewport, &next->cameraMatrixInfo)) {
return flags;
}
if (current->clippingPortalIndex == -1) {
// set the near clipping plane to be the exit portal surface
quatMultVector(&intoPortal->rotation, &gForward, &next->cameraMatrixInfo.cullingInformation.clippingPlanes[4].normal);
if (intoPortal < exitPortal) {
vector3Negate(&next->cameraMatrixInfo.cullingInformation.clippingPlanes[4].normal, &next->cameraMatrixInfo.cullingInformation.clippingPlanes[4].normal);
}
next->cameraMatrixInfo.cullingInformation.clippingPlanes[4].d = -vector3Dot(&next->cameraMatrixInfo.cullingInformation.clippingPlanes[4].normal, &intoPortal->position) * SCENE_SCALE;
}
next->clippingPortalIndex = -1;
next->exitPortalIndex = exitPortalIndex;
next->fromRoom = gCollisionScene.portalRooms[next->exitPortalIndex];
++renderPlan->stageCount;
next->previousProperties = current;
next->portalRenderType = 0;
renderPlanFinishView(renderPlan, scene, next, renderState);
return flags | PORTAL_RENDER_TYPE_ENABLED(portalIndex);
}
void renderPlanFinishView(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderProps* properties, struct RenderState* renderState) {
staticRenderDetermineVisibleRooms(&properties->cameraMatrixInfo.cullingInformation, properties->fromRoom, &properties->visiblerooms);
int closerPortal = vector3DistSqrd(&properties->camera.transform.position, &scene->portals[0].transform.position) > vector3DistSqrd(&properties->camera.transform.position, &scene->portals[1].transform.position) ? 0 : 1;
int otherPortal = 1 - closerPortal;
for (int i = 0; i < 2; ++i) {
if (gCollisionScene.portalTransforms[closerPortal] &&
properties->exitPortalIndex != closerPortal &&
staticRenderIsRoomVisible(properties->visiblerooms, gCollisionScene.portalRooms[closerPortal])) {
properties->portalRenderType |= renderPlanPortal(
renderPlan,
scene,
properties,
closerPortal,
renderState
);
}
closerPortal = 1 - closerPortal;
otherPortal = 1 - otherPortal;
}
}
void renderPlanBuild(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderState* renderState) {
renderPropsInit(&renderPlan->stageProps[0], &scene->camera, (float)SCREEN_WD / (float)SCREEN_HT, renderState, scene->player.body.currentRoom);
renderPlan->stageProps[0].camera = scene->camera;
renderPlan->stageCount = 1;
renderPlanFinishView(renderPlan, scene, &renderPlan->stageProps[0], renderState);
}
void renderPlanExecute(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderState* renderState) {
for (int i = renderPlan->stageCount - 1; i >= 0; --i) {
struct RenderProps* current = &renderPlan->stageProps[i];
if (!cameraApplyMatrices(renderState, &current->cameraMatrixInfo)) {
return;
}
gSPViewport(renderState->dl++, current->viewport);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, current->minX, current->minY, current->maxX, current->maxY);
for (int i = 0; i < 2; ++i) {
if ((current->portalRenderType & (PORTAL_RENDER_TYPE_VISIBLE(i) | PORTAL_RENDER_TYPE_ENABLED(i))) == PORTAL_RENDER_TYPE_VISIBLE(i)) {
float portalTransform[4][4];
struct Portal* portal = &scene->portals[i];
portalDetermineTransform(portal, portalTransform);
portalRenderCover(portal, portalTransform, renderState);
}
}
staticRender(&current->camera.transform, &current->cameraMatrixInfo.cullingInformation, current->visiblerooms, renderState);
if (current->previousProperties && (current->previousProperties->portalRenderType & PORTAL_RENDER_TYPE_VISIBLE(1 - current->exitPortalIndex))) {
gSPMatrix(renderState->dl++, osVirtualToPhysical(current->previousProperties->cameraMatrixInfo.projectionView), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
gSPPerspNormalize(renderState->dl++, current->previousProperties->cameraMatrixInfo.perspectiveNormalize);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, current->previousProperties->minX, current->previousProperties->minY, current->previousProperties->maxX, current->previousProperties->maxY);
gSPViewport(renderState->dl++, current->previousProperties->viewport);
float portalTransform[4][4];
struct Portal* portal = &scene->portals[i];
portalDetermineTransform(portal, portalTransform);
// render the front portal cover
Mtx* matrix = renderStateRequestMatrices(renderState, 1);
if (!matrix) {
return;
}
guMtxF2L(portalTransform, matrix);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
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(current->clipper.nearPolygon, current->clipper.nearPolygonCount, current, renderState);
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_blue_model_gfx);
} else {
gSPDisplayList(renderState->dl++, portal_portal_orange_face_model_gfx);
portalRenderScreenCover(current->clipper.nearPolygon, current->clipper.nearPolygonCount, current, renderState);
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_orange_model_gfx);
}
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}
}
}

17
src/scene/render_plan.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef __SCENE_RENDER_PLAN_H__
#define __SCENE_RENDER_PLAN_H__
#include "./scene.h"
#define MAX_PORTAL_STEPS 6
struct RenderPlan {
struct RenderProps stageProps[MAX_PORTAL_STEPS];
short stageCount;
};
void renderPlanBuild(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderState* renderState);
void renderPlanExecute(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderState* renderState);
#endif

View file

@ -130,7 +130,7 @@ void sceneRenderWithProperties(void* data, struct RenderProps* properties, struc
for (int i = 0; i < 2; ++i) {
if (gCollisionScene.portalTransforms[closerPortal] &&
properties->fromPortalIndex != closerPortal &&
properties->exitPortalIndex != closerPortal &&
staticRenderIsRoomVisible(visibleRooms, gCollisionScene.portalRooms[closerPortal])) {
portalRender(
&scene->portals[closerPortal],