void ProcessDecals( void ) { int i, j, x, y, pw[ 5 ], r, iterations; float distance; vec4_t projection, plane; vec3_t origin, target, delta; entity_t *e, *e2; parseMesh_t *p; mesh_t *mesh, *subdivided; bspDrawVert_t *dv[4]; const char *value; /* note it */ MsgDev( D_NOTE, "--- ProcessDecals ---\n" ); /* walk entity list */ for( i = 0; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; value = ValueForKey( e, "classname" ); if( com.stricmp( value, "_decal" ) ) continue; /* any patches? */ if( e->patches == NULL ) { MsgDev( D_WARN, "Decal entity without any patch meshes, ignoring.\n" ); e->epairs = NULL; /* fixme: leak! */ continue; } /* find target */ value = ValueForKey( e, "target" ); e2 = FindTargetEntity( value ); /* no target? */ if( e2 == NULL ) { MsgDev( D_WARN, "Decal entity without a valid target, ignoring.\n" ); continue; } /* walk entity patches */ for( p = e->patches; p != NULL; p = e->patches ) { /* setup projector */ if( VectorCompare( e->origin, vec3_origin ) ) { VectorAdd( p->eMins, p->eMaxs, origin ); VectorScale( origin, 0.5f, origin ); } else VectorCopy( e->origin, origin ); VectorCopy( e2->origin, target ); VectorSubtract( target, origin, delta ); /* setup projection plane */ distance = VectorNormalizeLength2( delta, projection ); projection[ 3 ] = DotProduct( origin, projection ); /* create projectors */ if( distance > 0.125f ) { /* tesselate the patch */ iterations = IterationsForCurve( p->longestCurve, patch_subdivide->integer ); subdivided = SubdivideMesh2( p->mesh, iterations ); /* fit it to the curve and remove colinear verts on rows/columns */ PutMeshOnCurve( *subdivided ); mesh = RemoveLinearMeshColumnsRows( subdivided ); FreeMesh( subdivided ); /* offset by projector origin */ for( j = 0; j < (mesh->width * mesh->height); j++ ) VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz ); /* iterate through the mesh quads */ for( y = 0; y < (mesh->height - 1); y++ ) { for( x = 0; x < (mesh->width - 1); x++ ) { /* set indexes */ pw[ 0 ] = x + (y * mesh->width); pw[ 1 ] = x + ((y + 1) * mesh->width); pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); pw[ 3 ] = x + 1 + (y * mesh->width); pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ /* set radix */ r = (x + y) & 1; /* get drawverts */ dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ]; dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ]; dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ]; dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ]; /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */ plane[ 0 ] = 0.0f; /* stupid msvc */ if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) && fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON ) { /* make a quad projector */ MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv ); } else { /* make first triangle */ MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv ); /* make second triangle */ dv[ 1 ] = dv[ 2 ]; dv[ 2 ] = dv[ 3 ]; MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv ); } } } /* clean up */ Mem_Free( mesh ); } /* remove patch from entity (fixme: leak!) */ e->patches = p->next; /* push patch to worldspawn (enable this to debug projectors) */ #if 0 p->next = entities[ 0 ].patches; entities[ 0 ].patches = p; #endif } } /* emit some stats */ MsgDev( D_NOTE, "%9d decal projectors\n", numProjectors ); }
static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds ) { int x, y, pw[ 5 ], r, iterations; vec4_t plane; float d; mesh_t src, *mesh, *subdivided; winding_t *w; /* 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 < dp->backfacecull ) return; } /* tesselate the patch */ src.width = ds->patchWidth; src.height = ds->patchHeight; src.verts = ds->verts; iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions ); subdivided = SubdivideMesh2( src, iterations ); /* fit it to the curve and remove colinear verts on rows/columns */ PutMeshOnCurve( *subdivided ); mesh = RemoveLinearMeshColumnsRows( subdivided ); FreeMesh( subdivided ); /* iterate through the mesh quads */ for( y = 0; y < (mesh->height - 1); y++ ) { for( x = 0; x < (mesh->width - 1); x++ ) { /* set indexes */ pw[ 0 ] = x + (y * mesh->width); pw[ 1 ] = x + ((y + 1) * mesh->width); pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); pw[ 3 ] = x + 1 + (y * mesh->width); pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ /* set radix */ r = (x + y) & 1; /* generate decal for first triangle */ w = AllocWinding( 3 ); w->numpoints = 3; VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] ); VectorCopy( mesh->verts[ pw[ r + 1 ] ].xyz, w->p[ 1 ] ); VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 2 ] ); ProjectDecalOntoWinding( dp, ds, w ); /* generate decal for second triangle */ w = AllocWinding( 3 ); w->numpoints = 3; VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] ); VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 1 ] ); VectorCopy( mesh->verts[ pw[ r + 3 ] ].xyz, w->p[ 2 ] ); ProjectDecalOntoWinding( dp, ds, w ); } } /* clean up */ free( mesh ); }
void TriangulatePatchSurface( mapDrawSurface_t *ds ){ int iterations, x, y, pw[ 5 ], r; mapDrawSurface_t *dsNew; mesh_t src, *subdivided, *mesh; /* try to early out */ if ( ds->numVerts == 0 || ds->type != SURFACE_PATCH || patchMeta == qfalse ) { return; } /* make a mesh from the drawsurf */ src.width = ds->patchWidth; src.height = ds->patchHeight; src.verts = ds->verts; //% subdivided = SubdivideMesh( src, 8, 999 ); iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions ); subdivided = SubdivideMesh2( src, iterations ); //% ds->maxIterations /* fit it to the curve and remove colinear verts on rows/columns */ PutMeshOnCurve( *subdivided ); mesh = RemoveLinearMeshColumnsRows( subdivided ); FreeMesh( subdivided ); //% MakeMeshNormals( mesh ); /* make a copy of the drawsurface */ dsNew = AllocDrawSurface( SURFACE_META ); memcpy( dsNew, ds, sizeof( *ds ) ); /* if the patch is nonsolid, then discard it */ if ( !( ds->shaderInfo->compileFlags & C_SOLID ) ) { ClearSurface( ds ); } /* set new pointer */ ds = dsNew; /* basic transmogrification */ ds->type = SURFACE_META; ds->numIndexes = 0; ds->indexes = safe_malloc( mesh->width * mesh->height * 6 * sizeof( int ) ); /* copy the verts in */ ds->numVerts = ( mesh->width * mesh->height ); ds->verts = mesh->verts; /* iterate through the mesh quads */ for ( y = 0; y < ( mesh->height - 1 ); y++ ) { for ( x = 0; x < ( mesh->width - 1 ); x++ ) { /* set indexes */ pw[ 0 ] = x + ( y * mesh->width ); pw[ 1 ] = x + ( ( y + 1 ) * mesh->width ); pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width ); pw[ 3 ] = x + 1 + ( y * mesh->width ); pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */ /* set radix */ r = ( x + y ) & 1; /* make first triangle */ ds->indexes[ ds->numIndexes++ ] = pw[ r + 0 ]; ds->indexes[ ds->numIndexes++ ] = pw[ r + 1 ]; ds->indexes[ ds->numIndexes++ ] = pw[ r + 2 ]; /* make second triangle */ ds->indexes[ ds->numIndexes++ ] = pw[ r + 0 ]; ds->indexes[ ds->numIndexes++ ] = pw[ r + 2 ]; ds->indexes[ ds->numIndexes++ ] = pw[ r + 3 ]; } } /* free the mesh, but not the verts */ free( mesh ); /* add to count */ numPatchMetaSurfaces++; /* classify it */ ClassifySurfaces( 1, ds ); }
void ProcessDecals( void ) { int i, j, x, y, pw[ 5 ], r, iterations, smoothNormals; float distance, lightmapScale, backfaceAngle; vec4_t projection, plane; vec3_t origin, target, delta, lightmapAxis; vec3_t minlight, minvertexlight, ambient, colormod; entity_t *e, *e2; parseMesh_t *p; mesh_t *mesh, *subdivided; bspDrawVert_t *dv[ 4 ]; const char *value; /* note it */ Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" ); /* no decals */ if (nodecals) { for( i = 0; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; value = ValueForKey( e, "classname" ); if( Q_stricmp( value, "_decal" ) && Q_stricmp( value, "misc_decal" ) ) continue; /* clear entity patches */ e->patches = NULL; // fixme: LEAK! } return; } /* walk entity list */ for( i = 0; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; value = ValueForKey( e, "classname" ); if( Q_stricmp( value, "_decal" ) && Q_stricmp( value, "misc_decal" ) ) continue; /* any patches? */ if( e->patches == NULL ) { Sys_Warning( e->mapEntityNum, "Decal entity without any patch meshes, ignoring." ); e->epairs = NULL; /* fixme: leak! */ continue; } /* find target */ value = ValueForKey( e, "target" ); e2 = FindTargetEntity( value ); /* no target? */ if( e2 == NULL ) { Sys_Warning( e->mapEntityNum, "Decal entity without a valid target, ignoring." ); continue; } /* vortex: get lightmap scaling value for this entity */ GetEntityLightmapScale( e, &lightmapScale, 0); /* vortex: get lightmap axis for this entity */ GetEntityLightmapAxis( e, lightmapAxis, NULL ); /* vortex: per-entity normal smoothing */ GetEntityNormalSmoothing( e, &smoothNormals, 0); /* vortex: per-entity _minlight, _ambient, _color, _colormod */ GetEntityMinlightAmbientColor( e, NULL, minlight, minvertexlight, ambient, colormod, qtrue ); /* vortex: _backfacecull */ if ( KeyExists(e, "_backfacecull") ) backfaceAngle = FloatForKey(e, "_backfacecull"); else if ( KeyExists(e, "_bfc") ) backfaceAngle = FloatForKey(e, "_bfc"); else backfaceAngle = 90.0f; /* walk entity patches */ for( p = e->patches; p != NULL; p = e->patches ) { /* setup projector */ if( VectorCompare( e->origin, vec3_origin ) ) { VectorAdd( p->eMins, p->eMaxs, origin ); VectorScale( origin, 0.5f, origin ); } else VectorCopy( e->origin, origin ); VectorCopy( e2->origin, target ); VectorSubtract( target, origin, delta ); /* setup projection plane */ distance = VectorNormalize( delta, projection ); projection[ 3 ] = DotProduct( origin, projection ); /* create projectors */ if( distance > 0.125f ) { /* tesselate the patch */ iterations = IterationsForCurve( p->longestCurve, patchSubdivisions ); subdivided = SubdivideMesh2( p->mesh, iterations ); /* fit it to the curve and remove colinear verts on rows/columns */ PutMeshOnCurve( *subdivided ); mesh = RemoveLinearMeshColumnsRows( subdivided ); FreeMesh( subdivided ); /* offset by projector origin */ for( j = 0; j < (mesh->width * mesh->height); j++ ) VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz ); /* iterate through the mesh quads */ for( y = 0; y < (mesh->height - 1); y++ ) { for( x = 0; x < (mesh->width - 1); x++ ) { /* set indexes */ pw[ 0 ] = x + (y * mesh->width); pw[ 1 ] = x + ((y + 1) * mesh->width); pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); pw[ 3 ] = x + 1 + (y * mesh->width); pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ /* set radix */ r = (x + y) & 1; /* get drawverts */ dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ]; dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ]; dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ]; dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ]; /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */ plane[ 0 ] = 0.0f; /* stupid msvc */ if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) && fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON ) { /* make a quad projector */ MakeDecalProjector( i, p->shaderInfo, projection, distance, 4, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals); } else { /* make first triangle */ MakeDecalProjector( i, p->shaderInfo, projection, distance, 3, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals); /* make second triangle */ dv[ 1 ] = dv[ 2 ]; dv[ 2 ] = dv[ 3 ]; MakeDecalProjector( i, p->shaderInfo, projection, distance, 3, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals); } } } /* clean up */ free( mesh ); } /* remove patch from entity (fixme: leak!) */ e->patches = p->next; /* push patch to worldspawn (enable this to debug projectors) */ #if 0 p->next = entities[ 0 ].patches; entities[ 0 ].patches = p; #endif } } /* emit some stats */ Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors ); }