Only keep one clipper result in the render plan

This commit is contained in:
James Lambert 2022-11-14 20:59:21 -07:00
parent d824c42317
commit f10fc3ef95
8 changed files with 223 additions and 402 deletions

View file

@ -203,6 +203,8 @@ build/src/scene/pedestal.o: $(MODEL_HEADERS)
build/src/scene/render_plan.o: $(MODEL_HEADERS)
build/src/scene/portal_render.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

@ -37,10 +37,6 @@ struct Vector3 gPortalOutline[PORTAL_LOOP_SIZE] = {
{-0.353553f * SCENE_SCALE * PORTAL_COVER_WIDTH, 0.707107f * SCENE_SCALE * PORTAL_COVER_HEIGHT, 0},
};
struct Quaternion gVerticalFlip = {0.0f, 1.0f, 0.0f, 0.0f};
#define STARTING_RENDER_DEPTH 2
#define PORTAL_CLIPPING_PLANE_BIAS (SCENE_SCALE * 0.25f)
#define CAMERA_CLIPPING_RADIUS 0.2f
@ -106,128 +102,6 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
props->portalRenderType = 0;
}
#define MIN_VP_WIDTH 64
void renderPropscheckViewportSize(int* min, int* max, int screenSize) {
if (*max < MIN_VP_WIDTH) {
*max = MIN_VP_WIDTH;
}
if (*min > screenSize - MIN_VP_WIDTH) {
*min = screenSize - MIN_VP_WIDTH;
}
int widthGrowBy = MIN_VP_WIDTH - (*max - *min);
if (widthGrowBy > 0) {
*min -= widthGrowBy >> 1;
*max += (widthGrowBy + 1) >> 1;
}
}
int renderPropsZDistance(int currentDepth) {
if (currentDepth >= STARTING_RENDER_DEPTH) {
return 0;
} else if (currentDepth < 0) {
return G_MAXZ;
} else {
return G_MAXZ - (G_MAXZ >> (STARTING_RENDER_DEPTH - currentDepth));
}
}
Vp* renderPropsBuildViewport(struct RenderProps* props, struct RenderState* renderState) {
int minX = props->minX;
int maxX = props->maxX;
int minY = props->minY;
int maxY = props->maxY;
int minZ = renderPropsZDistance(props->currentDepth);
int maxZ = renderPropsZDistance(props->currentDepth - 1);
renderPropscheckViewportSize(&minX, &maxX, SCREEN_WD);
renderPropscheckViewportSize(&minY, &maxY, SCREEN_HT);
Vp* viewport = renderStateRequestViewport(renderState);
if (!viewport) {
return NULL;
}
viewport->vp.vscale[0] = (maxX - minX) << 1;
viewport->vp.vscale[1] = (maxY - minY) << 1;
viewport->vp.vscale[2] = (maxZ - minZ) >> 1;
viewport->vp.vscale[3] = 0;
viewport->vp.vtrans[0] = (maxX + minX) << 1;
viewport->vp.vtrans[1] = (maxY + minY) << 1;
viewport->vp.vtrans[2] = (maxZ + minZ) >> 1;
viewport->vp.vtrans[3] = 0;
return viewport;
}
int renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState) {
struct Transform otherInverse;
transformInvert(fromPortal, &otherInverse);
struct Transform portalCombined;
transformConcat(toPortal, &otherInverse, &portalCombined);
next->camera = current->camera;
next->aspectRatio = current->aspectRatio;
transformConcat(&portalCombined, &current->camera.transform, &next->camera.transform);
struct Vector3 portalOffset;
vector3Sub(&toPortal->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;
Vp* viewport = renderPropsBuildViewport(next, renderState);
if (!viewport) {
return 0;
}
next->viewport = viewport;
if (!cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, viewport, &next->cameraMatrixInfo)) {
return 0;
}
if (!cameraApplyMatrices(renderState, &next->cameraMatrixInfo)) {
return 0;
}
if (current->clippingPortalIndex == -1) {
// set the near clipping plane to be the exit portal surface
quatMultVector(&toPortal->rotation, &gForward, &next->cameraMatrixInfo.cullingInformation.clippingPlanes[4].normal);
if (toPortal < fromPortal) {
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, &toPortal->position) * SCENE_SCALE;
}
next->clippingPortalIndex = -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);
return 1;
}
void portalInit(struct Portal* portal, enum PortalFlags flags) {
transformInitIdentity(&portal->transform);
portal->flags = flags;
@ -262,215 +136,6 @@ void portalUpdate(struct Portal* portal, int isOpen) {
}
}
void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct RenderProps* props, struct RenderState* renderState) {
if (pointCount == 0) {
return;
}
gDPPipeSync(renderState->dl++);
gDPSetDepthSource(renderState->dl++, G_ZS_PRIM);
gDPSetPrimDepth(renderState->dl++, 0, 0);
gDPSetRenderMode(renderState->dl++, CLR_ON_CVG | FORCE_BL | IM_RD | Z_CMP | Z_UPD | CVG_DST_WRAP | ZMODE_OPA | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), CLR_ON_CVG | FORCE_BL | IM_RD | Z_CMP | Z_UPD | CVG_DST_WRAP | ZMODE_OPA | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA));
gDPSetCombineLERP(renderState->dl++, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE);
if (controllerGetButton(1, D_CBUTTONS)) {
gDPSetPrimColor(renderState->dl++, 255, 255, 0, 0, 0, 128);
}
Mtx* idenity = renderStateRequestMatrices(renderState, 1);
if (!idenity) {
return;
}
guMtxIdent(idenity);
gSPMatrix(renderState->dl++, idenity, G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_PUSH);
Mtx* ortho = renderStateRequestMatrices(renderState, 1);
if (!ortho) {
return;
}
guOrtho(ortho, 0, SCREEN_WD << 2, 0, SCREEN_HT << 2, -10, 10, 1);
gSPMatrix(renderState->dl++, ortho, G_MTX_LOAD | G_MTX_PROJECTION | G_MTX_NOPUSH);
Vtx* vertices = renderStateRequestVertices(renderState, pointCount);
if (!vertices) {
return;
}
for (int i = 0; i < pointCount; ++i) {
Vtx* vertex = &vertices[i];
vertex->v.ob[0] = points[i].x;
vertex->v.ob[1] = points[i].y;
vertex->v.ob[2] = 0;
vertex->v.flag = 0;
vertex->v.tc[0] = 0;
vertex->v.tc[1] = 0;
vertex->v.cn[0] = 255;
vertex->v.cn[1] = 255;
vertex->v.cn[2] = 255;
vertex->v.cn[3] = 255;
}
gSPVertex(renderState->dl++, vertices, pointCount, 0);
for (int i = 2; i < pointCount; i += 2) {
if (i + 1 < pointCount) {
gSP2Triangles(renderState->dl++, 0, i - 1, i, 0, 0, i, i + 1, 0);
} else {
gSP1Triangle(renderState->dl++, 0, i - 1, i, 0);
}
}
gDPPipeSync(renderState->dl++);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
gSPMatrix(renderState->dl++, props->cameraMatrixInfo.projectionView, G_MTX_LOAD | G_MTX_PROJECTION | G_MTX_NOPUSH);
gDPSetDepthSource(renderState->dl++, G_ZS_PIXEL);
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);
if (!matrix) {
return;
}
guMtxF2L(portalTransform, matrix);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
if (portal->flags & PortalFlagsOddParity) {
gSPDisplayList(renderState->dl++, portal_portal_blue_filled_model_gfx);
} else {
gSPDisplayList(renderState->dl++, portal_portal_orange_filled_model_gfx);
}
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}
void portalRender(struct Portal* portal, struct Portal* otherPortal, struct RenderProps* props, SceneRenderCallback sceneRenderer, void* data, struct RenderState* renderState) {
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(&props->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;
}
struct ScreenClipper clipper;
float portalTransform[4][4];
portalDetermineTransform(portal, portalTransform);
if (props->currentDepth == 0 || !otherPortal) {
portalRenderCover(portal, portalTransform, renderState);
return;
}
struct RenderProps nextProps;
int portalIndex = portal < otherPortal ? 0 : 1;
screenClipperInitWithCamera(&clipper, &props->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct Box2D clippingBounds;
screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
if (props->clippingPortalIndex == portalIndex) {
nextProps.minX = 0;
nextProps.maxX = SCREEN_WD;
nextProps.minY = 0;
nextProps.maxY = SCREEN_HT;
} else {
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) {
if (!renderPropsNext(props, &nextProps, &portal->transform, &otherPortal->transform, renderState)) {
portalRenderCover(portal, portalTransform, renderState);
return;
}
sceneRenderer(data, &nextProps, renderState);
// revert to previous state
gSPMatrix(renderState->dl++, osVirtualToPhysical(props->cameraMatrixInfo.projectionView), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
gSPPerspNormalize(renderState->dl++, props->cameraMatrixInfo.perspectiveNormalize);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, props->minX, props->minY, props->maxX, props->maxY);
gSPViewport(renderState->dl++, props->viewport);
// 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) {
if (!controllerGetButton(1, L_CBUTTONS)) {
gSPDisplayList(renderState->dl++, portal_portal_blue_face_model_gfx);
if (!controllerGetButton(1, U_CBUTTONS)) {
portalRenderScreenCover(clipper.nearPolygon, clipper.nearPolygonCount, props, renderState);
}
}
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_blue_model_gfx);
} else {
if (!controllerGetButton(1, L_CBUTTONS)) {
gSPDisplayList(renderState->dl++, portal_portal_orange_face_model_gfx);
if (!controllerGetButton(1, U_CBUTTONS)) {
portalRenderScreenCover(clipper.nearPolygon, clipper.nearPolygonCount, props, renderState);
}
}
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_orange_model_gfx);
}
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}
}
int portalAttachToSurface(struct Portal* portal, struct PortalSurface* surface, int surfaceIndex, struct Transform* portalAt) {
// determine if portal is on surface
if (!portalSurfaceIsInside(surface, portalAt)) {

View file

@ -8,9 +8,8 @@
#include "camera.h"
#include "static_scene.h"
#include "./portal_surface.h"
#include "../graphics/screen_clipper.h"
#define STARTING_RENDER_DEPTH 2
#define PORTAL_LOOP_SIZE 8
enum PortalFlags {
@ -45,6 +44,8 @@ typedef void SceneRenderCallback(void* data, struct RenderProps* properties, str
#define PORTAL_RENDER_TYPE_VISIBLE(portalIndex) (PORTAL_RENDER_TYPE_VISIBLE_0 << (portalIndex))
#define PORTAL_RENDER_TYPE_ENABLED(portalIndex) (PORTAL_RENDER_TYPE_ENABLED_0 << (portalIndex))
extern struct Vector3 gPortalOutline[PORTAL_LOOP_SIZE];
struct RenderProps {
struct Camera camera;
float aspectRatio;
@ -69,17 +70,12 @@ struct RenderProps {
struct RenderProps* previousProperties;
struct RenderProps* nextProperites[2];
struct ScreenClipper clipper;
};
void renderPropsInit(struct RenderProps* props, struct Camera* camera, float aspectRatio, struct RenderState* renderState, u16 roomIndex);
int 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);
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);

110
src/scene/portal_render.c Normal file
View file

@ -0,0 +1,110 @@
#include "portal_render.h"
#include "../defs.h"
#include "../graphics/graphics.h"
#include "../build/assets/models/portal/portal_blue_filled.h"
#include "../build/assets/models/portal/portal_orange_filled.h"
struct Quaternion gVerticalFlip = {0.0f, 1.0f, 0.0f, 0.0f};
void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct RenderProps* props, struct RenderState* renderState) {
if (pointCount == 0) {
return;
}
gDPPipeSync(renderState->dl++);
gDPSetDepthSource(renderState->dl++, G_ZS_PRIM);
gDPSetPrimDepth(renderState->dl++, 0, 0);
gDPSetRenderMode(renderState->dl++, CLR_ON_CVG | FORCE_BL | IM_RD | Z_CMP | Z_UPD | CVG_DST_WRAP | ZMODE_OPA | GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA), CLR_ON_CVG | FORCE_BL | IM_RD | Z_CMP | Z_UPD | CVG_DST_WRAP | ZMODE_OPA | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA));
gDPSetCombineLERP(renderState->dl++, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE);
Mtx* idenity = renderStateRequestMatrices(renderState, 1);
if (!idenity) {
return;
}
guMtxIdent(idenity);
gSPMatrix(renderState->dl++, idenity, G_MTX_LOAD | G_MTX_MODELVIEW | G_MTX_PUSH);
Mtx* ortho = renderStateRequestMatrices(renderState, 1);
if (!ortho) {
return;
}
guOrtho(ortho, 0, SCREEN_WD << 2, 0, SCREEN_HT << 2, -10, 10, 1);
gSPMatrix(renderState->dl++, ortho, G_MTX_LOAD | G_MTX_PROJECTION | G_MTX_NOPUSH);
Vtx* vertices = renderStateRequestVertices(renderState, pointCount);
if (!vertices) {
return;
}
for (int i = 0; i < pointCount; ++i) {
Vtx* vertex = &vertices[i];
vertex->v.ob[0] = points[i].x;
vertex->v.ob[1] = points[i].y;
vertex->v.ob[2] = 0;
vertex->v.flag = 0;
vertex->v.tc[0] = 0;
vertex->v.tc[1] = 0;
vertex->v.cn[0] = 255;
vertex->v.cn[1] = 255;
vertex->v.cn[2] = 255;
vertex->v.cn[3] = 255;
}
gSPVertex(renderState->dl++, vertices, pointCount, 0);
for (int i = 2; i < pointCount; i += 2) {
if (i + 1 < pointCount) {
gSP2Triangles(renderState->dl++, 0, i - 1, i, 0, 0, i, i + 1, 0);
} else {
gSP1Triangle(renderState->dl++, 0, i - 1, i, 0);
}
}
gDPPipeSync(renderState->dl++);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
gSPMatrix(renderState->dl++, props->cameraMatrixInfo.projectionView, G_MTX_LOAD | G_MTX_PROJECTION | G_MTX_NOPUSH);
gDPSetDepthSource(renderState->dl++, G_ZS_PIXEL);
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);
if (!matrix) {
return;
}
guMtxF2L(portalTransform, matrix);
gSPMatrix(renderState->dl++, matrix, G_MTX_MODELVIEW | G_MTX_PUSH | G_MTX_MUL);
if (portal->flags & PortalFlagsOddParity) {
gSPDisplayList(renderState->dl++, portal_portal_blue_filled_model_gfx);
} else {
gSPDisplayList(renderState->dl++, portal_portal_orange_filled_model_gfx);
}
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
}

