|
|
@ -89,20 +89,27 @@ static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t |
|
|
// Check if the face is behind the camera |
|
|
// 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: 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... |
|
|
// TODO: or, just check against all corners of the face... |
|
|
short camDot = m_dot12(cam_vec, cam_dir); |
|
|
|
|
|
return camDot < 0; |
|
|
|
|
|
|
|
|
// const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex]; |
|
|
|
|
|
// for (int vertIdx = 0; vertIdx < face->numFaceVertices; ++vertIdx) |
|
|
|
|
|
// { |
|
|
|
|
|
// const ps1bsp_vertex_t *vert = &world->vertices[faceVertices[vertIdx].index]; |
|
|
|
|
|
// cam_vec.vx = vert->x - cam_pos.vx; |
|
|
|
|
|
// cam_vec.vy = vert->y - cam_pos.vy; |
|
|
|
|
|
// cam_vec.vz = vert->z - cam_pos.vz; |
|
|
|
|
|
// if (m_dot12(cam_vec, cam_dir) >= 0) |
|
|
|
|
|
// return 0; |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: disabling the behind-the-camera check does *not* actually solve the problem of polygons disappearing when too close to the camera! |
|
|
|
|
|
// This means that the GPU probably already clips polygons that stretch too far outside the drawing area. Tessellation should solve this. |
|
|
|
|
|
if (m_dot12(cam_vec, cam_dir) >= 0) |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
return 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void world_drawface_fast(const world_t *world, const ps1bsp_face_t *face, u_long *ot) |
|
|
static void world_drawface_fast(const world_t *world, const ps1bsp_face_t *face, u_long *ot) |
|
|
{ |
|
|
{ |
|
|
// Early primitive buffer check |
|
|
|
|
|
if (!mem_checkprim(sizeof(POLY_G4), face->totalQuads)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
short dot; |
|
|
|
|
|
if (world_cull_backface(world, face, &dot)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// Draw untextured, vertex colored faces, skipping the entire polygon tessellation step |
|
|
// Draw untextured, vertex colored faces, skipping the entire polygon tessellation step |
|
|
const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex]; |
|
|
const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex]; |
|
|
draw_quadstrip_colored(world->vertices, faceVertices, face->numFaceVertices, ot); |
|
|
draw_quadstrip_colored(world->vertices, faceVertices, face->numFaceVertices, ot); |
|
|
@ -110,14 +117,6 @@ static void world_drawface_fast(const world_t *world, const ps1bsp_face_t *face, |
|
|
|
|
|
|
|
|
static void world_drawface_lit(const world_t *world, const ps1bsp_face_t *face, u_long *ot) |
|
|
static void world_drawface_lit(const world_t *world, const ps1bsp_face_t *face, u_long *ot) |
|
|
{ |
|
|
{ |
|
|
// Early primitive buffer check |
|
|
|
|
|
if (!mem_checkprim(sizeof(POLY_G4), face->totalQuads)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
short dot; |
|
|
|
|
|
if (world_cull_backface(world, face, &dot)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// Draw untextured, vertex colored polygons |
|
|
// Draw untextured, vertex colored polygons |
|
|
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; |
|
|
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; |
|
|
for (u_char polyIdx = 0; polyIdx < face->numPolygons; ++polyIdx, ++poly) |
|
|
for (u_char polyIdx = 0; polyIdx < face->numPolygons; ++polyIdx, ++poly) |
|
|
@ -129,16 +128,6 @@ static void world_drawface_lit(const world_t *world, const ps1bsp_face_t *face, |
|
|
|
|
|
|
|
|
static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *face, u_long *ot) |
|
|
static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *face, u_long *ot) |
|
|
{ |
|
|
{ |
|
|
// Early primitive buffer check |
|
|
|
|
|
if (!mem_checkprim(sizeof(POLY_GT4), face->totalQuads)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: this value could be REALLY useful for determining the tessellation subdivisions. It has camera distance *and* angle in it. |
|
|
|
|
|
// Just include the face size/area for an approximate screen size. Maybe also separate x/y/z for angle-dependent tessellation. |
|
|
|
|
|
short dot; |
|
|
|
|
|
if (world_cull_backface(world, face, &dot)) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// Draw textured, vertex colored polygons |
|
|
// Draw textured, vertex colored polygons |
|
|
const ps1bsp_texture_t *texture = &world->textures[face->textureId]; |
|
|
const ps1bsp_texture_t *texture = &world->textures[face->textureId]; |
|
|
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; |
|
|
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; |
|
|
@ -170,6 +159,10 @@ static void world_drawFaces(const world_t *world, const ps1bsp_face_t *firstFace |
|
|
// 2) If we need to stop drawing because the primitive buffer is full, we'll only be culling distant faces. |
|
|
// 2) If we need to stop drawing because the primitive buffer is full, we'll only be culling distant faces. |
|
|
for (const ps1bsp_face_t *face = firstFace; face != NULL; face = face->nextFace) |
|
|
for (const ps1bsp_face_t *face = firstFace; face != NULL; face = face->nextFace) |
|
|
{ |
|
|
{ |
|
|
|
|
|
// Early primitive buffer check |
|
|
|
|
|
if (!mem_checkprim(sizeof(POLY_GT4), face->totalQuads)) |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
world_drawface(world, face, curOT); |
|
|
world_drawface(world, face, curOT); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -188,12 +181,19 @@ static ps1bsp_face_t *world_sortFaces(const world_t *world, const ps1bsp_leaf_t |
|
|
{ |
|
|
{ |
|
|
ps1bsp_face_t *face = &world->faces[leafFaces[leafFaceIdx]]; |
|
|
ps1bsp_face_t *face = &world->faces[leafFaces[leafFaceIdx]]; |
|
|
|
|
|
|
|
|
// Ensure we draw each face only once per frame |
|
|
|
|
|
|
|
|
// Make sure we draw each face only once per frame |
|
|
if (face->drawFrame == frameNum) |
|
|
if (face->drawFrame == frameNum) |
|
|
continue; |
|
|
continue; |
|
|
|
|
|
|
|
|
// Sort the faces to draw in front-to-back order |
|
|
|
|
|
face->drawFrame = frameNum; |
|
|
face->drawFrame = frameNum; |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: this value could be REALLY useful for determining the tessellation subdivisions. It has camera distance *and* angle in it. |
|
|
|
|
|
// Just include the face size/area for an approximate screen size. Maybe also separate x/y/z for angle-dependent tessellation. |
|
|
|
|
|
short dot; |
|
|
|
|
|
if (world_cull_backface(world, face, &dot)) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
// Sort the faces to draw in front-to-back order |
|
|
face->nextFace = firstFace; |
|
|
face->nextFace = firstFace; |
|
|
firstFace = face; |
|
|
firstFace = face; |
|
|
} |
|
|
} |
|
|
|