void RE_ProjectDecal( qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime ) { int i; float radius, iDist; vec3_t xyz; vec4_t omniProjection; decalVert_t dv[ 4 ]; decalProjector_t *dp, temp; /* first frame rendered does not have a valid decals list */ if ( tr.refdef.decalProjectors == NULL ) { return; } /* dummy check */ if ( numPoints != 1 && numPoints != 3 && numPoints != 4 ) { ri.Printf( PRINT_WARNING, "WARNING: Invalid number of decal points (%d)\n", numPoints ); return; } /* early outs */ if ( lifeTime == 0 ) { return; } if ( projection[ 3 ] <= 0.0f ) { return; } /* set times properly */ if ( lifeTime < 0 || fadeTime < 0 ) { lifeTime = 0; fadeTime = 0; } /* basic setup */ temp.shader = R_GetShaderByHandle( hShader ); /* debug code */ temp.numPlanes = temp.shader->entityMergable; temp.color[ 0 ] = color[ 0 ] * 255; temp.color[ 1 ] = color[ 1 ] * 255; temp.color[ 2 ] = color[ 2 ] * 255; temp.color[ 3 ] = color[ 3 ] * 255; temp.numPlanes = numPoints + 2; temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; temp.fadeEndTime = temp.fadeStartTime + fadeTime; /* set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) */ dv[ 0 ].st[ 0 ] = 0.0f; dv[ 0 ].st[ 1 ] = 0.0f; dv[ 1 ].st[ 0 ] = 0.0f; dv[ 1 ].st[ 1 ] = 1.0f; dv[ 2 ].st[ 0 ] = 1.0f; dv[ 2 ].st[ 1 ] = 1.0f; dv[ 3 ].st[ 0 ] = 1.0f; dv[ 3 ].st[ 1 ] = 0.0f; /* omnidirectional? */ if ( numPoints == 1 ) { /* set up omnidirectional */ numPoints = 4; temp.numPlanes = 6; temp.omnidirectional = qtrue; radius = projection[ 3 ]; Vector4Set( omniProjection, 0.0f, 0.0f, -1.0f, radius * 2.0f ); projection = omniProjection; iDist = 1.0f / ( radius * 2.0f ); /* set corner */ VectorSet( xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); /* make x axis texture matrix (yz) */ VectorSet( temp.texMat[ 0 ][ 0 ], 0.0f, iDist, 0.0f ); temp.texMat[ 0 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 0 ], xyz ); VectorSet( temp.texMat[ 0 ][ 1 ], 0.0f, 0.0f, iDist ); temp.texMat[ 0 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 0 ][ 1 ], xyz ); /* make y axis texture matrix (xz) */ VectorSet( temp.texMat[ 1 ][ 0 ], iDist, 0.0f, 0.0f ); temp.texMat[ 1 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 0 ], xyz ); VectorSet( temp.texMat[ 1 ][ 1 ], 0.0f, 0.0f, iDist ); temp.texMat[ 1 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 1 ][ 1 ], xyz ); /* make z axis texture matrix (xy) */ VectorSet( temp.texMat[ 2 ][ 0 ], iDist, 0.0f, 0.0f ); temp.texMat[ 2 ][ 0 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 0 ], xyz ); VectorSet( temp.texMat[ 2 ][ 1 ], 0.0f, iDist, 0.0f ); temp.texMat[ 2 ][ 1 ][ 3 ] = -DotProduct( temp.texMat[ 2 ][ 1 ], xyz ); /* setup decal points */ VectorSet( dv[ 0 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 1 ].xyz, points[ 0 ][ 0 ] - radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 2 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] + radius, points[ 0 ][ 2 ] + radius ); VectorSet( dv[ 3 ].xyz, points[ 0 ][ 0 ] + radius, points[ 0 ][ 1 ] - radius, points[ 0 ][ 2 ] + radius ); } else { /* set up unidirectional */ temp.omnidirectional = qfalse; /* set up decal points */ VectorCopy( points[ 0 ], dv[ 0 ].xyz ); VectorCopy( points[ 1 ], dv[ 1 ].xyz ); VectorCopy( points[ 2 ], dv[ 2 ].xyz ); VectorCopy( points[ 3 ], dv[ 3 ].xyz ); /* make texture matrix */ if ( !MakeTextureMatrix( temp.texMat[ 0 ], projection, &dv[ 0 ], &dv[ 1 ], &dv[ 2 ] ) ) { return; } } /* bound the projector */ ClearBounds( temp.mins, temp.maxs ); for ( i = 0; i < numPoints; i++ ) { AddPointToBounds( dv[ i ].xyz, temp.mins, temp.maxs ); VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz ); AddPointToBounds( xyz, temp.mins, temp.maxs ); } /* make bounding sphere */ VectorAdd( temp.mins, temp.maxs, temp.center ); VectorScale( temp.center, 0.5f, temp.center ); VectorSubtract( temp.maxs, temp.center, xyz ); temp.radius = VectorLength( xyz ); temp.radius2 = temp.radius * temp.radius; /* frustum cull the projector (fixme: this uses a stale frustum!) */ if ( R_CullPointAndRadius( temp.center, temp.radius ) == CULL_OUT ) { return; } /* make the front plane */ if ( !PlaneFromPoints( temp.planes[ 0 ], dv[ 0 ].xyz, dv[ 1 ].xyz, dv[ 2 ].xyz ) ) { return; } /* make the back plane */ VectorSubtract( vec3_origin, temp.planes[ 0 ], temp.planes[ 1 ] ); VectorMA( dv[ 0 ].xyz, projection[ 3 ], projection, xyz ); temp.planes[ 1 ][ 3 ] = DotProduct( xyz, temp.planes[ 1 ] ); /* make the side planes */ for ( i = 0; i < numPoints; i++ ) { VectorMA( dv[ i ].xyz, projection[ 3 ], projection, xyz ); if ( !PlaneFromPoints( temp.planes[ i + 2 ], dv[( i + 1 ) % numPoints ].xyz, dv[ i ].xyz, xyz ) ) { return; } } /* create a new projector */ dp = &tr.refdef.decalProjectors[ r_numDecalProjectors & DECAL_PROJECTOR_MASK ]; Com_Memcpy( dp, &temp, sizeof( *dp ) ); /* we have a winner */ r_numDecalProjectors++; }
static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv ) { int i, j; decalProjector_t *dp; vec3_t xyz; /* dummy check */ if( numVerts != 3 && numVerts != 4 ) return -1; /* limit check */ if( numProjectors >= MAX_PROJECTORS ) { MsgDev( D_WARN, "MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS ); return -2; } /* create a new projector */ dp = &projectors[ numProjectors ]; Mem_Set( dp, 0, sizeof( *dp )); /* basic setup */ dp->si = si; dp->numPlanes = numVerts + 2; /* make texture matrix */ if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) ) return -1; /* bound the projector */ ClearBounds( dp->mins, dp->maxs ); for( i = 0; i < numVerts; i++ ) { AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs ); VectorMA( dv[ i ]->xyz, distance, projection, xyz ); AddPointToBounds( xyz, dp->mins, dp->maxs ); } /* make bouding sphere */ VectorAdd( dp->mins, dp->maxs, dp->center ); VectorScale( dp->center, 0.5f, dp->center ); VectorSubtract( dp->maxs, dp->center, xyz ); dp->radius = VectorLength( xyz ); dp->radius2 = dp->radius * dp->radius; /* make the front plane */ if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) ) return -1; /* make the back plane */ VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] ); VectorMA( dv[ 0 ]->xyz, distance, projection, xyz ); dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] ); /* make the side planes */ for( i = 0; i < numVerts; i++ ) { j = (i + 1) % numVerts; VectorMA( dv[ i ]->xyz, distance, projection, xyz ); if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) ) return -1; } /* return ok */ numProjectors++; return numProjectors - 1; }
/** * @brief Creates a new decal projector from a triangle. * * Projected polygons should be 3 or 4 points. * * If a single point is passed in (numPoints == 1) then the decal will be omnidirectional * omnidirectional decals use points[ 0 ] as center and projection[ 3 ] as radius * pass in lifeTime < 0 for a temporary mark. * * @param[in] hShader * @param[in] numPoints * @param[in] points * @param[in] projection * @param[in] color * @param[in] lifeTime * @param[in] fadeTime */ void RE_ProjectDecal(qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime) { static int totalProjectors = 0; vec3_t xyz; decalVert_t dv[4]; int i; decalProjector_t *dp, temp; if (r_numDecalProjectors >= MAX_DECAL_PROJECTORS) { Ren_Print("WARNING: RE_ProjectDecal() Max decal projectors reached (%d)\n", MAX_DECAL_PROJECTORS); return; } // dummy check if (numPoints != 1 && numPoints != 3 && numPoints != 4) { Ren_Print("WARNING: RE_ProjectDecal() Invalid number of decal points (%d)\n", numPoints); return; } // early outs if (lifeTime == 0) { Ren_Developer("WARNING: RE_ProjectDecal() lifeTime == 0\n"); // modders should have a look at this - vanilla does these calls return; } if (projection[3] <= 0.0f) { Ren_Print("WARNING: RE_ProjectDecal() projection[3] <= 0.0f\n"); return; } // set times properly if (lifeTime < 0 || fadeTime < 0) { lifeTime = 0; fadeTime = 0; } // basic setup temp.shader = R_GetShaderByHandle(hShader); temp.color[0] = (byte)(color[0] * 255); temp.color[1] = (byte)(color[1] * 255); temp.color[2] = (byte)(color[2] * 255); temp.color[3] = (byte)(color[3] * 255); temp.numPlanes = numPoints + 2; temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; // FIXME: stale refdef time temp.fadeEndTime = temp.fadeStartTime + fadeTime; temp.projectorNum = 0; // set up decal texcoords (FIXME: support arbitrary projector st coordinates in trapcall) dv[0].st[0] = 0.0f; dv[0].st[1] = 0.0f; dv[1].st[0] = 0.0f; dv[1].st[1] = 1.0f; dv[2].st[0] = 1.0f; dv[2].st[1] = 1.0f; dv[3].st[0] = 1.0f; dv[3].st[1] = 0.0f; // omnidirectional? if (numPoints == 1) { float radius; float iDist; // set up omnidirectional numPoints = 4; temp.numPlanes = 6; temp.omnidirectional = qtrue; radius = projection[3]; Vector4Set(projection, 0.0f, 0.0f, -1.0f, radius * 2.0f); iDist = 1.0f / (radius * 2.0f); // set corner VectorSet(xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius); // make x axis texture matrix (yz) VectorSet(temp.texMat[0][0], 0.0f, iDist, 0.0f); temp.texMat[0][0][3] = -DotProduct(temp.texMat[0][0], xyz); VectorSet(temp.texMat[0][1], 0.0f, 0.0f, iDist); temp.texMat[0][1][3] = -DotProduct(temp.texMat[0][1], xyz); // make y axis texture matrix (xz) VectorSet(temp.texMat[1][0], iDist, 0.0f, 0.0f); temp.texMat[1][0][3] = -DotProduct(temp.texMat[1][0], xyz); VectorSet(temp.texMat[1][1], 0.0f, 0.0f, iDist); temp.texMat[1][1][3] = -DotProduct(temp.texMat[1][1], xyz); // make z axis texture matrix (xy) VectorSet(temp.texMat[2][0], iDist, 0.0f, 0.0f); temp.texMat[2][0][3] = -DotProduct(temp.texMat[2][0], xyz); VectorSet(temp.texMat[2][1], 0.0f, iDist, 0.0f); temp.texMat[2][1][3] = -DotProduct(temp.texMat[2][1], xyz); // setup decal points VectorSet(dv[0].xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius); VectorSet(dv[1].xyz, points[0][0] - radius, points[0][1] + radius, points[0][2] + radius); VectorSet(dv[2].xyz, points[0][0] + radius, points[0][1] + radius, points[0][2] + radius); VectorSet(dv[3].xyz, points[0][0] + radius, points[0][1] - radius, points[0][2] + radius); } else { // set up unidirectional temp.omnidirectional = qfalse; // set up decal points VectorCopy(points[0], dv[0].xyz); VectorCopy(points[1], dv[1].xyz); VectorCopy(points[2], dv[2].xyz); VectorCopy(points[3], dv[3].xyz); // make texture matrix if (!MakeTextureMatrix(temp.texMat[0], projection, &dv[0], &dv[1], &dv[2])) { Ren_Print("WARNING: RE_ProjectDecal() MakeTextureMatrix returns NULL\n"); return; } } // bound the projector ClearBounds(temp.mins, temp.maxs); for (i = 0; i < numPoints; i++) { AddPointToBounds(dv[i].xyz, temp.mins, temp.maxs); VectorMA(dv[i].xyz, projection[3], projection, xyz); AddPointToBounds(xyz, temp.mins, temp.maxs); } // make bounding sphere VectorAdd(temp.mins, temp.maxs, temp.center); VectorScale(temp.center, 0.5f, temp.center); VectorSubtract(temp.maxs, temp.center, xyz); temp.radius = VectorLength(xyz); temp.radius2 = temp.radius * temp.radius; // make the front plane if (!PlaneFromPoints(temp.planes[0], dv[0].xyz, dv[1].xyz, dv[2].xyz)) { Ren_Developer("WARNING: RE_ProjectDecal() PlaneFromPoints is NULL\n"); // occurs on UJE_fueldump return; } // make the back plane VectorSubtract(vec3_origin, temp.planes[0], temp.planes[1]); VectorMA(dv[0].xyz, projection[3], projection, xyz); temp.planes[1][3] = DotProduct(xyz, temp.planes[1]); // make the side planes for (i = 0; i < numPoints; i++) { VectorMA(dv[i].xyz, projection[3], projection, xyz); if (!PlaneFromPoints(temp.planes[i + 2], dv[(i + 1) % numPoints].xyz, dv[i].xyz, xyz)) { Ren_Developer("WARNING: RE_ProjectDecal() a side plane is NULL\n"); // occurs on map venice return; } } // create a new projector dp = &backEndData->decalProjectors[r_numDecalProjectors]; Com_Memcpy(dp, &temp, sizeof(*dp)); dp->projectorNum = totalProjectors++; // we have a winner r_numDecalProjectors++; }
static int MakeDecalProjector( int mapEntityNum, shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv, float backfacecull, float lightmapScale, vec3_t lightmapAxis, vec3_t minlight, vec3_t minvertexlight, vec3_t ambient, vec3_t colormod, int smoothNormals ) { int i, j; decalProjector_t *dp; vec3_t xyz; /* dummy check */ if( numVerts != 3 && numVerts != 4 ) return -1; /* limit check */ if( numProjectors >= MAX_PROJECTORS ) { Sys_Warning( mapEntityNum, "MAX_PROJECTORS (%d) exceeded, no more decal projectors available.", MAX_PROJECTORS ); return -2; } /* create a new projector */ dp = &projectors[ numProjectors ]; memset( dp, 0, sizeof( decalProjector_t ) ); /* basic setup */ dp->si = si; dp->numPlanes = numVerts + 2; dp->backfacecull = backfacecull; dp->lightmapScale = lightmapScale; VectorCopy( lightmapAxis, dp->lightmapAxis ); VectorCopy( minlight, dp->minlight ); VectorCopy( minvertexlight, dp->minvertexlight ); VectorCopy( ambient, dp->ambient ); VectorCopy( colormod, dp->colormod ); dp->smoothNormals = smoothNormals; dp->mapEntityNum = mapEntityNum; /* make texture matrix */ if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) ) return -1; /* bound the projector */ ClearBounds( dp->mins, dp->maxs ); for( i = 0; i < numVerts; i++ ) { AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs ); VectorMA( dv[ i ]->xyz, distance, projection, xyz ); AddPointToBounds( xyz, dp->mins, dp->maxs ); } /* make bouding sphere */ VectorAdd( dp->mins, dp->maxs, dp->center ); VectorScale( dp->center, 0.5f, dp->center ); VectorSubtract( dp->maxs, dp->center, xyz ); dp->radius = VectorLength( xyz ); dp->radius2 = dp->radius * dp->radius; /* make the front plane */ if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) ) return -1; /* make the back plane */ VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] ); VectorMA( dv[ 0 ]->xyz, distance, projection, xyz ); dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] ); /* make the side planes */ for( i = 0; i < numVerts; i++ ) { j = (i + 1) % numVerts; VectorMA( dv[ i ]->xyz, distance, projection, xyz ); if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) ) return -1; } /* return ok */ numProjectors++; return numProjectors - 1; }