/* ================= R_BoxSurfaces_r ================= */ void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int *listbmodel, int listsize, int *listlength, vec3_t dir) { int s, c; int *mark; // do the tail recursion in a loop while ( !node->isLeaf ) { s = BoxOnPlaneSide( mins, maxs, node->plane ); if (s == 1) { node = node->children[0]; } else if (s == 2) { node = node->children[1]; } else { R_BoxSurfaces_r(node->children[0], mins, maxs, list, listbmodel, listsize, listlength, dir); node = node->children[1]; } } // add the individual surfaces mark = tr.world->marksurfaces + node->firstmarksurface; c = node->nummarksurfaces; while (c--) { // if (*listlength >= listsize) break; // R_AddSurfaceToList( 0, *mark, mins, maxs, list, listbmodel, listsize, listlength, dir ); mark++; } }
void R_BoxSurfaces_r(mnode_t *node, vector3 *mins, vector3 *maxs, surfaceType_t **list, int listsize, int *listlength, vector3 *dir) { int s, c; msurface_t *surf, **mark; // do the tail recursion in a loop while ( node->contents == -1 ) { s = BoxOnPlaneSide( mins, maxs, node->plane ); if (s == 1) { node = node->children[0]; } else if (s == 2) { node = node->children[1]; } else { R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); node = node->children[1]; } } // add the individual surfaces mark = node->firstmarksurface; c = node->nummarksurfaces; while (c--) { // if (*listlength >= listsize) break; // surf = *mark; //QtZ: optimization from UrT, this surface has already been checked if (surf->viewCount == tr.viewCount) continue; // check if the surface has NOIMPACT or NOMARKS set if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { surf->viewCount = tr.viewCount; } // extra check for surfaces to avoid list overflows else if (*(surf->data) == SF_FACE) { // the face plane should go through the box s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane ); if (s == 1 || s == 2) { surf->viewCount = tr.viewCount; } else if (DotProduct(&(( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5f) { // don't add faces that make sharp angles with the projection direction surf->viewCount = tr.viewCount; } } else if (*(surfaceType_t *) (surf->data) != SF_GRID && *(surfaceType_t *) (surf->data) != SF_TRIANGLES) surf->viewCount = tr.viewCount; // check the viewCount because the surface may have // already been added if it spans multiple leafs if (surf->viewCount != tr.viewCount) { surf->viewCount = tr.viewCount; list[*listlength] = (surfaceType_t *) surf->data; (*listlength)++; } mark++; } }
static void R_BoxSurfaces_r( mbrush46_node_t* node, vec3_t mins, vec3_t maxs, idWorldSurface** list, int listsize, int* listlength, vec3_t dir ) { // RF, if this node hasn't been rendered recently, ignore it if ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) && node->visframe < tr.visCount - 2 ) { // allow us to be a few frames behind return; } // do the tail recursion in a loop while ( node->contents == -1 ) { int s = BoxOnPlaneSide( mins, maxs, node->plane ); if ( s == 1 ) { node = node->children[ 0 ]; } else if ( s == 2 ) { node = node->children[ 1 ]; } else { R_BoxSurfaces_r( node->children[ 0 ], mins, maxs, list, listsize, listlength, dir ); node = node->children[ 1 ]; } } // Ridah, don't mark alpha surfaces if ( GGameType & ( GAME_WolfSP | GAME_WolfMP | GAME_ET ) && node->contents & BSP46CONTENTS_TRANSLUCENT ) { return; } // add the individual surfaces idWorldSurface** mark = node->firstmarksurface; int c = node->nummarksurfaces; while ( c-- ) { if ( *listlength >= listsize ) { break; } idWorldSurface* surf = *mark; if ( !surf->CheckAddMarks( mins, maxs, dir ) ) { surf->viewCount = tr.viewCount; } // check the viewCount because the surface may have // already been added if it spans multiple leafs if ( surf->viewCount != tr.viewCount ) { surf->viewCount = tr.viewCount; list[ *listlength ] = surf; ( *listlength )++; } mark++; } }
/* ================= R_MarkFragments ================= */ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { int numsurfaces, numPlanes; int i, j, k, m, n; surfaceType_t *surfaces[64]; vec3_t mins, maxs; int returnedFragments; int returnedPoints; vec3_t normals[MAX_VERTS_ON_POLY+2]; float dists[MAX_VERTS_ON_POLY+2]; vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; int numClipPoints; float *v; srfSurfaceFace_t *surf; srfGridMesh_t *cv; drawVert_t *dv; vec3_t normal; vec3_t projectionDir; vec3_t v1, v2; int *indexes; //increment view count for double check prevention tr.viewCount++; // VectorNormalize2( projection, projectionDir ); // find all the brushes that are to be considered ClearBounds( mins, maxs ); for ( i = 0 ; i < numPoints ; i++ ) { vec3_t temp; AddPointToBounds( points[i], mins, maxs ); VectorAdd( points[i], projection, temp ); AddPointToBounds( temp, mins, maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( points[i], -20, projectionDir, temp ); AddPointToBounds( temp, mins, maxs ); } if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; // create the bounding planes for the to be projected polygon for ( i = 0 ; i < numPoints ; i++ ) { VectorSubtract(points[(i+1)%numPoints], points[i], v1); VectorAdd(points[i], projection, v2); VectorSubtract(points[i], v2, v2); CrossProduct(v1, v2, normals[i]); VectorNormalizeFast(normals[i]); dists[i] = DotProduct(normals[i], points[i]); } // add near and far clipping planes for projection VectorCopy(projectionDir, normals[numPoints]); dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; VectorCopy(projectionDir, normals[numPoints+1]); VectorInverse(normals[numPoints+1]); dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; numPlanes = numPoints + 2; numsurfaces = 0; R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir); //assert(numsurfaces <= 64); //assert(numsurfaces != 64); returnedPoints = 0; returnedFragments = 0; for ( i = 0 ; i < numsurfaces ; i++ ) { if (*surfaces[i] == SF_GRID) { cv = (srfGridMesh_t *) surfaces[i]; for ( m = 0 ; m < cv->height - 1 ; m++ ) { for ( n = 0 ; n < cv->width - 1 ; n++ ) { // We triangulate the grid and chop all triangles within // the bounding planes of the to be projected polygon. // LOD is not taken into account, not such a big deal though. // // It's probably much nicer to chop the grid itself and deal // with this grid as a normal SF_GRID surface so LOD will // be applied. However the LOD of that chopped grid must // be synced with the LOD of the original curve. // One way to do this; the chopped grid shares vertices with // the original curve. When LOD is applied to the original // curve the unused vertices are flagged. Now the chopped curve // should skip the flagged vertices. This still leaves the // problems with the vertices at the chopped grid edges. // // To avoid issues when LOD applied to "hollow curves" (like // the ones around many jump pads) we now just add a 2 unit // offset to the triangle vertices. // The offset is added in the vertex normal vector direction // so all triangles will still fit together. // The 2 unit offset should avoid pretty much all LOD problems. numClipPoints = 3; dv = cv->verts + m * cv->width + n; VectorCopy(dv[0].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); if (DotProduct(normal, projectionDir) < -0.1) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } VectorCopy(dv[1].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); if (DotProduct(normal, projectionDir) < -0.05) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } } } } else if (*surfaces[i] == SF_FACE) { surf = ( srfSurfaceFace_t * ) surfaces[i]; // check the normal of this face if (DotProduct(surf->plane.normal, projectionDir) > -0.5) { continue; } /* VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalize(normal); if (DotProduct(normal, projectionDir) > -0.5) continue; */ indexes = (int *)( (byte *)surf + surf->ofsIndices ); for ( k = 0 ; k < surf->numIndices ; k += 3 ) { for ( j = 0 ; j < 3 ; j++ ) { v = surf->points[0] + VERTEXSIZE * indexes[k+j];; VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); } // add the fragments of this face R_AddMarkFragments( 3 , clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } continue; } else { // ignore all other world surfaces // might be cool to also project polygons on a triangle soup // however this will probably create huge amounts of extra polys // even more than the projection onto curves continue; } } return returnedFragments; }
/* ================= R_MarkFragments ================= */ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) { int numsurfaces, numPlanes; int i, j, k, m, n; surfaceType_t *surfaces[64]; int surfacesBmodel[64]; int lastBmodel; vec3_t mins, maxs; int returnedFragments; int returnedPoints; vec3_t normals[MAX_VERTS_ON_POLY+2], localNormals[MAX_VERTS_ON_POLY+2]; float dists[MAX_VERTS_ON_POLY+2], localDists[MAX_VERTS_ON_POLY+2]; vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; int numClipPoints; float *v; srfBspSurface_t *cv; glIndex_t *tri; srfVert_t *dv; vec3_t normal; vec3_t projectionDir, localProjectionDir; vec3_t v1, v2; if (numPoints <= 0) { return 0; } //increment view count for double check prevention tr.viewCount++; // VectorNormalize2( projection, projectionDir ); // find all the brushes that are to be considered ClearBounds( mins, maxs ); for ( i = 0 ; i < numPoints ; i++ ) { vec3_t temp; AddPointToBounds( points[i], mins, maxs ); VectorAdd( points[i], projection, temp ); AddPointToBounds( temp, mins, maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( points[i], -20, projectionDir, temp ); AddPointToBounds( temp, mins, maxs ); } if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY; // create the bounding planes for the to be projected polygon for ( i = 0 ; i < numPoints ; i++ ) { VectorSubtract(points[(i+1)%numPoints], points[i], v1); VectorAdd(points[i], projection, v2); VectorSubtract(points[i], v2, v2); CrossProduct(v1, v2, normals[i]); VectorNormalizeFast(normals[i]); dists[i] = DotProduct(normals[i], points[i]); } // add near and far clipping planes for projection VectorCopy(projectionDir, normals[numPoints]); dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32; VectorCopy(projectionDir, normals[numPoints+1]); VectorInverse(normals[numPoints+1]); dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20; numPlanes = numPoints + 2; numsurfaces = 0; R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, surfacesBmodel, 64, &numsurfaces, projectionDir); //assert(numsurfaces <= 64); //assert(numsurfaces != 64); // add bmodel surfaces for ( j = 1; j < tr.world->numBModels; j++ ) { vec3_t localProjection, bmodelOrigin, bmodelAxis[3]; R_TransformMarkProjection( j, projection, localProjection, 0, NULL, NULL, NULL, NULL ); R_GetBmodelInfo( j, NULL, bmodelOrigin, bmodelAxis ); VectorNormalize2( localProjection, localProjectionDir ); // find all the brushes that are to be considered ClearBounds( mins, maxs ); for ( i = 0 ; i < numPoints ; i++ ) { vec3_t temp; vec3_t delta; vec3_t localPoint; // convert point to bmodel local space VectorSubtract( points[i], bmodelOrigin, delta ); localPoint[0] = DotProduct( delta, bmodelAxis[0] ); localPoint[1] = DotProduct( delta, bmodelAxis[1] ); localPoint[2] = DotProduct( delta, bmodelAxis[2] ); AddPointToBounds( localPoint, mins, maxs ); VectorAdd( localPoint, localProjection, temp ); AddPointToBounds( temp, mins, maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( localPoint, -20, localProjectionDir, temp ); AddPointToBounds( temp, mins, maxs ); } R_BmodelSurfaces( j, mins, maxs, surfaces, surfacesBmodel, 64, &numsurfaces, localProjectionDir); } returnedPoints = 0; returnedFragments = 0; lastBmodel = -1; for ( i = 0 ; i < numsurfaces ; i++ ) { if (i == 0 || surfacesBmodel[i] != lastBmodel) { R_TransformMarkProjection( surfacesBmodel[i], projectionDir, localProjectionDir, numPlanes, normals, dists, localNormals, localDists ); lastBmodel = surfacesBmodel[i]; // don't use projectionDir, normals, or dists beyond this point !!! // mins and maxs are not setup, so they are not valid !!! } if (*surfaces[i] == SF_GRID) { cv = (srfBspSurface_t *) surfaces[i]; for ( m = 0 ; m < cv->height - 1 ; m++ ) { for ( n = 0 ; n < cv->width - 1 ; n++ ) { // We triangulate the grid and chop all triangles within // the bounding planes of the to be projected polygon. // LOD is not taken into account, not such a big deal though. // // It's probably much nicer to chop the grid itself and deal // with this grid as a normal SF_GRID surface so LOD will // be applied. However the LOD of that chopped grid must // be synced with the LOD of the original curve. // One way to do this; the chopped grid shares vertices with // the original curve. When LOD is applied to the original // curve the unused vertices are flagged. Now the chopped curve // should skip the flagged vertices. This still leaves the // problems with the vertices at the chopped grid edges. // // To avoid issues when LOD applied to "hollow curves" (like // the ones around many jump pads) we now just add a 2 unit // offset to the triangle vertices. // The offset is added in the vertex normal vector direction // so all triangles will still fit together. // The 2 unit offset should avoid pretty much all LOD problems. numClipPoints = 3; dv = cv->verts + m * cv->width + n; VectorCopy(dv[0].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); if (DotProduct(normal, localProjectionDir) < -0.1) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, localNormals, localDists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } VectorCopy(dv[1].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalizeFast(normal); if (DotProduct(normal, localProjectionDir) < -0.05) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, localNormals, localDists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } } } } else if (*surfaces[i] == SF_FACE) { srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i]; // check the normal of this face if (DotProduct(surf->cullPlane.normal, localProjectionDir) > -0.5) { continue; } for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) { for(j = 0; j < 3; j++) { v = surf->verts[tri[j]].xyz; VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]); } // add the fragments of this face R_AddMarkFragments( 3 , clipPoints, numPlanes, localNormals, localDists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir); if ( returnedFragments == maxFragments ) { return returnedFragments; // not enough space for more fragments } } } else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i]; for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3) { for(j = 0; j < 3; j++) { v = surf->verts[tri[j]].xyz; VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]); } // add the fragments of this face R_AddMarkFragments(3, clipPoints, numPlanes, localNormals, localDists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs, lastBmodel, localProjectionDir); if(returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } } } return returnedFragments; }
/* ================= R_MarkFragments ================= */ int R_MarkFragments(int orientation, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer) { int numsurfaces, numPlanes; int i, j, k, m, n; surfaceType_t *surfaces[4096]; vec3_t mins, maxs; int returnedFragments; int returnedPoints; vec3_t normals[MAX_VERTS_ON_POLY + 2]; float dists[MAX_VERTS_ON_POLY + 2]; vec3_t clipPoints[2][MAX_VERTS_ON_POLY]; int numClipPoints; float *v; srfGridMesh_t *cv; srfTriangle_t *tri; srfVert_t *dv; vec3_t normal; vec3_t projectionDir; vec3_t v1, v2; float radius; vec3_t center; // center of original mark //vec3_t bestCenter; // center point projected onto the closest surface float texCoordScale; //float dot; int numPoints = 4; // Ridah, we were only ever passing in 4, so I made this local and used the parameter for the orientation qboolean oldMapping = qfalse; if (numPoints <= 0) { return 0; } //increment view count for double check prevention tr.viewCount++; // RF, negative maxFragments means we want original mapping if (maxFragments < 0) { maxFragments = -maxFragments; //return R_OldMarkFragments( numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer ); oldMapping = qtrue; } VectorClear(center); for (i = 0 ; i < numPoints ; i++) { VectorAdd(points[i], center, center); } VectorScale(center, 1.0 / numPoints, center); // radius = VectorNormalize2(projection, projectionDir) / 2.0; bestdist = 0; VectorNegate(projectionDir, bestnormal); // find all the brushes that are to be considered ClearBounds(mins, maxs); for (i = 0 ; i < numPoints ; i++) { vec3_t temp; AddPointToBounds(points[i], mins, maxs); VectorMA(points[i], 1 * (1 + oldMapping * radius * 4), projection, temp); AddPointToBounds(temp, mins, maxs); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA(points[i], -20 * (1.0 + (float)oldMapping * (radius / 20.0) * 4), projectionDir, temp); AddPointToBounds(temp, mins, maxs); } if (numPoints > MAX_VERTS_ON_POLY) { numPoints = MAX_VERTS_ON_POLY; } // create the bounding planes for the to be projected polygon for (i = 0 ; i < numPoints ; i++) { VectorSubtract(points[(i + 1) % numPoints], points[i], v1); VectorAdd(points[i], projection, v2); VectorSubtract(points[i], v2, v2); CrossProduct(v1, v2, normals[i]); VectorNormalize(normals[i]); dists[i] = DotProduct(normals[i], points[i]); } // add near and far clipping planes for projection VectorCopy(projectionDir, normals[numPoints]); dists[numPoints] = DotProduct(normals[numPoints], points[0]) - radius * (1 + oldMapping * 10); VectorCopy(projectionDir, normals[numPoints + 1]); VectorInverse(normals[numPoints + 1]); dists[numPoints + 1] = DotProduct(normals[numPoints + 1], points[0]) - radius * (1 + oldMapping * 10); numPlanes = numPoints + 2; numsurfaces = 0; R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 4096, &numsurfaces, projectionDir); //assert(numsurfaces <= 64); //assert(numsurfaces != 64); texCoordScale = 0.5 * 1.0 / radius; returnedPoints = 0; returnedFragments = 0; // find the closest surface to center the decal there, and wrap around other surfaces if (!oldMapping) { /* for ( i = 0 ; i < numsurfaces ; i++ ) { if (*surfaces[i] == SF_FACE) { surf = ( srfSurfaceFace_t * ) surfaces[i]; // Ridah, check if this is the closest surface dot = DotProduct( center, surf->plane.normal ); dot -= surf->plane.dist; if (!bestdist) { if (dot < 0) bestdist = fabs(dot) + 1000; // avoid this surface, since the point is behind it else bestdist = dot; VectorCopy( surf->plane.normal, bestnormal ); VectorMA( center, -dot, surf->plane.normal, bestCenter ); } else if (dot >= 0 && dot < bestdist) { bestdist = dot; VectorCopy( surf->plane.normal, bestnormal ); VectorMA( center, -dot, surf->plane.normal, bestCenter ); } } } // bestCenter is now the real center VectorCopy( bestCenter, center ); Com_Printf("bestnormal: %1.1f %1.1f %1.1f \n", bestnormal[0], bestnormal[1], bestnormal[2] ); */ VectorNegate(bestnormal, bestnormal); } for (i = 0 ; i < numsurfaces ; i++) { if (*surfaces[i] == SF_GRID) { cv = (srfGridMesh_t *) surfaces[i]; for (m = 0 ; m < cv->height - 1 ; m++) { for (n = 0 ; n < cv->width - 1 ; n++) { // We triangulate the grid and chop all triangles within // the bounding planes of the to be projected polygon. // LOD is not taken into account, not such a big deal though. // // It's probably much nicer to chop the grid itself and deal // with this grid as a normal SF_GRID surface so LOD will // be applied. However the LOD of that chopped grid must // be synced with the LOD of the original curve. // One way to do this; the chopped grid shares vertices with // the original curve. When LOD is applied to the original // curve the unused vertices are flagged. Now the chopped curve // should skip the flagged vertices. This still leaves the // problems with the vertices at the chopped grid edges. // // To avoid issues when LOD applied to "hollow curves" (like // the ones around many jump pads) we now just add a 2 unit // offset to the triangle vertices. // The offset is added in the vertex normal vector direction // so all triangles will still fit together. // The 2 unit offset should avoid pretty much all LOD problems. numClipPoints = 3; dv = cv->verts + m * cv->width + n; VectorCopy(dv[0].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalize(normal); if (DotProduct(normal, projectionDir) < -0.1) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if (returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } VectorCopy(dv[1].xyz, clipPoints[0][0]); VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); VectorCopy(dv[cv->width + 1].xyz, clipPoints[0][2]); VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); CrossProduct(v1, v2, normal); VectorNormalize(normal); if (DotProduct(normal, projectionDir) < -0.05) { // add the fragments of this triangle R_AddMarkFragments(numClipPoints, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if (returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } } } } else if (*surfaces[i] == SF_FACE) { extern float VectorDistance(vec3_t v1, vec3_t v2); vec3_t axis[3]; float texCoordScale, dot; vec3_t originalPoints[4]; vec3_t newCenter, delta; int oldNumPoints; float epsilon = 0.5; // duplicated so we don't mess with the original clips for the curved surfaces vec3_t lnormals[MAX_VERTS_ON_POLY + 2]; float ldists[MAX_VERTS_ON_POLY + 2]; vec3_t lmins, lmaxs; srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i]; if (!oldMapping) { // Ridah, create a new clip box such that this decal surface is mapped onto // the current surface without distortion. To find the center of the new clip box, // we project the center of the original impact center out along the projection vector, // onto the current surface // find the center of the new decal dot = DotProduct(center, surf->plane.normal); dot -= surf->plane.dist; // check the normal of this face if (dot < -epsilon && DotProduct(surf->plane.normal, projectionDir) >= 0.01) { continue; } else if (fabs(dot) > radius) { continue; } // if the impact point is behind the surface, subtract the projection, otherwise add it VectorMA(center, -dot, bestnormal, newCenter); // recalc dot from the offset position dot = DotProduct(newCenter, surf->plane.normal); dot -= surf->plane.dist; VectorMA(newCenter, -dot, surf->plane.normal, newCenter); VectorMA(newCenter, MARKER_OFFSET, surf->plane.normal, newCenter); // create the texture axis VectorNormalize2(surf->plane.normal, axis[0]); PerpendicularVector(axis[1], axis[0]); RotatePointAroundVector(axis[2], axis[0], axis[1], (float)orientation); CrossProduct(axis[0], axis[2], axis[1]); texCoordScale = 0.5 * 1.0 / radius; // create the full polygon for (j = 0 ; j < 3 ; j++) { originalPoints[0][j] = newCenter[j] - radius * axis[1][j] - radius * axis[2][j]; originalPoints[1][j] = newCenter[j] + radius * axis[1][j] - radius * axis[2][j]; originalPoints[2][j] = newCenter[j] + radius * axis[1][j] + radius * axis[2][j]; originalPoints[3][j] = newCenter[j] - radius * axis[1][j] + radius * axis[2][j]; } ClearBounds(lmins, lmaxs); // create the bounding planes for the to be projected polygon for (j = 0 ; j < 4 ; j++) { AddPointToBounds(originalPoints[j], lmins, lmaxs); VectorSubtract(originalPoints[(j + 1) % numPoints], originalPoints[j], v1); VectorSubtract(originalPoints[j], surf->plane.normal, v2); VectorSubtract(originalPoints[j], v2, v2); CrossProduct(v1, v2, lnormals[j]); VectorNormalize(lnormals[j]); ldists[j] = DotProduct(lnormals[j], originalPoints[j]); } numPlanes = numPoints; // done. for (k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++) { for (j = 0; j < 3; j++) { v = surf->verts[tri->indexes[j]].xyz; VectorMA(v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j]); } oldNumPoints = returnedPoints; // add the fragments of this face R_AddMarkFragments(3, clipPoints, numPlanes, lnormals, ldists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, lmins, lmaxs); if (oldNumPoints != returnedPoints) { // flag this surface as already having computed ST's fragmentBuffer[returnedFragments - 1].numPoints *= -1; // Ridah, calculate ST's for (j = 0 ; j < (returnedPoints - oldNumPoints) ; j++) { VectorSubtract((float *)pointBuffer + 5 * (oldNumPoints + j), newCenter, delta); *((float *)pointBuffer + 5 * (oldNumPoints + j) + 3) = 0.5 + DotProduct(delta, axis[1]) * texCoordScale; *((float *)pointBuffer + 5 * (oldNumPoints + j) + 4) = 0.5 + DotProduct(delta, axis[2]) * texCoordScale; } } if (returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } } else // old mapping { // check the normal of this face //if (DotProduct(surf->plane.normal, projectionDir) > 0.0) { // continue; //} for (k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++) { for (j = 0; j < 3; j++) { v = surf->verts[tri->indexes[j]].xyz; VectorMA(v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j]); } // add the fragments of this face R_AddMarkFragments(3, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if (returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } } } else if (*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) { srfTriangles_t *surf = (srfTriangles_t *) surfaces[i]; for (k = 0, tri = surf->triangles; k < surf->numTriangles; k++, tri++) { for (j = 0; j < 3; j++) { v = surf->verts[tri->indexes[j]].xyz; VectorMA(v, MARKER_OFFSET, surf->verts[tri->indexes[j]].normal, clipPoints[0][j]); } // add the fragments of this face R_AddMarkFragments(3, clipPoints, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs); if (returnedFragments == maxFragments) { return returnedFragments; // not enough space for more fragments } } } } return returnedFragments; }
/* ================= R_BoxSurfaces_r ================= */ void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { int s, c; msurface_t *surf; int *mark; // do the tail recursion in a loop while (node->contents == -1) { s = BoxOnPlaneSide(mins, maxs, node->plane); if (s == 1) { node = node->children[0]; } else if (s == 2) { node = node->children[1]; } else { R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); node = node->children[1]; } } // Ridah, don't mark alpha surfaces if (node->contents & CONTENTS_TRANSLUCENT) { return; } // add the individual surfaces mark = tr.world->marksurfaces + node->firstmarksurface; c = node->nummarksurfaces; while (c--) { int *surfViewCount; // if (*listlength >= listsize) { break; } // surfViewCount = &tr.world->surfacesViewCount[*mark]; surf = tr.world->surfaces + *mark; // check if the surface has NOIMPACT or NOMARKS set if ((surf->shader->surfaceFlags & (SURF_NOIMPACT | SURF_NOMARKS)) || (surf->shader->contentFlags & CONTENTS_FOG)) { *surfViewCount = tr.viewCount; } // extra check for surfaces to avoid list overflows else if (*(surf->data) == SF_FACE) { // the face plane should go through the box s = BoxOnPlaneSide(mins, maxs, &surf->cullinfo.plane); if (s == 1 || s == 2) { *surfViewCount = tr.viewCount; } else if (DotProduct(surf->cullinfo.plane.normal, dir) > -0.5) { // don't add faces that make sharp angles with the projection direction *surfViewCount = tr.viewCount; } } else if (*(surf->data) != SF_GRID && *(surf->data) != SF_TRIANGLES) { *surfViewCount = tr.viewCount; } // check the viewCount because the surface may have // already been added if it spans multiple leafs if (*surfViewCount != tr.viewCount) { *surfViewCount = tr.viewCount; list[*listlength] = surf->data; (*listlength)++; } mark++; } }
/* ================= R_BoxSurfaces_r ================= */ void R_BoxSurfaces_r( mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir ) { int s, c; msurface_t *surf, **mark; // RF, if this node hasn't been rendered recently, ignore it if ( node->visframe < tr.visCount - 2 ) { // allow us to be a few frames behind return; } // do the tail recursion in a loop while ( node->contents == -1 ) { s = BoxOnPlaneSide( mins, maxs, node->plane ); if ( s == 1 ) { node = node->children[0]; } else if ( s == 2 ) { node = node->children[1]; } else { R_BoxSurfaces_r( node->children[0], mins, maxs, list, listsize, listlength, dir ); node = node->children[1]; } } // Ridah, don't mark alpha surfaces if ( node->contents & CONTENTS_TRANSLUCENT ) { return; } // add the individual surfaces mark = node->firstmarksurface; c = node->nummarksurfaces; while ( c-- ) { // if ( *listlength >= listsize ) { break; } // surf = *mark; // check if the surface has NOIMPACT or NOMARKS set if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { surf->viewCount = tr.viewCount; } // extra check for surfaces to avoid list overflows else if ( *( surf->data ) == SF_FACE ) { #if defined RTCW_ET if ( ( ( srfSurfaceFace_t * ) surf->data )->plane.type != PLANE_NON_PLANAR ) { #endif // RTCW_XX // the face plane should go through the box s = BoxOnPlaneSide( mins, maxs, &( ( srfSurfaceFace_t * ) surf->data )->plane ); if ( s == 1 || s == 2 ) { surf->viewCount = tr.viewCount; } else if ( DotProduct( ( ( srfSurfaceFace_t * ) surf->data )->plane.normal, dir ) < -0.5 ) { // don't add faces that make sharp angles with the projection direction surf->viewCount = tr.viewCount; } #if !defined RTCW_ET } else if ( *( surfaceType_t * )( surf->data ) != SF_GRID ) { #else } } else if ( *( surfaceType_t * )( surf->data ) != SF_GRID && *( surfaceType_t * )( surf->data ) != SF_TRIANGLES ) { #endif // RTCW_XX surf->viewCount = tr.viewCount; } // check the viewCount because the surface may have // already been added if it spans multiple leafs if ( surf->viewCount != tr.viewCount ) { surf->viewCount = tr.viewCount; list[*listlength] = (surfaceType_t *) surf->data; ( *listlength )++; } mark++; } }
/* ================= R_BoxSurfaces_r ================= */ void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { int s, c; msurface_t *surf, **mark; // do the tail recursion in a loop while ( node->contents == -1 ) { s = BoxOnPlaneSide( mins, maxs, node->plane ); if (s == 1) { node = node->children[0]; } else if (s == 2) { node = node->children[1]; } else { R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); node = node->children[1]; } } // add the individual surfaces mark = node->firstmarksurface; c = node->nummarksurfaces; while (c--) { // if (*listlength >= listsize) break; // surf = *mark; //ri.Printf(PRINT_ALL, "^3surf: %s\n", surf->shader->name); // check if the surface has NOIMPACT or NOMARKS set if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { if (r_ignoreNoMarks->integer == 0) { surf->viewCount = tr.viewCount; } else if (r_ignoreNoMarks->integer == 1) { if (surf->shader->contentFlags & (CONTENTS_FOG | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA)) { surf->viewCount = tr.viewCount; } } else { // r_ignoreNoMarks->integer >= 2 // allow marks liquids, etc.. } } // extra check for surfaces to avoid list overflows else if (*(surf->data) == SF_FACE) { // the face plane should go through the box s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane ); if (s == 1 || s == 2) { surf->viewCount = tr.viewCount; } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) { // don't add faces that make sharp angles with the projection direction //ri.Printf(PRINT_ALL, "^3sharp angle '%s'\n", surf->shader->name); surf->viewCount = tr.viewCount; } else { //ri.Printf(PRINT_ALL, "^3surf: %s\n", surf->shader->name); } } else if (*(surfaceType_t *) (surf->data) != SF_GRID && *(surfaceType_t *) (surf->data) != SF_TRIANGLES) { surf->viewCount = tr.viewCount; } // check the viewCount because the surface may have // already been added if it spans multiple leafs if (surf->viewCount != tr.viewCount) { surf->viewCount = tr.viewCount; mxsurf[*listlength] = surf; list[*listlength] = (surfaceType_t *) surf->data; (*listlength)++; //ri.Printf(PRINT_ALL, "^3surf: %s\n", surf->shader->name); } mark++; } }
int R_MarkFragmentsWolf( int orientation, const vec3_t* points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t* fragmentBuffer ) { int numPlanes; int i; vec3_t mins, maxs; int returnedFragments; int returnedPoints; vec3_t normals[ MAX_VERTS_ON_POLY + 2 ]; float dists[ MAX_VERTS_ON_POLY + 2 ]; vec3_t projectionDir; vec3_t v1, v2; float radius; vec3_t center; // center of original mark int numPoints = 4; // Ridah, we were only ever passing in 4, so I made this local and used the parameter for the orientation qboolean oldMapping = false; //increment view count for double check prevention tr.viewCount++; // RF, negative maxFragments means we want original mapping if ( maxFragments < 0 ) { maxFragments = -maxFragments; oldMapping = true; } VectorClear( center ); for ( i = 0; i < numPoints; i++ ) { VectorAdd( points[ i ], center, center ); } VectorScale( center, 1.0 / numPoints, center ); // radius = VectorNormalize2( projection, projectionDir ) / 2.0; vec3_t bestnormal; VectorNegate( projectionDir, bestnormal ); // find all the brushes that are to be considered ClearBounds( mins, maxs ); for ( i = 0; i < numPoints; i++ ) { vec3_t temp; AddPointToBounds( points[ i ], mins, maxs ); VectorMA( points[ i ], 1 * ( 1 + oldMapping * radius * 4 ), projection, temp ); AddPointToBounds( temp, mins, maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( points[ i ], -20 * ( 1.0 + ( float )oldMapping * ( radius / 20.0 ) * 4 ), projectionDir, temp ); AddPointToBounds( temp, mins, maxs ); } if ( numPoints > MAX_VERTS_ON_POLY ) { numPoints = MAX_VERTS_ON_POLY; } // create the bounding planes for the to be projected polygon for ( i = 0; i < numPoints; i++ ) { VectorSubtract( points[ ( i + 1 ) % numPoints ], points[ i ], v1 ); VectorAdd( points[ i ], projection, v2 ); VectorSubtract( points[ i ], v2, v2 ); CrossProduct( v1, v2, normals[ i ] ); VectorNormalize( normals[ i ] ); dists[ i ] = DotProduct( normals[ i ], points[ i ] ); } // add near and far clipping planes for projection VectorCopy( projectionDir, normals[ numPoints ] ); dists[ numPoints ] = DotProduct( normals[ numPoints ], points[ 0 ] ) - radius * ( 1 + oldMapping * 10 ); VectorCopy( projectionDir, normals[ numPoints + 1 ] ); VectorInverse( normals[ numPoints + 1 ] ); dists[ numPoints + 1 ] = DotProduct( normals[ numPoints + 1 ], points[ 0 ] ) - radius * ( 1 + oldMapping * 10 ); numPlanes = numPoints + 2; int numsurfaces = 0; idWorldSurface* surfaces[ 4096 ]; R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 4096, &numsurfaces, projectionDir ); returnedPoints = 0; returnedFragments = 0; // find the closest surface to center the decal there, and wrap around other surfaces if ( !oldMapping ) { VectorNegate( bestnormal, bestnormal ); } for ( i = 0; i < numsurfaces; i++ ) { surfaces[ i ]->MarkFragmentsWolf( projectionDir, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs, oldMapping, center, radius, bestnormal, orientation, numPoints ); if ( returnedFragments == maxFragments ) { break; // not enough space for more fragments } } return returnedFragments; }
int R_MarkFragments( int numPoints, const vec3_t* points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t* fragmentBuffer ) { //increment view count for double check prevention tr.viewCount++; vec3_t projectionDir; VectorNormalize2( projection, projectionDir ); // find all the brushes that are to be considered vec3_t mins, maxs; ClearBounds( mins, maxs ); for ( int i = 0; i < numPoints; i++ ) { AddPointToBounds( points[ i ], mins, maxs ); vec3_t temp; VectorAdd( points[ i ], projection, temp ); AddPointToBounds( temp, mins, maxs ); // make sure we get all the leafs (also the one(s) in front of the hit surface) VectorMA( points[ i ], -20, projectionDir, temp ); AddPointToBounds( temp, mins, maxs ); } if ( numPoints > MAX_VERTS_ON_POLY ) { numPoints = MAX_VERTS_ON_POLY; } // create the bounding planes for the to be projected polygon vec3_t normals[ MAX_VERTS_ON_POLY + 2 ]; float dists[ MAX_VERTS_ON_POLY + 2 ]; for ( int i = 0; i < numPoints; i++ ) { vec3_t v1, v2; VectorSubtract( points[ ( i + 1 ) % numPoints ], points[ i ], v1 ); VectorAdd( points[ i ], projection, v2 ); VectorSubtract( points[ i ], v2, v2 ); CrossProduct( v1, v2, normals[ i ] ); VectorNormalizeFast( normals[ i ] ); dists[ i ] = DotProduct( normals[ i ], points[ i ] ); } // add near and far clipping planes for projection VectorCopy( projectionDir, normals[ numPoints ] ); dists[ numPoints ] = DotProduct( normals[ numPoints ], points[ 0 ] ) - 32; VectorCopy( projectionDir, normals[ numPoints + 1 ] ); VectorInverse( normals[ numPoints + 1 ] ); dists[ numPoints + 1 ] = DotProduct( normals[ numPoints + 1 ], points[ 0 ] ) - 20; int numPlanes = numPoints + 2; int numsurfaces = 0; idWorldSurface* surfaces[ 64 ]; R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir ); //assert(numsurfaces <= 64); //assert(numsurfaces != 64); int returnedPoints = 0; int returnedFragments = 0; for ( int i = 0; i < numsurfaces; i++ ) { surfaces[ i ]->MarkFragments( projectionDir, numPlanes, normals, dists, maxPoints, pointBuffer, maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs ); if ( returnedFragments == maxFragments ) { break; // not enough space for more fragments } } return returnedFragments; }
/* ================= R_BoxSurfaces_r ================= */ void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) { int s, c; msurface_t *surf, **mark; // do the tail recursion in a loop while ( node->contents == -1 ) { #ifdef _XBOX s = BoxOnPlaneSide( mins, maxs, tr.world->planes + node->planeNum ); #else s = BoxOnPlaneSide( mins, maxs, node->plane ); #endif if (s == 1) { node = node->children[0]; } else if (s == 2) { node = node->children[1]; } else { R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir); node = node->children[1]; } } // add the individual surfaces #ifdef _XBOX mleaf_s *leaf = (mleaf_s*)node; mark = tr.world->marksurfaces + leaf->firstMarkSurfNum; c = leaf->nummarksurfaces; #else mark = node->firstmarksurface; c = node->nummarksurfaces; #endif while (c--) { // if (*listlength >= listsize) break; // surf = *mark; // check if the surface has NOIMPACT or NOMARKS set if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) ) || ( surf->shader->contentFlags & CONTENTS_FOG ) ) { surf->viewCount = tr.viewCount; } // extra check for surfaces to avoid list overflows else if (*(surf->data) == SF_FACE) { // the face plane should go through the box s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane ); if (s == 1 || s == 2) { surf->viewCount = tr.viewCount; } else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) { // don't add faces that make sharp angles with the projection direction surf->viewCount = tr.viewCount; } } else if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount; // check the viewCount because the surface may have // already been added if it spans multiple leafs if (surf->viewCount != tr.viewCount) { surf->viewCount = tr.viewCount; list[*listlength] = (surfaceType_t *) surf->data; (*listlength)++; } mark++; } }