static void ProjectDecalOntoWinding( decalProjector_t *dp, int numPoints, vec3_t points[ 2 ][ MAX_DECAL_VERTS ], bspSurface_t *surf, bspModel_t *bmodel ) { int i, pingPong, count, axis; float pd, d, d2, alpha = 1.f; vec4_t plane; vec3_t absNormal; decal_t *decal, *oldest; polyVert_t *vert; /* make a plane from the winding */ if ( !PlaneFromPoints( plane, points[ 0 ][ 0 ], points[ 0 ][ 1 ], points[ 0 ][ 2 ] ) ) { return; } /* omnidirectional projectors need plane type */ if ( dp->omnidirectional ) { /* compiler warnings be gone */ pd = 1.0f; /* fade by distance from plane */ d = DotProduct( dp->center, plane ) - plane[ 3 ]; alpha = 1.0f - ( fabs( d ) / dp->radius ); if ( alpha < 0.0f ) { return; } if ( alpha > 1.0f ) { alpha = 1.0f; } /* set projection axis */ absNormal[ 0 ] = fabs( plane[ 0 ] ); absNormal[ 1 ] = fabs( plane[ 1 ] ); absNormal[ 2 ] = fabs( plane[ 2 ] ); if ( absNormal[ 2 ] >= absNormal[ 0 ] && absNormal[ 2 ] >= absNormal[ 1 ] ) { axis = 2; } else if ( absNormal[ 0 ] >= absNormal[ 1 ] && absNormal[ 0 ] >= absNormal[ 2 ] ) { axis = 0; } else { axis = 1; } } else { /* backface check */ pd = DotProduct( dp->planes[ 0 ], plane ); if ( pd < -0.0001f ) { return; } /* directional decals use first texture matrix */ axis = 0; } /* chop the winding by all the projector planes */ pingPong = 0; for ( i = 0; i < dp->numPlanes; i++ ) //% dp->numPlanes { ChopWindingBehindPlane( numPoints, points[ pingPong ], &numPoints, points[ !pingPong ], dp->planes[ i ], 0.0f ); pingPong ^= 1; if ( numPoints < 3 ) { return; } if ( numPoints == MAX_DECAL_VERTS ) { break; } } /* find first free decal (fixme: optimize this) */ count = ( bmodel == tr.world->models ? MAX_WORLD_DECALS : MAX_ENTITY_DECALS ); oldest = &bmodel->decals[ 0 ]; decal = bmodel->decals; for ( i = 0; i < count; i++, decal++ ) { /* try to find an empty decal slot */ if ( decal->shader == NULL ) { break; } /* find oldest decal */ if ( decal->fadeEndTime < oldest->fadeEndTime ) { oldest = decal; } } /* guess we have to use the oldest decal */ if ( i >= count ) { decal = oldest; } /* r_speeds useful info */ tr.pc.c_decalSurfacesCreated++; /* set it up (fixme: get the shader before this happens) */ decal->parent = surf; decal->shader = dp->shader; decal->fadeStartTime = dp->fadeStartTime; decal->fadeEndTime = dp->fadeEndTime; decal->fogIndex = surf->fogIndex; /* add points */ decal->numVerts = numPoints; vert = decal->verts; for ( i = 0; i < numPoints; i++, vert++ ) { /* set xyz */ VectorCopy( points[ pingPong ][ i ], vert->xyz ); /* set st */ vert->st[ 0 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 0 ] ) + dp->texMat[ axis ][ 0 ][ 3 ]; vert->st[ 1 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 1 ] ) + dp->texMat[ axis ][ 1 ][ 3 ]; /* unidirectional decals fade by half distance from front->back planes */ if ( !dp->omnidirectional ) { /* set alpha */ d = DotProduct( vert->xyz, dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ]; d2 = DotProduct( vert->xyz, dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ]; alpha = 2.0f * d2 / ( d + d2 ); if ( alpha > 1.0f ) { alpha = 1.0f; } else if ( alpha < 0.0f ) { alpha = 0.0f; } } /* set color */ vert->modulate[ 0 ] = Q_ftol( pd * alpha * dp->color[ 0 ] ); vert->modulate[ 1 ] = Q_ftol( pd * alpha * dp->color[ 1 ] ); vert->modulate[ 2 ] = Q_ftol( pd * alpha * dp->color[ 2 ] ); vert->modulate[ 3 ] = Q_ftol( alpha * dp->color[ 3 ] ); } }
// projects decal onto a polygon void ProjectDecalOntoWinding( decalProjector_t* dp, int numPoints, vec3_t points[ 2 ][ MAX_DECAL_VERTS ], const idWorldSurface* surf, mbrush46_model_t* bmodel ) { // make a plane from the winding vec4_t plane; if ( !PlaneFromPoints( plane, points[ 0 ][ 0 ], points[ 0 ][ 1 ], points[ 0 ][ 2 ] ) ) { return; } // omnidirectional projectors need plane type float pd; int axis; float alpha = 1.f; if ( dp->omnidirectional ) { pd = 1.0f; // fade by distance from plane float d = DotProduct( dp->center, plane ) - plane[ 3 ]; alpha = 1.0f - ( fabs( d ) / dp->radius ); if ( alpha < 0.0f ) { return; } if ( alpha > 1.0f ) { alpha = 1.0f; } // set projection axis vec3_t absNormal; absNormal[ 0 ] = fabs( plane[ 0 ] ); absNormal[ 1 ] = fabs( plane[ 1 ] ); absNormal[ 2 ] = fabs( plane[ 2 ] ); if ( absNormal[ 2 ] >= absNormal[ 0 ] && absNormal[ 2 ] >= absNormal[ 1 ] ) { axis = 2; } else if ( absNormal[ 0 ] >= absNormal[ 1 ] && absNormal[ 0 ] >= absNormal[ 2 ] ) { axis = 0; } else { axis = 1; } } else { // backface check pd = DotProduct( dp->planes[ 0 ], plane ); if ( pd < -0.0001f ) { return; } // directional decals use first texture matrix axis = 0; } // chop the winding by all the projector planes int pingPong = 0; for ( int i = 0; i < dp->numPlanes; i++ ) { ChopWindingBehindPlane( numPoints, points[ pingPong ], &numPoints, points[ !pingPong ], dp->planes[ i ], 0.0f ); pingPong ^= 1; if ( numPoints < 3 ) { return; } if ( numPoints == MAX_DECAL_VERTS ) { break; } } // find first free decal (fixme: optimize this) int count = ( bmodel == tr.world->bmodels ? MAX_WORLD_DECALS : MAX_ENTITY_DECALS ); mbrush46_decal_t* oldest = &bmodel->decals[ 0 ]; mbrush46_decal_t* decal = bmodel->decals; int i; for ( i = 0; i < count; i++, decal++ ) { // try to find an empty decal slot if ( decal->shader == NULL ) { break; } // find oldest decal if ( decal->fadeEndTime < oldest->fadeEndTime ) { oldest = decal; } } // guess we have to use the oldest decal if ( i >= count ) { decal = oldest; } // r_speeds useful info tr.pc.c_decalSurfacesCreated++; // set it up (fixme: get the shader before this happens) decal->parent = surf; decal->shader = dp->shader; decal->fadeStartTime = dp->fadeStartTime; decal->fadeEndTime = dp->fadeEndTime; decal->fogIndex = surf->fogIndex; // add points decal->numVerts = numPoints; polyVert_t* vert = decal->verts; for ( i = 0; i < numPoints; i++, vert++ ) { // set xyz VectorCopy( points[ pingPong ][ i ], vert->xyz ); // set st vert->st[ 0 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 0 ] ) + dp->texMat[ axis ][ 0 ][ 3 ]; vert->st[ 1 ] = DotProduct( vert->xyz, dp->texMat[ axis ][ 1 ] ) + dp->texMat[ axis ][ 1 ][ 3 ]; // unidirectional decals fade by half distance from front->back planes if ( !dp->omnidirectional ) { // set alpha float d = DotProduct( vert->xyz, dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ]; float d2 = DotProduct( vert->xyz, dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ]; alpha = 2.0f * d2 / ( d + d2 ); if ( alpha > 1.0f ) { alpha = 1.0f; } else if ( alpha < 0.0f ) { alpha = 0.0f; } } // set color vert->modulate[ 0 ] = idMath::FtoiFast( pd * alpha * dp->color[ 0 ] ); vert->modulate[ 1 ] = idMath::FtoiFast( pd * alpha * dp->color[ 1 ] ); vert->modulate[ 2 ] = idMath::FtoiFast( pd * alpha * dp->color[ 2 ] ); vert->modulate[ 3 ] = idMath::FtoiFast( alpha * dp->color[ 3 ] ); } }