/* ================= 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 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 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; }