Пример #1
0
void ExportEntities( void ){
        char filename[ 1024 ];
        FILE *file;

        /* note it */
        Sys_FPrintf( SYS_VRB, "--- ExportEntities ---\n" );

        /* do some path mangling */
        strcpy( filename, source );
        StripExtension( filename );
        strcat( filename, ".ent" );

        /* sanity check */
        if ( bspEntData == NULL || bspEntDataSize == 0 ) {
                Sys_Warning( "No BSP entity data. aborting...\n" );
                return;
        }

        /* write it */
        Sys_Printf( "Writing %s\n", filename );
        Sys_FPrintf( SYS_VRB, "(%d bytes)\n", bspEntDataSize );
        file = fopen( filename, "w" );

        if ( file == NULL ) {
                Error( "Unable to open %s for writing", filename );
        }

        fprintf( file, "%s\n", bspEntData );
        fclose( file );
}
Пример #2
0
void FreeBrush( brush_t *b )
{
    int			i;


    /* error check */
    if( *((int*) b) == 0xFEFEFEFE )
    {
        Sys_Warning( "Attempt to free an already freed brush!" );
        return;
    }

    /* free brush sides */
    for( i = 0; i < b->numsides; i++ )
        if( b->sides[i].winding != NULL )
            FreeWinding( b->sides[ i ].winding );

    /* ydnar: overwrite it */
    memset( b, 0xFE, (int) &(((brush_t*) 0)->sides[ b->numsides ]) );
    *((int*) b) = 0xFEFEFEFE;

    /* free it */
    free( b );
    if( numthreads == 1 )
        numActiveBrushes--;
}
Пример #3
0
/* DESCRIPTION: COM_WriteFile
// LOCATION: NOT the info_write thing that's in common.c
// PATH:
//
// We make a file and write to it.  The target is the game directory.
// Until I rework the various systems and better know how HL should
// signify which dir to write to, we use this cheap trick:
// The first dir on the list should be the game dir (unless another was aded).
// So just open the file regularly and it'll be in the right place.
*/
void COM_WriteFile(char *filename, void *filedata, int length) {

   hl_file_t *fp;
   char * c;
   c = strrchr(filename, '/');

   if(c != NULL) {

      *c = '\0';
      FS_CreateDirHierarchy(filename, NULL);
      *c = '/';
   }

   fp = FS_Open(filename, "wb");
   if (!fp) {
      Sys_Warning("COM_WriteFile: Couldn't open some file %s.\n", filename);
   }
   else {
      if(FS_Write(filedata, 1, length, fp) != length) {
         Sys_Warning("COM_WriteFile: Didn't manage to write all of file %s.\n", filename);
      }
      FS_Close(fp);
   }
}
Пример #4
0
static void R_DefineEdge( int v1, int v2, int planeNum ) {
	int		i;

	// check for degenerate edge
	if ( v1 == v2 ) {
		return;
	}
	// search for a matching other side
	for ( i = 0; i<numSilEdges; ++i) {
		if ( silEdges[i].v1 == v1 && silEdges[i].v2 == v2 ) {
			c_duplicatedEdges++;
			// allow it to still create a new edge
			continue;
		}
		if ( silEdges[i].v2 == v1 && silEdges[i].v1 == v2 ) {
			if ( silEdges[i].p2 != numPlanes )  {
				c_tripledEdges++;
				// allow it to still create a new edge
				continue;
			}
			// this is a matching back side
			silEdges[i].p2 = planeNum;
			return;
		}

	}

	// define the new edge
	if ( numSilEdges == MAX_SIL_EDGES ) {
		Sys_Warning( "MAX_SIL_EDGES" );
		return;
	}
	
	silEdges[numSilEdges].p1 = planeNum;
	silEdges[numSilEdges].p2 = numPlanes;
	silEdges[numSilEdges].v1 = v1;
	silEdges[numSilEdges].v2 = v2;

	numSilEdges++;
}
Пример #5
0
/*
   =============
   GetThreadWork

   =============
 */
