/* ==================== FacetsForPatch ==================== */ void FacetsForPatch( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) { int i, j; drawVert_t *v1, *v2, *v3, *v4; int count; mesh_t srcMesh, *subdivided, *mesh; srcMesh.width = dsurf->patchWidth; srcMesh.height = dsurf->patchHeight; srcMesh.verts = &drawVerts[ dsurf->firstVert ]; //subdivided = SubdivideMesh( mesh, CURVE_FACET_ERROR, 9999 ); mesh = SubdivideMesh( srcMesh, 8, 999 ); PutMeshOnCurve( *mesh ); MakeMeshNormals( *mesh ); subdivided = RemoveLinearMeshColumnsRows( mesh ); FreeMesh(mesh); test->patch = qtrue; test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2; test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets ); test->shader = si; count = 0; for ( i = 0 ; i < subdivided->width - 1 ; i++ ) { for ( j = 0 ; j < subdivided->height - 1 ; j++ ) { v1 = subdivided->verts + j * subdivided->width + i; v2 = v1 + 1; v3 = v1 + subdivided->width + 1; v4 = v1 + subdivided->width; if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v4, v3, v2 ) ) { count++; } else { if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v4, v3 )) count++; if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v3, v2 )) count++; } } } test->numFacets = count; FreeMesh(subdivided); }
void AllocateLightmapForPatch( mapDrawSurface_t *ds ) { int i, j, k; drawVert_t *verts; int w, h; int x, y; float s, t; mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh; int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize; verts = ds->verts; mesh.width = ds->patchWidth; mesh.height = ds->patchHeight; mesh.verts = verts; newmesh = SubdivideMesh( mesh, 8, 999 ); PutMeshOnCurve( *newmesh ); tempMesh = RemoveLinearMeshColumnsRows( newmesh ); FreeMesh(newmesh); ssize = samplesize; if (ds->shaderInfo->lightmapSampleSize) ssize = ds->shaderInfo->lightmapSampleSize; #ifdef LIGHTMAP_PATCHSHIFT subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable); #else subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable); #endif w = subdividedMesh->width; h = subdividedMesh->height; #ifdef LIGHTMAP_PATCHSHIFT w++; h++; #endif FreeMesh(subdividedMesh); // allocate the lightmap c_exactLightmap += w * h; if ( !AllocLMBlock( w, h, &x, &y ) ) { PrepareNewLightmap(); if ( !AllocLMBlock( w, h, &x, &y ) ) { Error("Entity %i, brush %i: Lightmap allocation failed", ds->mapBrush->entitynum, ds->mapBrush->brushnum ); } } #ifdef LIGHTMAP_PATCHSHIFT w--; h--; #endif // set the lightmap texture coordinates in the drawVerts ds->lightmapNum = numLightmaps - 1; ds->lightmapWidth = w; ds->lightmapHeight = h; ds->lightmapX = x; ds->lightmapY = y; for ( i = 0 ; i < ds->patchWidth ; i++ ) { for ( k = 0 ; k < w ; k++ ) { if ( originalWidths[k] >= i ) { break; } } if (k >= w) k = w-1; s = x + k; for ( j = 0 ; j < ds->patchHeight ; j++ ) { for ( k = 0 ; k < h ; k++ ) { if ( originalHeights[k] >= j ) { break; } } if (k >= h) k = h-1; t = y + k; verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH; verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT; } } }
static void PopulateWithBSPModel(bspModel_t * model, matrix_t transform) { int i, j, x, y, pw[5], r, nodeNum; bspDrawSurface_t *ds; surfaceInfo_t *info; bspDrawVert_t *verts; int *indexes; mesh_t srcMesh, *mesh, *subdivided; traceInfo_t ti; traceWinding_t tw; /* dummy check */ if(model == NULL || transform == NULL) return; /* walk the list of surfaces in this model and fill out the info structs */ for(i = 0; i < model->numBSPSurfaces; i++) { /* get surface and info */ ds = &bspDrawSurfaces[model->firstBSPSurface + i]; info = &surfaceInfos[model->firstBSPSurface + i]; if(info->si == NULL) continue; /* no shadows */ if(!info->castShadows) continue; /* patchshadows? */ if(ds->surfaceType == MST_PATCH && patchShadows == qfalse) continue; /* some surfaces in the bsp might have been tagged as nodraw, with a bogus shader */ if((bspShaders[ds->shaderNum].contentFlags & noDrawContentFlags) || (bspShaders[ds->shaderNum].surfaceFlags & noDrawSurfaceFlags)) continue; /* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */ if((info->si->compileFlags & C_NODRAW)) continue; if((info->si->compileFlags & C_TRANSLUCENT) && !(info->si->compileFlags & C_ALPHASHADOW) && !(info->si->compileFlags & C_LIGHTFILTER)) continue; /* setup trace info */ ti.si = info->si; ti.castShadows = info->castShadows; ti.surfaceNum = model->firstBSPBrush + i; ti.skipGrid = (ds->surfaceType == MST_PATCH); /* choose which node (normal or skybox) */ if(info->parentSurfaceNum >= 0) { nodeNum = skyboxNodeNum; /* sky surfaces in portal skies are ignored */ if(info->si->compileFlags & C_SKY) continue; } else nodeNum = headNodeNum; /* setup trace winding */ memset(&tw, 0, sizeof(tw)); tw.infoNum = AddTraceInfo(&ti); tw.numVerts = 3; /* switch on type */ switch (ds->surfaceType) { /* handle patches */ case MST_PATCH: /* subdivide the surface */ srcMesh.width = ds->patchWidth; srcMesh.height = ds->patchHeight; srcMesh.verts = &bspDrawVerts[ds->firstVert]; //% subdivided = SubdivideMesh( srcMesh, 8, 512 ); subdivided = SubdivideMesh2(srcMesh, info->patchIterations); /* fit it to the curve and remove colinear verts on rows/columns */ PutMeshOnCurve(*subdivided); mesh = RemoveLinearMeshColumnsRows(subdivided); FreeMesh(subdivided); /* set verts */ verts = mesh->verts; /* subdivide each quad to place the models */ 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 */ VectorCopy(verts[pw[r + 0]].xyz, tw.v[0].xyz); Vector2Copy(verts[pw[r + 0]].st, tw.v[0].st); VectorCopy(verts[pw[r + 1]].xyz, tw.v[1].xyz); Vector2Copy(verts[pw[r + 1]].st, tw.v[1].st); VectorCopy(verts[pw[r + 2]].xyz, tw.v[2].xyz); Vector2Copy(verts[pw[r + 2]].st, tw.v[2].st); MatrixTransformPoint2(transform, tw.v[0].xyz); MatrixTransformPoint2(transform, tw.v[1].xyz); MatrixTransformPoint2(transform, tw.v[2].xyz); FilterTraceWindingIntoNodes_r(&tw, nodeNum); /* make second triangle */ VectorCopy(verts[pw[r + 0]].xyz, tw.v[0].xyz); Vector2Copy(verts[pw[r + 0]].st, tw.v[0].st); VectorCopy(verts[pw[r + 2]].xyz, tw.v[1].xyz); Vector2Copy(verts[pw[r + 2]].st, tw.v[1].st); VectorCopy(verts[pw[r + 3]].xyz, tw.v[2].xyz); Vector2Copy(verts[pw[r + 3]].st, tw.v[2].st); MatrixTransformPoint2(transform, tw.v[0].xyz); MatrixTransformPoint2(transform, tw.v[1].xyz); MatrixTransformPoint2(transform, tw.v[2].xyz); FilterTraceWindingIntoNodes_r(&tw, nodeNum); } } /* free the subdivided mesh */ FreeMesh(mesh); break; /* handle triangle surfaces */ case MST_TRIANGLE_SOUP: case MST_PLANAR: /* set verts and indexes */ verts = &bspDrawVerts[ds->firstVert]; indexes = &bspDrawIndexes[ds->firstIndex]; /* walk the triangle list */ for(j = 0; j < ds->numIndexes; j += 3) { VectorCopy(verts[indexes[j]].xyz, tw.v[0].xyz); Vector2Copy(verts[indexes[j]].st, tw.v[0].st); VectorCopy(verts[indexes[j + 1]].xyz, tw.v[1].xyz); Vector2Copy(verts[indexes[j + 1]].st, tw.v[1].st); VectorCopy(verts[indexes[j + 2]].xyz, tw.v[2].xyz); Vector2Copy(verts[indexes[j + 2]].st, tw.v[2].st); MatrixTransformPoint2(transform, tw.v[0].xyz); MatrixTransformPoint2(transform, tw.v[1].xyz); MatrixTransformPoint2(transform, tw.v[2].xyz); FilterTraceWindingIntoNodes_r(&tw, nodeNum); } break; /* other surface types do not cast shadows */ default: break; } } }
void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ) { int i, x, y, v, t, pw[ 5 ], r; bspDrawSurface_t *ds; surfaceInfo_t *info; bspDrawVert_t *bogus; bspDrawVert_t *dv[ 4 ]; mesh_t src, *subdivided, *mesh; float *radVertexLuxel; float dist; vec4_t plane; qboolean planar; radWinding_t rw; /* get surface */ ds = &bspDrawSurfaces[ num ]; info = &surfaceInfos[ num ]; /* construct a bogus vert list with color index stuffed into color[ 0 ] */ bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) ); memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) ); for( i = 0; i < ds->numVerts; i++ ) bogus[ i ].color[ 0 ][ 0 ] = i; /* build a subdivided mesh identical to shadow facets for this patch */ /* this MUST MATCH FacetsForPatch() identically! */ src.width = ds->patchWidth; src.height = ds->patchHeight; src.verts = bogus; //% subdivided = SubdivideMesh( src, 8, 512 ); subdivided = SubdivideMesh2( src, info->patchIterations ); PutMeshOnCurve( *subdivided ); //% MakeMeshNormals( *subdivided ); mesh = RemoveLinearMeshColumnsRows( subdivided ); FreeMesh( subdivided ); free( bogus ); /* FIXME: build interpolation table into color[ 1 ] */ /* fix up color indexes */ for( i = 0; i < (mesh->width * mesh->height); i++ ) { dv[ 0 ] = &mesh->verts[ i ]; if( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts ) dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1; } /* 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? */ planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ); if( planar ) { dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ]; if( fabs( dist ) > PLANAR_EPSILON ) planar = qfalse; } /* generate a quad */ if( planar ) { rw.numVerts = 4; for( v = 0; v < 4; v++ ) { /* get most everything */ memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) ); /* fix colors */ for( i = 0; i < MAX_LIGHTMAPS; i++ ) { radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] ); VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] ); rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ]; } } /* subdivide into area lights */ RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw ); } /* generate 2 tris */ else { rw.numVerts = 3; for( t = 0; t < 2; t++ ) { for( v = 0; v < 3 + t; v++ ) { /* get "other" triangle (stupid hacky logic, but whatevah) */ if( v == 1 && t == 1 ) v++; /* get most everything */ memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) ); /* fix colors */ for( i = 0; i < MAX_LIGHTMAPS; i++ ) { radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] ); VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] ); rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ]; } } /* subdivide into area lights */ RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw ); } } } } /* free the mesh */ FreeMesh( mesh ); }
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 < -0.0001f ) return; } /* tesselate the patch */ src.width = ds->patchWidth; src.height = ds->patchHeight; src.verts = ds->verts; iterations = IterationsForCurve( ds->longestCurve, patch_subdivide->integer ); 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 */ Mem_Free( mesh ); }
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 ); }
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 ); }