Пример #1
0
/*
================
DrawSurfaceForMesh
================
*/
mapDrawSurface_t	*DrawSurfaceForMesh( mesh_t *m ) {
	mapDrawSurface_t	*ds;
	int				i, j;
	mesh_t			*copy;

	// to make valid normals for patches with degenerate edges,
	// we need to make a copy of the mesh and put the aproximating
	// points onto the curve
	copy = CopyMesh( m );
	PutMeshOnCurve( *copy );
	MakeMeshNormals( *copy );
	for ( j = 0 ; j < m->width ; j++ ) {
		for ( i = 0 ; i < m->height ; i++ ) {
			VectorCopy( copy->verts[i*m->width+j].normal, m->verts[i*m->width+j].normal );
		}
	}
	FreeMesh( copy );

	ds = AllocDrawSurf();
	ds->mapBrush = NULL;
	ds->side = NULL;

	ds->patch = qtrue;
	ds->patchWidth = m->width;
	ds->patchHeight = m->height;
	ds->numVerts = ds->patchWidth * ds->patchHeight;
	ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
	memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );

	ds->lightmapNum = -1;
	ds->fogNum = -1;

	return ds;
}
Пример #2
0
/*
====================
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);
}
Пример #3
0
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;
		}
	}
}
Пример #4
0
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;
		}
	}
}
Пример #5
0
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 );
}
Пример #6
0
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 );
}
Пример #7
0
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 );
}
Пример #9
0
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 );
}