int GetThreadWork( void ){
	int r;
	int f;

	ThreadLock();

	if ( dispatch == workcount ) {
		ThreadUnlock();
		return -1;
	}

	f = 40 * dispatch / workcount;
	if ( f < oldf ) {
		Sys_Warning( "progress went backwards (should never happen)\n" );
		oldf = f;
	}
	while ( f > oldf )
	{
		++oldf;
		if ( pacifier ) {
			if ( oldf % 4 == 0 ) {
				Sys_Printf( "%i", f / 4 );
			}
			else{
				Sys_Printf( "." );
			}
			fflush( stdout );   /* ydnar */
		}
	}

	r = dispatch;
	dispatch++;
	ThreadUnlock();

	return r;
}
Пример #6
0
void ParsePatch( qboolean onlyLights )
{
	vec_t			info[ 5 ];
	int				i, j, k;
	parseMesh_t		*pm;
	char			texture[ MAX_QPATH ];
	char			shader[ MAX_QPATH ];
	mesh_t			m;
	bspDrawVert_t	*verts;
	epair_t			*ep;
	vec4_t			delta, delta2, delta3;
	qboolean		degenerate;
	float			longestCurve;
	int				maxIterations;
	
	MatchToken( "{" );
	
	/* get texture */
	GetToken( qtrue );
	strcpy( texture, token );
	
	Parse1DMatrix( 5, info );
	m.width = info[0];
	m.height = info[1];
	m.verts = verts = (bspDrawVert_t *)safe_malloc( m.width * m.height * sizeof( m.verts[0] ) );
	
	if( m.width < 0 || m.width > MAX_PATCH_SIZE || m.height < 0 || m.height > MAX_PATCH_SIZE )
		Error( "ParsePatch: bad size" );
	
	MatchToken( "(" );
	for( j = 0; j < m.width ; j++ )
	{
		MatchToken( "(" );
		for( i = 0; i < m.height ; i++ )
		{
			Parse1DMatrix( 5, verts[ i * m.width + j ].xyz );
			
			/* ydnar: fix colors */
			for( k = 0; k < MAX_LIGHTMAPS; k++ )
			{
				verts[ i * m.width + j ].color[ k ][ 0 ] = 255;
				verts[ i * m.width + j ].color[ k ][ 1 ] = 255;
				verts[ i * m.width + j ].color[ k ][ 2 ] = 255;
				verts[ i * m.width + j ].color[ k ][ 3 ] = 255;
			}
		}
		MatchToken( ")" );
	}
	MatchToken( ")" );

	// if brush primitives format, we may have some epairs to ignore here
	GetToken(qtrue);
	if (g_bBrushPrimit!=BPRIMIT_OLDBRUSHES && strcmp(token,"}"))
	{
		// NOTE: we leak that!
		ep = ParseEPair();
	}
	else
		UnGetToken();

	MatchToken( "}" );
	MatchToken( "}" );
	
	/* short circuit */
	if( noCurveBrushes || onlyLights )
		return;
	
	
	/* ydnar: delete and warn about degenerate patches */
	j = (m.width * m.height);
	VectorClear( delta );
	delta[ 3 ] = 0;
	degenerate = qtrue;
	
	/* find first valid vector */
	for( i = 1; i < j && delta[ 3 ] == 0; i++ )
	{
		VectorSubtract( m.verts[ 0 ].xyz, m.verts[ i ].xyz, delta );
		delta[ 3 ] = VectorNormalize( delta, delta );
	}
	
	/* secondary degenerate test */
	if( delta[ 3 ] == 0 )
		degenerate = qtrue;
	else
	{
		/* if all vectors match this or are zero, then this is a degenerate patch */
		for( i = 1; i < j && degenerate == qtrue; i++ )
		{
			VectorSubtract( m.verts[ 0 ].xyz, m.verts[ i ].xyz, delta2 );
			delta2[ 3 ] = VectorNormalize( delta2, delta2 );
			if( delta2[ 3 ] != 0 )
			{
				/* create inverse vector */
				VectorCopy( delta2, delta3 );
				delta3[ 3 ] = delta2[ 3 ];
				VectorNegate( delta3, delta3 );
				
				/* compare */
				if( VectorCompare( delta, delta2 ) == qfalse && VectorCompare( delta, delta3 ) == qfalse )
					degenerate = qfalse;
			}
		}
	}
	
	/* warn and select degenerate patch */
	if( degenerate )
	{
		Sys_Warning( mapEnt->mapEntityNum, entitySourceBrushes, "Degenerate patch" );
		free( m.verts );
		return;
	}
	
	/* find longest curve on the mesh */
	longestCurve = 0.0f;
	maxIterations = 0;
	for( j = 0; j + 2 < m.width; j += 2 )
	{
		for( i = 0; i + 2 < m.height; i += 2 )
		{
			ExpandLongestCurve( &longestCurve, verts[ i * m.width + j ].xyz, verts[ i * m.width + (j + 1) ].xyz, verts[ i * m.width + (j + 2) ].xyz );		/* row */
			ExpandLongestCurve( &longestCurve, verts[ i * m.width + j ].xyz, verts[ (i + 1) * m.width + j ].xyz, verts[ (i + 2) * m.width + j ].xyz );		/* col */
			ExpandMaxIterations( &maxIterations, patchSubdivisions, verts[ i * m.width + j ].xyz, verts[ i * m.width + (j + 1) ].xyz, verts[ i * m.width + (j + 2) ].xyz );		/* row */
			ExpandMaxIterations( &maxIterations, patchSubdivisions, verts[ i * m.width + j ].xyz, verts[ (i + 1) * m.width + j ].xyz, verts[ (i + 2) * m.width + j ].xyz  );	/* col */
		}
	}
	
	/* allocate patch mesh */
	pm = (parseMesh_t *)safe_malloc( sizeof( *pm ) );
	memset( pm, 0, sizeof( *pm ) );
	
	/* ydnar: add entity/brush numbering */
	pm->entityNum = mapEnt->mapEntityNum;
	pm->mapEntityNum = mapEnt->mapEntityNum;
	pm->brushNum = entitySourceBrushes;
	
	/* set shader */
	sprintf( shader, "textures/%s", texture );
	pm->shaderInfo = ShaderInfoForShader( shader );
	
	/* set mesh */
	pm->mesh = m;
	
	/* set longest curve */
	pm->longestCurve = longestCurve;
	pm->maxIterations = maxIterations;
	
	/* link to the entity */
	pm->next = mapEnt->patches;
	mapEnt->patches = pm;
}
Пример #7
0
void R_IdentifySilEdges( srfTriangles_t *tri ) {
	int		i;
	int		numTris;
	int		shared, single;

	numTris = tri->numIndices / 3;

	numSilEdges = 0;
	numPlanes = numTris;

	c_duplicatedEdges = 0;
	c_tripledEdges = 0;

	for ( i = 0 ; i < numTris ; i++ ) {
		int		i1, i2, i3;

		i1 = tri->silIndices[ i*3 + 0 ];
		i2 = tri->silIndices[ i*3 + 1 ];
		i3 = tri->silIndices[ i*3 + 2 ];

		// create the edges
		R_DefineEdge( i1, i2, i );
		R_DefineEdge( i2, i3, i );
		R_DefineEdge( i3, i1, i );
	}

	if ( c_duplicatedEdges || c_tripledEdges ) {
		Sys_Warning( "%i duplicated edge directions, %i tripled edges", c_duplicatedEdges, c_tripledEdges );
	}

	// if we know that the vertexes aren't going
	// to deform, we can remove interior triangulation edges
	// on otherwise planar polygons.
	// I earlier believed that I could also remove concave
	// edges, because they are never silhouettes in the conventional sense,
	// but they are still needed to balance out all the true sil edges
	// for the shadow algorithm to function
	int		c_coplanarCulled;

	c_coplanarCulled = 0;
	c_totalSilEdges += numSilEdges;

	// sort the sil edges based on plane number
	qsort( silEdges, numSilEdges, sizeof( silEdges[0] ), SilEdgeSort );

	// count up the distribution.
	// a perfectly built model should only have shared
	// edges, but most models will have some interpenetration
	// and dangling edges
	shared = 0;
	single = 0;
	for ( i = 0 ; i < numSilEdges ; i++ ) {
		if ( silEdges[i].p2 == numPlanes ) {
			sigIndice[single*2] = silEdges[i].v1;
			sigIndice[single*2 + 1] = silEdges[i].v2;
			single++;
		} else {
			shared++;
		}
	}

	if ( !single ) {
		tri->perfectHull = true;
	} else {
		tri->perfectHull = false;
		Sys_Warning("built model has single edges %d\n", single);
	}

	tri->numSilEdges = numSilEdges;
	tri->silEdges = (silEdge_t*)mem_alloc( numSilEdges * sizeof(silEdge_t) );
	memcpy( tri->silEdges, silEdges, numSilEdges * sizeof( tri->silEdges[0] ) );

}
Пример #8
0
void LoadSurfaceExtraFile( const char *path ){
	char srfPath[ 1024 ];
	surfaceExtra_t  *se;
	int surfaceNum, size;
	byte            *buffer;


	/* dummy check */
	if ( path == NULL || path[ 0 ] == '\0' ) {
		return;
	}

	/* load the file */
	strcpy( srfPath, path );
	StripExtension( srfPath );
	strcat( srfPath, ".srf" );
	Sys_Printf( "Loading %s\n", srfPath );
	size = LoadFile( srfPath, (void**) &buffer );
	if ( size <= 0 ) {
		Sys_Warning( "Unable to find surface file %s, using defaults.\n", srfPath );
		return;
	}

	/* parse the file */
	ParseFromMemory( (char *) buffer, size );

	/* tokenize it */
	while ( 1 )
	{
		/* test for end of file */
		if ( !GetToken( qtrue ) ) {
			break;
		}

		/* default? */
		if ( !Q_stricmp( token, "default" ) ) {
			se = &seDefault;
		}

		/* surface number */
		else
		{
			surfaceNum = atoi( token );
			if ( surfaceNum < 0 || surfaceNum > MAX_MAP_DRAW_SURFS ) {
				Error( "ReadSurfaceExtraFile(): %s, line %d: bogus surface num %d", srfPath, scriptline, surfaceNum );
			}
			while ( surfaceNum >= numSurfaceExtras )
				se = AllocSurfaceExtra();
			se = &surfaceExtras[ surfaceNum ];
		}

		/* handle { } section */
		if ( !GetToken( qtrue ) || strcmp( token, "{" ) ) {
			Error( "ReadSurfaceExtraFile(): %s, line %d: { not found", srfPath, scriptline );
		}
		while ( 1 )
		{
			if ( !GetToken( qtrue ) ) {
				break;
			}
			if ( !strcmp( token, "}" ) ) {
				break;
			}

			/* shader */
			if ( !Q_stricmp( token, "shader" ) ) {
				GetToken( qfalse );
				se->si = ShaderInfoForShader( token );
			}

			/* parent surface number */
			else if ( !Q_stricmp( token, "parent" ) ) {
				GetToken( qfalse );
				se->parentSurfaceNum = atoi( token );
			}

			/* entity number */
			else if ( !Q_stricmp( token, "entity" ) ) {
				GetToken( qfalse );
				se->entityNum = atoi( token );
			}

			/* cast shadows */
			else if ( !Q_stricmp( token, "castShadows" ) ) {
				GetToken( qfalse );
				se->castShadows = atoi( token );
			}

			/* recv shadows */
			else if ( !Q_stricmp( token, "receiveShadows" ) ) {
				GetToken( qfalse );
				se->recvShadows = atoi( token );
			}

			/* lightmap sample size */
			else if ( !Q_stricmp( token, "sampleSize" ) ) {
				GetToken( qfalse );
				se->sampleSize = atoi( token );
			}

			/* longest curve */
			else if ( !Q_stricmp( token, "longestCurve" ) ) {
				GetToken( qfalse );
				se->longestCurve = atof( token );
			}

			/* lightmap axis vector */
			else if ( !Q_stricmp( token, "lightmapAxis" ) ) {
				Parse1DMatrix( 3, se->lightmapAxis );
			}

			/* ignore all other tokens on the line */
			while ( TokenAvailable() )
				GetToken( qfalse );
		}
	}

	/* free the buffer */
	free( buffer );
}
Пример #9
0
void SplitBrush( brush_t *brush, int planenum, brush_t **front, brush_t **back )
{
    brush_t		*b[2];
    int			i, j;
    winding_t	*w, *cw[2], *midwinding;
    plane_t		*plane, *plane2;
    side_t		*s, *cs;
    float		d, d_front, d_back;


    *front = NULL;
    *back = NULL;
    plane = &mapplanes[planenum];

    // check all points
    d_front = d_back = 0;
    for (i=0 ; i<brush->numsides ; i++)
    {
        w = brush->sides[i].winding;
        if (!w)
            continue;
        for (j=0 ; j<w->numpoints ; j++)
        {
            d = DotProduct (w->p[j], plane->normal) - plane->dist;
            if (d > 0 && d > d_front)
                d_front = d;
            if (d < 0 && d < d_back)
                d_back = d;
        }
    }

    if (d_front < 0.1) // PLANESIDE_EPSILON)
    {   // only on back
        *back = CopyBrush( brush );
        return;
    }

    if (d_back > -0.1) // PLANESIDE_EPSILON)
    {   // only on front
        *front = CopyBrush( brush );
        return;
    }

    // create a new winding from the split plane
    w = BaseWindingForPlane (plane->normal, plane->dist);
    for (i=0 ; i<brush->numsides && w ; i++)
    {
        plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
        ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0);
    }

    if (!w || WindingIsTiny (w) )
    {   // the brush isn't really split
        int		side;

        side = BrushMostlyOnSide (brush, plane);
        if (side == PSIDE_FRONT)
            *front = CopyBrush (brush);
        if (side == PSIDE_BACK)
            *back = CopyBrush (brush);
        return;
    }

    if( WindingIsHuge( w ) )
        Sys_Warning( w, "Huge winding" );

    midwinding = w;

    // split it for real

    for (i=0 ; i<2 ; i++)
    {
        b[i] = AllocBrush (brush->numsides+1);
        memcpy( b[i], brush, sizeof( brush_t ) - sizeof( brush->sides ) );
        b[i]->numsides = 0;
        b[i]->next = NULL;
        b[i]->original = brush->original;
    }

    // split all the current windings

    for (i=0 ; i<brush->numsides ; i++)
    {
        s = &brush->sides[i];
        w = s->winding;
        if (!w)
            continue;
        ClipWindingEpsilon (w, plane->normal, plane->dist,
                            0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
        for (j=0 ; j<2 ; j++)
        {
            if (!cw[j])
                continue;
            cs = &b[j]->sides[b[j]->numsides];
            b[j]->numsides++;
            *cs = *s;
            cs->winding = cw[j];
        }
    }


    // see if we have valid polygons on both sides
    for (i=0 ; i<2 ; i++)
    {
        if (b[i]->numsides < 3 || !BoundBrush (b[i]))
        {
            if (b[i]->numsides >= 3)
                Sys_FPrintf (SYS_VRB,"bogus brush after clip\n");
            FreeBrush (b[i]);
            b[i] = NULL;
        }
    }

    if ( !(b[0] && b[1]) )
    {
        if (!b[0] && !b[1])
            Sys_FPrintf (SYS_VRB,"split removed brush\n");
        else
            Sys_FPrintf (SYS_VRB,"split not on both sides\n");
        if (b[0])
        {
            FreeBrush (b[0]);
            *front = CopyBrush (brush);
        }
        if (b[1])
        {
            FreeBrush (b[1]);
            *back = CopyBrush (brush);
        }
        return;
    }

    // add the midwinding to both sides
    for (i=0 ; i<2 ; i++)
    {
        cs = &b[i]->sides[b[i]->numsides];
        b[i]->numsides++;

        cs->planenum = planenum^i^1;
        cs->shaderInfo = NULL;
        if (i==0)
            cs->winding = CopyWinding (midwinding);
        else
            cs->winding = midwinding;
    }

    {
        vec_t	v1;
        int		i;


        for (i=0 ; i<2 ; i++)
        {
            v1 = BrushVolume (b[i]);
            if (v1 < 1.0)
            {
                FreeBrush (b[i]);
                b[i] = NULL;
                //			Sys_FPrintf (SYS_VRB,"tiny volume after clip\n");
            }
        }
    }

    *front = b[0];
    *back = b[1];
}
Пример #10
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 );
}
Пример #11
0
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;
}