12
src/scene/portal_render.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef __SCENE_PORTAL_RENDER_H__
#define __SCENE_PORTAL_RENDER_H__
#include "../math/vector2s16.h"
#include "portal.h"
#include "../graphics/renderstate.h"
void portalRenderScreenCover(struct Vector2s16* points, int pointCount, struct RenderProps* props, struct RenderState* renderState);
void portalDetermineTransform(struct Portal* portal, float portalTransform[4][4]);
void portalRenderCover(struct Portal* portal, float portalTransform[4][4], struct RenderState* renderState);
#endif

View file

@ -5,19 +5,77 @@
#include "../physics/collision_scene.h"
#include "../levels/static_render.h"
#include "../util/memory.h"
#include "portal_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);
#define MIN_VP_WIDTH 64
void renderPropscheckViewportSize(int* min, int* max, int screenSize) {
if (*max < MIN_VP_WIDTH) {
*max = MIN_VP_WIDTH;
}
if (*min > screenSize - MIN_VP_WIDTH) {
*min = screenSize - MIN_VP_WIDTH;
}
int widthGrowBy = MIN_VP_WIDTH - (*max - *min);
if (widthGrowBy > 0) {
*min -= widthGrowBy >> 1;
*max += (widthGrowBy + 1) >> 1;
}
}
int renderPropsZDistance(int currentDepth) {
if (currentDepth >= STARTING_RENDER_DEPTH) {
return 0;
} else if (currentDepth < 0) {
return G_MAXZ;
} else {
return G_MAXZ - (G_MAXZ >> (STARTING_RENDER_DEPTH - currentDepth));
}
}
Vp* renderPropsBuildViewport(struct RenderProps* props, struct RenderState* renderState) {
int minX = props->minX;
int maxX = props->maxX;
int minY = props->minY;
int maxY = props->maxY;
int minZ = renderPropsZDistance(props->currentDepth);
int maxZ = renderPropsZDistance(props->currentDepth - 1);
renderPropscheckViewportSize(&minX, &maxX, SCREEN_WD);
renderPropscheckViewportSize(&minY, &maxY, SCREEN_HT);
Vp* viewport = renderStateRequestViewport(renderState);
if (!viewport) {
return NULL;
}
viewport->vp.vscale[0] = (maxX - minX) << 1;
viewport->vp.vscale[1] = (maxY - minY) << 1;
viewport->vp.vscale[2] = (maxZ - minZ) >> 1;
viewport->vp.vscale[3] = 0;
viewport->vp.vtrans[0] = (maxX + minX) << 1;
viewport->vp.vtrans[1] = (maxY + minY) << 1;
viewport->vp.vtrans[2] = (maxZ + minZ) >> 1;
viewport->vp.vtrans[3] = 0;
return viewport;
}
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))
@ -53,9 +111,17 @@ int renderPlanPortal(struct RenderPlan* renderPlan, struct Scene* scene, struct
struct RenderProps* next = &renderPlan->stageProps[renderPlan->stageCount];
screenClipperInitWithCamera(&next->clipper, &current->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct ScreenClipper clipper;
screenClipperInitWithCamera(&clipper, &current->camera, (float)SCREEN_WD / (float)SCREEN_HT, portalTransform);
struct Box2D clippingBounds;
screenClipperBoundingPoints(&next->clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
screenClipperBoundingPoints(&clipper, gPortalOutline, sizeof(gPortalOutline) / sizeof(*gPortalOutline), &clippingBounds);
if (clipper.nearPolygonCount) {
renderPlan->nearPolygonCount = clipper.nearPolygonCount;
memCopy(renderPlan->nearPolygon, clipper.nearPolygon, sizeof(struct Vector2s16) * clipper.nearPolygonCount);
renderPlan->clippedPortalIndex = portalIndex;
}
if (current->clippingPortalIndex == portalIndex) {
next->minX = 0;
@ -193,6 +259,8 @@ void renderPlanFinishView(struct RenderPlan* renderPlan, struct Scene* scene, st
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->stageCount = 1;
renderPlan->clippedPortalIndex = -1;
renderPlan->nearPolygonCount = 0;
renderPlanFinishView(renderPlan, scene, &renderPlan->stageProps[0], renderState);
}
@ -231,19 +299,24 @@ void renderPlanExecute(struct RenderPlan* renderPlan, struct Scene* scene, struc
gDPSetEnvColor(renderState->dl++, 255, 255, 255, portal->opacity < 0.0f ? 0 : (portal->opacity > 1.0f ? 255 : (u8)(portal->opacity * 255.0f)));
Gfx* faceModel;
Gfx* portalModel;
if (portal->flags & PortalFlagsOddParity) {
gSPDisplayList(renderState->dl++, portal_portal_blue_face_model_gfx);
portalRenderScreenCover(portalProps->clipper.nearPolygon, portalProps->clipper.nearPolygonCount, current, renderState);
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_blue_model_gfx);
faceModel = portal_portal_blue_face_model_gfx;
portalModel = portal_portal_blue_model_gfx;
} else {
gSPDisplayList(renderState->dl++, portal_portal_orange_face_model_gfx);
portalRenderScreenCover(portalProps->clipper.nearPolygon, portalProps->clipper.nearPolygonCount, current, renderState);
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portal_portal_orange_model_gfx);
faceModel = portal_portal_orange_face_model_gfx;
portalModel = portal_portal_orange_model_gfx;
}
gSPDisplayList(renderState->dl++, faceModel);
if (current->previousProperties == NULL && portalIndex == renderPlan->clippedPortalIndex && renderPlan->nearPolygonCount) {
portalRenderScreenCover(renderPlan->nearPolygon, renderPlan->nearPolygonCount, current, renderState);
}
gDPPipeSync(renderState->dl++);
gSPDisplayList(renderState->dl++, portalModel);
gSPPopMatrix(renderState->dl++, G_MTX_MODELVIEW);
} else {

View file

@ -2,12 +2,16 @@
#define __SCENE_RENDER_PLAN_H__
#include "./scene.h"
#include "../graphics/screen_clipper.h"
#define MAX_PORTAL_STEPS 6
struct RenderPlan {
struct RenderProps stageProps[MAX_PORTAL_STEPS];
short stageCount;
short clippedPortalIndex;
short nearPolygonCount;
struct Vector2s16 nearPolygon[MAX_NEAR_POLYGON_SIZE];
};
void renderPlanBuild(struct RenderPlan* renderPlan, struct Scene* scene, struct RenderState* renderState);

View file

@ -120,40 +120,6 @@ void sceneInit(struct Scene* scene) {
scene->freeCameraOffset = gZeroVec;
}
void sceneRenderWithProperties(void* data, struct RenderProps* properties, struct RenderState* renderState) {
struct Scene* scene = (struct Scene*)data;
u64 visibleRooms = 0;
staticRenderDetermineVisibleRooms(&properties->cameraMatrixInfo.cullingInformation, properties->fromRoom, &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(visibleRooms, gCollisionScene.portalRooms[closerPortal])) {
portalRender(
&scene->portals[closerPortal],
gCollisionScene.portalTransforms[otherPortal] ? &scene->portals[otherPortal] : NULL,
properties,
sceneRenderWithProperties,
data,
renderState
);
}
closerPortal = 1 - closerPortal;
otherPortal = 1 - otherPortal;
}
if (controllerGetButton(1, A_BUTTON) && properties->currentDepth == 2) {
return;
}
staticRender(&properties->camera.transform, &properties->cameraMatrixInfo.cullingInformation, visibleRooms, renderState);
}
#define SOLID_COLOR 0, 0, 0, ENVIRONMENT, 0, 0, 0, ENVIRONMENT
void sceneRenderPerformanceMetrics(struct Scene* scene, struct RenderState* renderState, struct GraphicsTask* task) {
@ -204,11 +170,6 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
*lookAt = gLookAt;
gSPLookAt(renderState->dl++, lookAt);
struct RenderProps renderProperties;
renderPropsInit(&renderProperties, &scene->camera, (float)SCREEN_WD / (float)SCREEN_HT, renderState, scene->player.body.currentRoom);
cameraApplyMatrices(renderState, &renderProperties.cameraMatrixInfo);
gDPSetRenderMode(renderState->dl++, G_RM_ZB_OPA_SURF, G_RM_ZB_OPA_SURF2);
@ -217,8 +178,6 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
renderPlanBuild(&renderPlan, scene, renderState);
renderPlanExecute(&renderPlan, scene, renderState);
// sceneRenderWithProperties(scene, &renderProperties, renderState);
sceneRenderPortalGun(scene, renderState);
gDPPipeSync(renderState->dl++);