static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds ) { vec4_t plane; float d; winding_t *w; /* dummy check */ if( ds->sideRef == NULL || ds->sideRef->side == NULL ) return; /* backface check */ if( ds->planar ) { VectorCopy( mapplanes[ ds->planeNum ].normal, plane ); plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin ); d = DotProduct( dp->planes[ 0 ], plane ); if( d < -0.0001f ) return; } /* generate decal */ w = WindingFromDrawSurf( ds ); ProjectDecalOntoWinding( dp, ds, w ); }
/* ==================== ChopFaceByBrush There may be a fragment contained in the brush ==================== */ qboolean ChopFaceByBrush(drawSurface_t * ds, bspBrush_t * b) { int i, j; side_t *s; plane_t *plane; winding_t *w; winding_t *front, *back; winding_t *outside[MAX_BRUSH_SIDES]; int numOutside; drawSurface_t *newds; drawVert_t *dv; shaderInfo_t *si; float mins[2]; // brush primitive : // axis base vec3_t texX, texY; vec_t x, y; w = WindingFromDrawSurf(ds); numOutside = 0; for(i = 0; i < b->numsides; i++) { s = &b->sides[i]; if(s->backSide) { continue; } plane = &mapPlanes[s->planenum]; // handle coplanar outfacing (don't fog) if(ds->side->planenum == s->planenum) { return qfalse; } // handle coplanar infacing (keep inside) if((ds->side->planenum ^ 1) == s->planenum) { continue; } // general case ClipWindingEpsilon(w, plane->normal, plane->dist, ON_EPSILON, &front, &back); FreeWinding(w); if(!back) { // nothing actually contained inside for(j = 0; j < numOutside; j++) { FreeWinding(outside[j]); } return qfalse; } if(front) { if(numOutside == MAX_BRUSH_SIDES) { Error("MAX_BRUSH_SIDES"); } outside[numOutside] = front; numOutside++; } w = back; } // all of outside fragments become seperate drawsurfs // linked to the same side c_fogFragment += numOutside; s = ds->side; for(i = 0; i < numOutside; i++) { newds = DrawSurfaceForSide(ds->mapBrush, s, outside[i]); FreeWinding(outside[i]); } // replace ds->verts with the verts for w ds->numVerts = w->numpoints; free(ds->verts); ds->verts = malloc(ds->numVerts * sizeof(*ds->verts)); memset(ds->verts, 0, ds->numVerts * sizeof(*ds->verts)); si = s->shaderInfo; mins[0] = 9999; mins[1] = 9999; // compute s/t coordinates from brush primitive texture matrix // compute axis base ComputeAxisBase(mapPlanes[s->planenum].normal, texX, texY); for(j = 0; j < w->numpoints; j++) { dv = ds->verts + j; VectorCopy(w->p[j], dv->xyz); if(g_bBrushPrimit == BPRIMIT_OLDBRUSHES) { // calculate texture s/t dv->st[0] = s->vecs[0][3] + DotProduct(s->vecs[0], dv->xyz); dv->st[1] = s->vecs[1][3] + DotProduct(s->vecs[1], dv->xyz); dv->st[0] /= si->width; dv->st[1] /= si->height; } else { // calculate texture s/t from brush primitive texture matrix x = DotProduct(dv->xyz, texX); y = DotProduct(dv->xyz, texY); dv->st[0] = s->texMat[0][0] * x + s->texMat[0][1] * y + s->texMat[0][2]; dv->st[1] = s->texMat[1][0] * x + s->texMat[1][1] * y + s->texMat[1][2]; } if(dv->st[0] < mins[0]) { mins[0] = dv->st[0]; } if(dv->st[1] < mins[1]) { mins[1] = dv->st[1]; } // copy normal VectorCopy(mapPlanes[s->planenum].normal, dv->normal); } // adjust the texture coordinates to be as close to 0 as possible if(!si->globalTexture) { mins[0] = floor(mins[0]); mins[1] = floor(mins[1]); for(i = 0; i < w->numpoints; i++) { dv = ds->verts + i; dv->st[0] -= mins[0]; dv->st[1] -= mins[1]; } } return qtrue; }
qboolean ChopFaceSurfaceByBrush( entity_t *e, mapDrawSurface_t *ds, brush_t *b ){ int i, j; side_t *s; plane_t *plane; winding_t *w; winding_t *front, *back; winding_t *outside[ MAX_BRUSH_SIDES ]; int numOutside; mapDrawSurface_t *newds; /* dummy check */ if ( ds->sideRef == NULL || ds->sideRef->side == NULL ) { return qfalse; } /* initial setup */ w = WindingFromDrawSurf( ds ); numOutside = 0; /* chop by each brush side */ for ( i = 0; i < b->numsides; i++ ) { /* get brush side and plane */ s = &b->sides[ i ]; plane = &mapplanes[ s->planenum ]; /* handle coplanar outfacing (don't fog) */ if ( ds->sideRef->side->planenum == s->planenum ) { return qfalse; } /* handle coplanar infacing (keep inside) */ if ( ( ds->sideRef->side->planenum ^ 1 ) == s->planenum ) { continue; } /* general case */ ClipWindingEpsilonStrict( w, plane->normal, plane->dist, ON_EPSILON, &front, &back ); /* strict; if plane is "almost identical" to face, both ways to continue can be wrong, so we better not fog it */ FreeWinding( w ); if ( back == NULL ) { /* nothing actually contained inside */ for ( j = 0; j < numOutside; j++ ) FreeWinding( outside[ j ] ); return qfalse; } if ( front != NULL ) { if ( numOutside == MAX_BRUSH_SIDES ) { Error( "MAX_BRUSH_SIDES" ); } outside[ numOutside ] = front; numOutside++; } w = back; } /* fixme: celshaded surface fragment errata */ /* all of outside fragments become seperate drawsurfs */ numFogFragments += numOutside; s = ds->sideRef->side; for ( i = 0; i < numOutside; i++ ) { newds = DrawSurfaceForSide( e, ds->mapBrush, s, outside[ i ] ); newds->fogNum = ds->fogNum; FreeWinding( outside[ i ] ); } /* ydnar: the old code neglected to snap to 0.125 for the fragment inside the fog brush, leading to sparklies. this new code does the right thing and uses the original surface's brush side */ /* build a drawsurf for it */ newds = DrawSurfaceForSide( e, ds->mapBrush, s, w ); if ( newds == NULL ) { return qfalse; } /* copy new to original */ ClearSurface( ds ); memcpy( ds, newds, sizeof( mapDrawSurface_t ) ); /* didn't really add a new drawsurface... :) */ numMapDrawSurfs--; /* return ok */ return qtrue; }