mirror of
https://github.com/mwpenny/portal64-still-alive.git
synced 2024-10-20 10:37:37 -04:00
Work on screen clipping
This commit is contained in:
parent
ba6fb4ed2b
commit
2eda4a3710
|
@ -29,45 +29,6 @@ void screenClipperInitWithCamera(struct ScreenClipper* clipper, struct Camera* c
|
|||
guMtxCatF(modelTransform, viewProjection, clipper->pointTransform);
|
||||
}
|
||||
|
||||
enum ClipperBounds {
|
||||
ClipperBoundsRight = (1 << 0),
|
||||
ClipperBoundsLeft = (1 << 1),
|
||||
ClipperBoundsUp = (1 << 2),
|
||||
ClipperBoundsDown = (1 << 3),
|
||||
ClipperBoundsFront = (1 << 4),
|
||||
ClipperBoundsW = (1 << 5),
|
||||
};
|
||||
|
||||
int screenClipperGetOutOfBounds(struct Vector4* transformed) {
|
||||
int result = 0;
|
||||
|
||||
if (transformed->x > transformed->w) {
|
||||
result |= ClipperBoundsRight;
|
||||
}
|
||||
|
||||
if (transformed->x < -transformed->w) {
|
||||
result |= ClipperBoundsLeft;
|
||||
}
|
||||
|
||||
if (transformed->y > transformed->w) {
|
||||
result |= ClipperBoundsUp;
|
||||
}
|
||||
|
||||
if (transformed->y < -transformed->w) {
|
||||
result |= ClipperBoundsDown;
|
||||
}
|
||||
|
||||
if (transformed->z < -transformed->w) {
|
||||
result |= ClipperBoundsFront;
|
||||
}
|
||||
|
||||
if (transformed->w <= 0.0001f) {
|
||||
result |= ClipperBoundsW;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float determineClippingDistance(float x0, float x1, float w0, float w1) {
|
||||
float denominator = (x1 - x0) - (w1 - w0);
|
||||
|
||||
|
@ -78,33 +39,6 @@ float determineClippingDistance(float x0, float x1, float w0, float w1) {
|
|||
return (w0 - x0) / denominator;
|
||||
}
|
||||
|
||||
void screenClipperClip(struct Vector4* from, struct Vector4* to, int clippingMask, struct Vector4* output) {
|
||||
float t = 1.0f;
|
||||
float check;
|
||||
|
||||
if ((clippingMask & ClipperBoundsRight) && (check = determineClippingDistance(from->x, to->x, from->w, to->w)) < t) {
|
||||
t = check;
|
||||
}
|
||||
|
||||
if ((clippingMask & ClipperBoundsLeft) && (check = determineClippingDistance(from->x, to->x, -from->w, -to->w)) < t) {
|
||||
t = check;
|
||||
}
|
||||
|
||||
if ((clippingMask & ClipperBoundsUp) && (check = determineClippingDistance(from->y, to->y, from->w, to->w)) < t) {
|
||||
t = check;
|
||||
}
|
||||
|
||||
if ((clippingMask & ClipperBoundsDown) && (check = determineClippingDistance(from->y, to->y, -from->w, -to->w)) < t) {
|
||||
t = check;
|
||||
}
|
||||
|
||||
if ((clippingMask & ClipperBoundsFront) && (check = determineClippingDistance(from->z, to->z, -from->w, -to->w)) < t) {
|
||||
t = check;
|
||||
}
|
||||
|
||||
vector4Lerp(from, to, t, output);
|
||||
}
|
||||
|
||||
void screenClipperIncludePoint(struct Vector4* point, struct Box2D* output) {
|
||||
struct Vector2 viewportPos;
|
||||
float invW = 1.0f / point->w;
|
||||
|
@ -115,6 +49,40 @@ void screenClipperIncludePoint(struct Vector4* point, struct Box2D* output) {
|
|||
vector2Max(&output->max, &viewportPos, &output->max);
|
||||
}
|
||||
|
||||
unsigned screenClipperClipBoundary(struct ScreenClipper* clipper, struct Vector4* input, struct Vector4* output, unsigned pointCount, int axis, int direction) {
|
||||
unsigned outputPointCount = 0;
|
||||
|
||||
struct Vector4* previous = &input[pointCount - 1];
|
||||
float pos = VECTOR3_AS_ARRAY(previous)[axis];
|
||||
float wReference = previous->w;
|
||||
int wasInside = (direction < 0 ? -pos : pos) < wReference;
|
||||
|
||||
for (unsigned i = 0; i < pointCount; ++i) {
|
||||
struct Vector4* current = &input[i];
|
||||
|
||||
pos = VECTOR3_AS_ARRAY(current)[axis];
|
||||
wReference = current->w;
|
||||
|
||||
int isInside = (direction < 0 ? -pos : pos) < wReference;
|
||||
|
||||
if (isInside != wasInside) {
|
||||
float lerp = determineClippingDistance(VECTOR3_AS_ARRAY(previous)[axis], pos, direction < 0 ? -previous->w : previous->w, direction < 0 ? -wReference : wReference);
|
||||
vector4Lerp(previous, current, lerp, &output[outputPointCount]);
|
||||
++outputPointCount;
|
||||
}
|
||||
|
||||
if (isInside) {
|
||||
output[outputPointCount] = input[i];
|
||||
++outputPointCount;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
wasInside = isInside;
|
||||
}
|
||||
|
||||
return outputPointCount;
|
||||
}
|
||||
|
||||
void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3* input, unsigned pointCount, struct Box2D* output) {
|
||||
vector2Scale(&gOneVec2, -1.0f, &output->max);
|
||||
output->min = gOneVec2;
|
||||
|
@ -123,50 +91,21 @@ void screenClipperBoundingPoints(struct ScreenClipper* clipper, struct Vector3*
|
|||
return;
|
||||
}
|
||||
|
||||
struct Vector4 previousPoint;
|
||||
matrixVec3Mul(clipper->pointTransform, &input[pointCount - 1], &previousPoint);
|
||||
int prevIsClipped = screenClipperGetOutOfBounds(&previousPoint);
|
||||
struct Vector4 clipBuffer[16];
|
||||
struct Vector4 clipBufferSwap[16];
|
||||
|
||||
for (unsigned i = 0; i < pointCount; ++i) {
|
||||
struct Vector4 transformedPoint;
|
||||
matrixVec3Mul(clipper->pointTransform, &input[i], &clipBuffer[i]);
|
||||
}
|
||||
|
||||
matrixVec3Mul(clipper->pointTransform, &input[i], &transformedPoint);
|
||||
pointCount = screenClipperClipBoundary(clipper, clipBuffer, clipBufferSwap, pointCount, 0, 1);
|
||||
pointCount = screenClipperClipBoundary(clipper, clipBufferSwap, clipBuffer, pointCount, 0, -1);
|
||||
pointCount = screenClipperClipBoundary(clipper, clipBuffer, clipBufferSwap, pointCount, 1, 1);
|
||||
pointCount = screenClipperClipBoundary(clipper, clipBufferSwap, clipBuffer, pointCount, 1, -1);
|
||||
pointCount = screenClipperClipBoundary(clipper, clipBuffer, clipBufferSwap, pointCount, 2, -1);
|
||||
|
||||
int isClipped = screenClipperGetOutOfBounds(&transformedPoint);
|
||||
|
||||
int clippedBoundary = prevIsClipped | isClipped;
|
||||
|
||||
if (clippedBoundary && (!isClipped || !prevIsClipped)) {
|
||||
struct Vector4 clipped;
|
||||
if (isClipped) {
|
||||
screenClipperClip(&previousPoint, &transformedPoint, clippedBoundary, &clipped);
|
||||
} else {
|
||||
screenClipperClip(&transformedPoint, &previousPoint, clippedBoundary, &clipped);
|
||||
}
|
||||
|
||||
screenClipperIncludePoint(&clipped, output);
|
||||
}
|
||||
|
||||
if (!isClipped) {
|
||||
screenClipperIncludePoint(&transformedPoint, output);
|
||||
} else {
|
||||
if (!(isClipped & ClipperBoundsW)) {
|
||||
if (isClipped & ClipperBoundsLeft) {
|
||||
output->min.x = -1.0f;
|
||||
} else if (isClipped & ClipperBoundsRight) {
|
||||
output->max.x = 1.0f;
|
||||
}
|
||||
|
||||
if (isClipped & ClipperBoundsDown) {
|
||||
output->min.y = -1.0f;
|
||||
} else if (isClipped & ClipperBoundsUp) {
|
||||
output->max.y = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
previousPoint = transformedPoint;
|
||||
prevIsClipped = isClipped;
|
||||
for (unsigned i = 0; i < pointCount; ++i) {
|
||||
screenClipperIncludePoint(&clipBufferSwap[i], output);
|
||||
}
|
||||
|
||||
struct Vector2 negativeOne;
|
||||
|
|
|
@ -9,9 +9,15 @@ struct StaticContentElement {
|
|||
u8 materialIndex;
|
||||
};
|
||||
|
||||
struct BoundingSphere {
|
||||
short x, y, z;
|
||||
short radius;
|
||||
};
|
||||
|
||||
struct LevelDefinition {
|
||||
struct CollisionObject* collisionQuads;
|
||||
struct StaticContentElement *staticContent;
|
||||
struct BoundingSphere* boundingSpheres;
|
||||
struct PortalSurface* portalSurfaces;
|
||||
// maps index of a collisionQuads to indices in portalSurfaces
|
||||
struct PortalSurfaceMapping* portalSurfaceMapping;
|
||||
|
|
|
@ -45,6 +45,35 @@ void renderPropsInit(struct RenderProps* props, struct Camera* camera, float asp
|
|||
props->maxY = SCREEN_HT;
|
||||
}
|
||||
|
||||
#define MIN_VP_WIDTH 40
|
||||
|
||||
Vp* renderPropsBuildViewport(struct RenderProps* props, struct RenderState* renderState) {
|
||||
int minX = props->minX;
|
||||
int maxX = props->maxX;
|
||||
|
||||
if (maxX < MIN_VP_WIDTH) {
|
||||
maxX = MIN_VP_WIDTH;
|
||||
}
|
||||
|
||||
if (minX > SCREEN_WD - MIN_VP_WIDTH) {
|
||||
minX = SCREEN_WD - MIN_VP_WIDTH;
|
||||
}
|
||||
|
||||
Vp* viewport = renderStateRequestViewport(renderState);
|
||||
|
||||
viewport->vp.vscale[0] = (maxX - minX) << 1;
|
||||
viewport->vp.vscale[1] = (props->maxY - props->minY) << 1;
|
||||
viewport->vp.vscale[2] = G_MAXZ/2;
|
||||
viewport->vp.vscale[3] = 0;
|
||||
|
||||
viewport->vp.vtrans[0] = (maxX + minX) << 1;
|
||||
viewport->vp.vtrans[1] = (props->maxY + props->minY) << 1;
|
||||
viewport->vp.vtrans[2] = G_MAXZ/2;
|
||||
viewport->vp.vtrans[3] = 0;
|
||||
|
||||
return viewport;
|
||||
}
|
||||
|
||||
void renderPropsNext(struct RenderProps* current, struct RenderProps* next, struct Transform* fromPortal, struct Transform* toPortal, struct RenderState* renderState) {
|
||||
struct Transform otherInverse;
|
||||
transformInvert(fromPortal, &otherInverse);
|
||||
|
@ -59,17 +88,7 @@ void renderPropsNext(struct RenderProps* current, struct RenderProps* next, stru
|
|||
cameraSetupMatrices(&next->camera, renderState, next->aspectRatio, &next->perspectiveCorrect, current->viewport);
|
||||
dynamicSceneRender(renderState, 1);
|
||||
|
||||
Vp* viewport = renderStateRequestViewport(renderState);
|
||||
|
||||
viewport->vp.vscale[0] = (next->maxX - next->minX) << 1;
|
||||
viewport->vp.vscale[1] = (next->maxY - next->minY) << 1;
|
||||
viewport->vp.vscale[2] = G_MAXZ/2;
|
||||
viewport->vp.vscale[3] = 0;
|
||||
|
||||
viewport->vp.vtrans[0] = (next->maxX + next->minX) << 1;
|
||||
viewport->vp.vtrans[1] = (next->maxY + next->minY) << 1;
|
||||
viewport->vp.vtrans[2] = G_MAXZ/2;
|
||||
viewport->vp.vtrans[3] = 0;
|
||||
Vp* viewport = renderPropsBuildViewport(next, renderState);
|
||||
|
||||
next->viewport = viewport;
|
||||
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
#define __PORTAL_H__
|
||||
|
||||
#include "../math/transform.h"
|
||||
#include "../math/plane.h"
|
||||
#include "../graphics/renderstate.h"
|
||||
#include "camera.h"
|
||||
#include "static_scene.h"
|
||||
|
||||
|
||||
#define PORTAL_LOOP_SIZE 8
|
||||
|
||||
|
@ -27,6 +30,8 @@ struct RenderProps {
|
|||
float aspectRatio;
|
||||
Mtx* perspectiveMatrix;
|
||||
Vp* viewport;
|
||||
struct FrustrumCullingInformation cullingInfo;
|
||||
|
||||
u16 perspectiveCorrect;
|
||||
short currentDepth;
|
||||
|
||||
|
@ -34,6 +39,7 @@ struct RenderProps {
|
|||
short minY;
|
||||
short maxX;
|
||||
short maxY;
|
||||
|
||||
};
|
||||
|
||||
#define STARTING_RENDER_DEPTH 1
|
||||
|
|
|
@ -1 +1,18 @@
|
|||
#include "static_scene.h"
|
||||
#include "static_scene.h"
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingSphere* boundingSphere) {
|
||||
struct Vector3 spherePos;
|
||||
|
||||
spherePos.x = boundingSphere->x * (1.0f / SCENE_SCALE);
|
||||
spherePos.y = boundingSphere->y * (1.0f / SCENE_SCALE);
|
||||
spherePos.z = boundingSphere->z * (1.0f / SCENE_SCALE);
|
||||
|
||||
vector3Sub(&spherePos, &frustrum->cameraPosition, &spherePos);
|
||||
struct Vector3 crossDirection;
|
||||
vector3Cross(&frustrum->frustrumDirection, &spherePos, &crossDirection);
|
||||
|
||||
float distance = sqrtf(vector3MagSqrd(&crossDirection)) * frustrum->cosFrustumAngle - vector3Dot(&frustrum->frustrumDirection, &crossDirection) * frustrum->sinFrustrumAngle;
|
||||
return distance > boundingSphere->radius * (1.0f / SCENE_SCALE);
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include <ultra64.h>
|
||||
#include "../math/transform.h"
|
||||
#include "../math/box3d.h"
|
||||
#include "../levels/level_definition.h"
|
||||
|
||||
enum StaticSceneEntryFlags {
|
||||
StaticSceneEntryFlagsHidden,
|
||||
|
@ -30,6 +31,16 @@ struct StaticScene {
|
|||
u16 gridHeight;
|
||||
};
|
||||
|
||||
struct FrustrumCullingInformation {
|
||||
struct Plane nearPlane;
|
||||
struct Vector3 frustrumDirection;
|
||||
struct Vector3 cameraPosition;
|
||||
float cosFrustumAngle;
|
||||
float sinFrustrumAngle;
|
||||
};
|
||||
|
||||
void staticSceneInit();
|
||||
|
||||
int isOutsideFrustrum(struct FrustrumCullingInformation* frustrum, struct BoundingSphere* boundingSphere);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue