diff --git a/display.c b/display.c index 13dec1b..307c4a3 100644 --- a/display.c +++ b/display.c @@ -1,5 +1,6 @@ #include "common.h" #include "display.h" +#include "frustum.h" #include @@ -177,6 +178,9 @@ void display_start() // Compose view and projection matrices to obtain a combined view-projection matrix CompMatrixLV(&proj_matrix, &view_matrix, &vp_matrix); + + int screenheight = (GetVideoMode() == MODE_NTSC) ? SCREENHEIGHT_NTSC : SCREENHEIGHT_PAL; + frustum_update(&view_matrix, (SCREENWIDTH << 12) / aspect_scale.vx, (screenheight << 12) / aspect_scale.vy); } void display_finish() diff --git a/frustum.c b/frustum.c new file mode 100644 index 0000000..74969d2 --- /dev/null +++ b/frustum.c @@ -0,0 +1,56 @@ +#include "common.h" +#include "frustum.h" +#include "display.h" + +#include + +static SVECTOR left, right, top, bottom; + +static INLINE void frustum_buildPlane(MATRIX *view_matrix, VECTOR *normal, SVECTOR *outPlane) +{ + ApplyMatrixLV(view_matrix, normal, normal); + VectorNormalS(normal, outPlane); + outPlane->pad = m_dot12(cam_pos, *outPlane); +} + +void frustum_update(MATRIX *view_matrix, int width, int height) +{ + VECTOR l, r, t, b; + + int near; + gte_ReadGeomScreen(&near); + + //FntPrint(-1, "N = %d, W = %d, H = %d\n", near, width, height); + + // 2 * near, shifted left for division + near <<= 13; + + l.vx = near / width; + l.vy = ONE; + l.vz = 0; + + b.vx = 0; + b.vy = ONE; + b.vz = near / height; + + r.vx = -l.vx; + r.vy = ONE; + r.vz = 0; + + t.vx = 0; + t.vy = ONE; + t.vz = -b.vz; + + frustum_buildPlane(view_matrix, &l, &left); + frustum_buildPlane(view_matrix, &r, &right); + frustum_buildPlane(view_matrix, &t, &top); + frustum_buildPlane(view_matrix, &b, &bottom); + + // FntPrint(-1, "l = %d %d, r = %d %d, t = %d %d, b = %d %d\n", + // left.vx, left.pad, right.vx, right.pad, top.vz, top.pad, bottom.vz, bottom.pad); +} + +u_char frustum_checkSphere(SVECTOR *sphere) +{ + return 1; +} diff --git a/frustum.h b/frustum.h new file mode 100644 index 0000000..99f507c --- /dev/null +++ b/frustum.h @@ -0,0 +1,7 @@ +#ifndef __FRUSTUM_H__ +#define __FRUSTUM_H__ + +void frustum_update(MATRIX *view_matrix, int width, int height); +u_char frustum_checkSphere(SVECTOR *sphere); + +#endif // __FRUSTUM_H__ diff --git a/qmath.h b/qmath.h index 1839310..bd9ecd7 100644 --- a/qmath.h +++ b/qmath.h @@ -3,10 +3,7 @@ MATRIX *RotMatrixQ(SVECTOR *r, MATRIX *m); -INLINE int m_dot12s(const SVECTOR a, const SVECTOR b) -{ - return (((int)a.vx * b.vx) >> 12) + (((int)a.vy * b.vy) >> 12) + (((int)a.vz * b.vz) >> 12); -} +#define m_dot12(a, b) ((((int)(a).vx * (b).vx) >> 12) + (((int)(a).vy * (b).vy) >> 12) + (((int)(a).vz * (b).vz) >> 12)) // TODO: worth a benchmark: is it faster to copy these vectors and use them from the stack, or to do six pointer dereferences? INLINE int m_pointPlaneDist2(const VECTOR point2, const SVECTOR normal12, int dist2) diff --git a/world.c b/world.c index d34182b..c2d4518 100644 --- a/world.c +++ b/world.c @@ -66,7 +66,7 @@ static INLINE short world_planeDot(const SVECTOR *dir, const ps1bsp_plane_t *pla if (plane->type < 3) return ((short*)dir)[plane->type]; - return (short)m_dot12s(*dir, plane->normal); + return (short)m_dot12(*dir, plane->normal); } static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t *face, short *dot) @@ -78,8 +78,10 @@ static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t cam_vec.vy = face->center.vy - cam_pos.vy; cam_vec.vz = face->center.vz - cam_pos.vz; - // Check if the face is behind the camera - short camDot = m_dot12s(cam_vec, cam_dir); + // Check if the face is behind the camera + // TODO: this may cull faces close to the camera, use VectorNormalS to normalize and check for angles < -60 degrees + // TODO: or, just check against all corners of the face... + short camDot = m_dot12(cam_vec, cam_dir); if (camDot < 0) return 1; @@ -199,6 +201,7 @@ static void world_drawnode(const world_t *world, short nodeIdx, u_char *pvs) ps1bsp_face_t *face = &world->faces[*leafFace]; // Check if we've already drawn this face on the current frame + // NOTE: this can cause sorting issues when rendering front-to-back with leaf-based depth if (face->drawFrame == frameNum) continue; @@ -214,6 +217,7 @@ static void world_drawnode(const world_t *world, short nodeIdx, u_char *pvs) short dist = world_pointPlaneDist(&cam_pos, plane); // Draw child nodes in front-to-back order; adding faces to the OT will reverse the drawing order + // PLAN: traverse back-to-front to determine leaf order & depth, then draw faces front-to-back with primbuf checks char order = dist < 0; world_drawnode(world, node->children[order], pvs); world_drawnode(world, node->children[order ^ 1], pvs); @@ -282,8 +286,6 @@ static u_short world_leafAtPoint(const world_t *world, const VECTOR *point) void world_draw(const world_t *world) { - int p; - // The world doesn't move, so we just set the camera view-projection matrix gte_SetRotMatrix(&vp_matrix); gte_SetTransMatrix(&vp_matrix);