Esempio n. 1
0
void MiniMapSetupBrushes(void)
{
	int             i, b, compileFlags;
	bspBrush_t     *brush;
	bspShader_t    *shader;
	shaderInfo_t   *si;


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

	/* allocate */
	if(opaqueBrushes == NULL)
		opaqueBrushes = safe_malloc(numBSPBrushes / 8 + 1);

	/* clear */
	memset(opaqueBrushes, 0, numBSPBrushes / 8 + 1);
	numOpaqueBrushes = 0;

	/* walk the list of worldspawn brushes */
	for(i = 0; i < minimap.model->numBSPBrushes; i++)
	{
		/* get brush */
		b = minimap.model->firstBSPBrush + i;
		brush = &bspBrushes[b];

#if 0
		/* check all sides */
		compileFlags = 0;
		for(j = 0; j < brush->numSides; j++)
		{
			/* do bsp shader calculations */
			side = &bspBrushSides[brush->firstSide + j];
			shader = &bspShaders[side->shaderNum];

			/* get shader info */
			si = ShaderInfoForShader(shader->shader);
			if(si == NULL)
				continue;

			/* or together compile flags */
			compileFlags |= si->compileFlags;
		}
#else
		shader = &bspShaders[brush->shaderNum];
		si = ShaderInfoForShader(shader->shader);
		if(si == NULL)
			compileFlags = 0;
		else
			compileFlags = si->compileFlags;
#endif

		/* determine if this brush is solid */
		if((compileFlags & (C_SOLID | C_SKY)) == C_SOLID)
		{
			opaqueBrushes[b >> 3] |= (1 << (b & 7));
			numOpaqueBrushes++;
			maxOpaqueBrush = i;
		}
	}
Esempio n. 2
0
void WriteTexFile( char* name){
	FILE			*texfile;
	char			filename[1024];
	int				i;

	sprintf (filename, "%s.tex", name);

	if(!compile_map){
		RestoreSurfaceFlags(filename);
	}

	Sys_Printf("Writing %s ...\n", filename);
	texfile = fopen (filename, "w");

	fprintf( texfile, "TEXFILE\n");

	fprintf( texfile, "%i\n", numBSPShaders);
	for ( i = 0 ; i < numBSPShaders ; i++ ) {
		shaderInfo_t	*se = ShaderInfoForShader(bspShaders[i].shader);

		fprintf( texfile, "\n%i %f %f %f", bspShaders[i].surfaceFlags,
			se->color[0], se->color[1], se->color[2]);
		

		bspShaders[i].surfaceFlags = i;
	}
	fclose(texfile);
}
Esempio n. 3
0
/*
============
EmitShader
============
*/
int	EmitShader( const char *shader ) {
	int				i;
	shaderInfo_t	*si;

	if ( !shader ) {
		shader = "noshader";
	}

	for ( i = 0 ; i < numShaders ; i++ ) {
		if ( !Q_stricmp( shader, dshaders[i].shader ) ) {
			return i;
		}
	}

	if ( i == MAX_MAP_SHADERS ) {
		Error( "MAX_MAP_SHADERS" );
	}
	numShaders++;
	strcpy( dshaders[i].shader, shader );

	si = ShaderInfoForShader( shader );
	dshaders[i].surfaceFlags = si->surfaceFlags;
	dshaders[i].contentFlags = si->contents;

	return i;
}
Esempio n. 4
0
int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags ){
	int i;
	shaderInfo_t    *si;


	/* handle special cases */
	if ( shader == NULL ) {
		shader = "noshader";
	}

	/* try to find an existing shader */
	for ( i = 0; i < numBSPShaders; i++ )
	{
		/* ydnar: handle custom surface/content flags */
		if ( surfaceFlags != NULL && bspShaders[ i ].surfaceFlags != *surfaceFlags ) {
			continue;
		}
		if ( contentFlags != NULL && bspShaders[ i ].contentFlags != *contentFlags ) {
			continue;
		}

		/* compare name */
		if ( !Q_stricmp( shader, bspShaders[ i ].shader ) ) {
			return i;
		}
	}

	// i == numBSPShaders

	/* get shaderinfo */
	si = ShaderInfoForShader( shader );

	/* emit a new shader */
	AUTOEXPAND_BY_REALLOC_BSP( Shaders, 1024 );

	numBSPShaders++;
	strcpy( bspShaders[ i ].shader, shader );
	bspShaders[ i ].surfaceFlags = si->surfaceFlags;
	bspShaders[ i ].contentFlags = si->contentFlags;

	/* handle custom content/surface flags */
	if ( surfaceFlags != NULL ) {
		bspShaders[ i ].surfaceFlags = *surfaceFlags;
	}
	if ( contentFlags != NULL ) {
		bspShaders[ i ].contentFlags = *contentFlags;
	}

	/* recursively emit any damage shaders */
	if ( si->damageShader != NULL && si->damageShader[ 0 ] != '\0' ) {
		Sys_FPrintf( SYS_VRB, "Shader %s has damage shader %s\n", si->shader, si->damageShader );
		EmitShader( si->damageShader, NULL, NULL );
	}

	/* return it */
	return i;
}
Esempio n. 5
0
/*
================
ShaderForLayer
================
*/
shaderInfo_t *ShaderForLayer( int minlayer, int maxlayer, const char *shadername ) {
	char	shader[ MAX_QPATH ];

	if ( minlayer == maxlayer ) {
		sprintf( shader, "textures/%s_%d", shadername, maxlayer );
	} else {
		sprintf( shader, "textures/%s_%dto%d", shadername, minlayer, maxlayer );
	}

	return ShaderInfoForShader( shader );
}
Esempio n. 6
0
static void ConvertShader(FILE * f, dshader_t * shader, int shaderNum)
{
	shaderInfo_t   *si;
	char           *c, filename[1024];


	// get shader
	si = ShaderInfoForShader(shader->shader);
	if(si == NULL)
	{
		Sys_Printf("WARNING: NULL shader in BSP\n");
		return;
	}

	// set bitmap filename
	if(si->shader[0] != '*')
		strcpy(filename, si->shader);
	else
		sprintf(filename, "%s.tga", si->shader);

#if 0
	for(c = filename; *c != '\0'; c++)
		if(*c == '/')
			*c = '\\';
#endif

	// print shader info
	fprintf(f, "\t*MATERIAL\t%d\t{\r\n", shaderNum);
	fprintf(f, "\t\t*MATERIAL_NAME\t\"%s\"\r\n", shader->shader);
	fprintf(f, "\t\t*MATERIAL_CLASS\t\"Standard\"\r\n");
	fprintf(f, "\t\t*MATERIAL_DIFFUSE\t%f\t%f\t%f\r\n", si->color[0], si->color[1], si->color[2]);
	fprintf(f, "\t\t*MATERIAL_SHADING Phong\r\n");

	// print map info
	fprintf(f, "\t\t*MAP_DIFFUSE\t{\r\n");
	fprintf(f, "\t\t\t*MAP_NAME\t\"%s\"\r\n", shader->shader);
	fprintf(f, "\t\t\t*MAP_CLASS\t\"Bitmap\"\r\n");
	fprintf(f, "\t\t\t*MAP_SUBNO\t1\r\n");
	fprintf(f, "\t\t\t*MAP_AMOUNT\t1.0\r\n");
	fprintf(f, "\t\t\t*MAP_TYPE\tScreen\r\n");
	fprintf(f, "\t\t\t*BITMAP\t\"%s\"\r\n", filename);
	fprintf(f, "\t\t\t*BITMAP_FILTER\tPyramidal\r\n");
	fprintf(f, "\t\t}\r\n");

	fprintf(f, "\t}\r\n");
}
Esempio n. 7
0
/*
=====================
InitSurfacesForTesting

Builds structures to speed the ray tracing against surfaces
=====================
*/
void InitSurfacesForTesting( void ) {

	int				i, j;
	dsurface_t		*dsurf;
	surfaceTest_t	*test;
	drawVert_t		*dvert;
	shaderInfo_t	*si;

	for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
		dsurf = &drawSurfaces[ i ];
		if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
			continue;
		}

		// don't make surfaces for transparent objects
		// because we want light to pass through them
		si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
		if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
			continue;
		}

		test = malloc( sizeof( *test ) );
		surfaceTest[i] = test;
		ClearBounds( test->mins, test->maxs );

		dvert = &drawVerts[ dsurf->firstVert ];
		for ( j = 0 ; j < dsurf->numVerts ; j++, dvert++ ) {
			AddPointToBounds( dvert->xyz, test->mins, test->maxs );
		}

		SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );

		if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
			FacetsForTriangleSurface( dsurf, si, test );
		} else if ( dsurf->surfaceType == MST_PATCH ) {
			FacetsForPatch( dsurf, si, test );
		}
	}
}
Esempio n. 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_Printf( "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 );
}
Esempio n. 9
0
/*
=================
ParseRawBrush

parses the sides into buildBrush->sides[], nothing else.
no validation, back plane removal, etc.
=================
*/
static void ParseRawBrush( bool onlyLights )
{
	side_t		*side;
	float		planePoints[3][3];
	int		planenum;
	char 		name[MAX_SHADERPATH];
	char		shader[MAX_SHADERPATH];
	shaderInfo_t	*si;
	token_t		token;
	vects_t		vects;
	int		flags;
	
	buildBrush->numsides = 0;
	buildBrush->detail = false;
	
	if( g_bBrushPrimit == BRUSH_RADIANT )
		Com_CheckToken( mapfile, "{" );
	
	while( 1 )
	{
		if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES|SC_COMMENT_SEMICOLON, &token ))
			break;
		if( !com.stricmp( token.string, "}" )) break;
		if( g_bBrushPrimit == BRUSH_RADIANT )
		{
			while( 1 )
			{
				if( com.strcmp( token.string, "(" ))
					Com_ReadToken( mapfile, 0, &token );
				else break;
				Com_ReadToken( mapfile, SC_ALLOW_NEWLINES, &token );
			}
		}
		Com_SaveToken( mapfile, &token );
		
		if( buildBrush->numsides >= MAX_BUILD_SIDES )
			Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum );
		
		side = &buildBrush->sides[ buildBrush->numsides ];
		Mem_Set( side, 0, sizeof( *side ));
		buildBrush->numsides++;
		
		// read the three point plane definition
		Com_Parse1DMatrix( mapfile, 3, planePoints[0] );
		Com_Parse1DMatrix( mapfile, 3, planePoints[1] );
		Com_Parse1DMatrix( mapfile, 3, planePoints[2] );
		
		// read the texture matrix
		if( g_bBrushPrimit == BRUSH_RADIANT )
			Com_Parse2DMatrix( mapfile, 2, 3, (float *)side->texMat );
		
		// read the texturedef or shadername
		Com_ReadToken( mapfile, SC_ALLOW_PATHNAMES|SC_PARSE_GENERIC, &token );
		com.strncpy( name, token.string, sizeof( name ));
		
		if( g_bBrushPrimit == BRUSH_WORLDCRAFT_22 || g_bBrushPrimit == BRUSH_GEARCRAFT_40 ) // Worldcraft 2.2+
                    {
			// texture U axis
			Com_ReadToken( mapfile, 0, &token );
			if( com.strcmp( token.string, "[" )) Sys_Break( "missing '[' in texturedef (U)\n" );
			Com_ReadFloat( mapfile, false, &vects.hammer.UAxis[0] );
			Com_ReadFloat( mapfile, false, &vects.hammer.UAxis[1] );
			Com_ReadFloat( mapfile, false, &vects.hammer.UAxis[2] );
			Com_ReadFloat( mapfile, false, &vects.hammer.shift[0] );
			Com_ReadToken( mapfile, 0, &token );
			if( com.strcmp( token.string, "]" )) Sys_Break( "missing ']' in texturedef (U)\n" );

			// texture V axis
			Com_ReadToken( mapfile, 0, &token );
			if( com.strcmp( token.string, "[" )) Sys_Break( "missing '[' in texturedef (V)\n" );
			Com_ReadFloat( mapfile, false, &vects.hammer.VAxis[0] );
			Com_ReadFloat( mapfile, false, &vects.hammer.VAxis[1] );
			Com_ReadFloat( mapfile, false, &vects.hammer.VAxis[2] );
			Com_ReadFloat( mapfile, false, &vects.hammer.shift[1] );
			Com_ReadToken( mapfile, 0, &token );
			if( com.strcmp( token.string, "]" )) Sys_Break( "missing ']' in texturedef (V)\n");

			// texture rotation is implicit in U/V axes.
			Com_ReadToken( mapfile, 0, &token );
			vects.hammer.rotate = 0;

			// texure scale
			Com_ReadFloat( mapfile, false, &vects.hammer.scale[0] );
			Com_ReadFloat( mapfile, false, &vects.hammer.scale[1] );

			if( g_bBrushPrimit == BRUSH_GEARCRAFT_40 )
			{
				Com_ReadLong( mapfile, false, &flags );	// read gearcraft flags
				Com_SkipRestOfLine( mapfile );	// gearcraft lightmap scale and rotate

				if( flags & GEARBOX_DETAIL )
					side->compileFlags |= C_DETAIL;

			}
                    }
		else if( g_bBrushPrimit == BRUSH_WORLDCRAFT_21 || g_bBrushPrimit == BRUSH_QUARK )
		{
			// worldcraft 2.1-, old Radiant, QuArK
			Com_ReadFloat( mapfile, false, &vects.hammer.shift[0] );
			Com_ReadFloat( mapfile, false, &vects.hammer.shift[1] );
			Com_ReadFloat( mapfile, false, &vects.hammer.rotate );
			Com_ReadFloat( mapfile, false, &vects.hammer.scale[0] );
			Com_ReadFloat( mapfile, SC_COMMENT_SEMICOLON, &vects.hammer.scale[1] );
                    }

		// set default flags and values
		com.sprintf( shader, "textures/%s", name );
		if( onlyLights ) si = &shaderInfo[0];
		else si = ShaderInfoForShader( shader );

		side->shaderInfo = si;
		side->surfaceFlags = si->surfaceFlags;
		side->contentFlags = si->contentFlags;
		side->compileFlags = si->compileFlags;
		side->value = si->value;
		
		// bias texture shift for non-radiant sides
		if( g_bBrushPrimit != BRUSH_RADIANT && si->globalTexture == false )
		{
			vects.hammer.shift[0] -= (floor( vects.hammer.shift[0] / si->shaderWidth ) * si->shaderWidth);
			vects.hammer.shift[1] -= (floor( vects.hammer.shift[1] / si->shaderHeight ) * si->shaderHeight);
		}
		
		// historically, there are 3 integer values at the end of a brushside line in a .map file.
		// in quake 3, the only thing that mattered was the first of these three values, which
		// was previously the content flags. and only then did a single bit matter, the detail
		// bit. because every game has its own special flags for specifying detail, the
		// traditionally game-specified BASECONT_DETAIL flag was overridden for Q3Map 2.3.0
		// by C_DETAIL, defined in q3map2.h. the value is exactly as it was before, but
		// is stored in compileFlags, as opposed to contentFlags, for multiple-game
		// portability. :sigh:
                    if( g_bBrushPrimit != BRUSH_QUARK && Com_ReadToken( mapfile, SC_COMMENT_SEMICOLON, &token ))
		{
			// overwrite shader values directly from .map file
			Com_SaveToken( mapfile, &token );
			Com_ReadLong( mapfile, false, &flags );
			Com_ReadLong( mapfile, false, NULL );
			Com_ReadLong( mapfile, false, NULL );
			if( flags & C_DETAIL ) side->compileFlags |= C_DETAIL;
		}		

		if( mapfile->TXcommand == '1' || mapfile->TXcommand == '2' )
		{
			// we are QuArK mode and need to translate some numbers to align textures its way
			// from QuArK, the texture vectors are given directly from the three points
			vec3_t          texMat[2];
			float           dot22, dot23, dot33, mdet, aa, bb, dd;
			int             j, k;

			g_bBrushPrimit = BRUSH_QUARK;	// we can detect it only here
			k = mapfile->TXcommand - '0';
			for( j = 0; j < 3; j++ )
				texMat[1][j] = (planePoints[k][j] - planePoints[0][j]) * (0.0078125f);	// QuArK magic value

			k = 3 - k;
			for( j = 0; j < 3; j++ )
				texMat[0][j] = (planePoints[k][j] - planePoints[0][j]) * (0.0078125f);	// QuArK magic value

			dot22 = DotProduct( texMat[0], texMat[0] );
			dot23 = DotProduct( texMat[0], texMat[1] );
			dot33 = DotProduct( texMat[1], texMat[1] );
			mdet = dot22 * dot33 - dot23 * dot23;
			if( mdet < 1E-6 && mdet > -1E-6 )
			{
				aa = bb = dd = 0;
				MsgDev( D_WARN, "Entity %i, Brush %i: degenerate QuArK-style texture: \n", buildBrush->entityNum, buildBrush->brushNum );
			}
			else
			{
				mdet = 1.0 / mdet;
				aa = dot33 * mdet;
				bb = -dot23 * mdet;
				dd = dot22 * mdet;
			}
			for( j = 0; j < 3; j++ )
			{
				vects.quark.vecs[0][j] = aa * texMat[0][j] + bb * texMat[1][j];
				vects.quark.vecs[1][j] = -(bb * texMat[0][j] + dd * texMat[1][j]);
			}
			vects.quark.vecs[0][3] = -DotProduct( vects.quark.vecs[0], planePoints[0] );
			vects.quark.vecs[1][3] = -DotProduct( vects.quark.vecs[1], planePoints[0] );
		}

		// find the plane number
		planenum = MapPlaneFromPoints( planePoints );
		if( planenum == -1 )
		{
			MsgDev( D_ERROR, "Entity %i, Brush %i: plane with no normal\n", buildBrush->entityNum, buildBrush->brushNum );
			continue;
		}
		side->planenum = planenum;

		if( g_bBrushPrimit == BRUSH_QUARK ) 
		{
			// QuArK format completely matched with internal
			// FIXME: don't calculate vecs, use QuArK texMat instead ?
			Mem_Copy( side->vecs, vects.quark.vecs, sizeof( side->vecs ));
		}
		else if( g_bBrushPrimit != BRUSH_RADIANT )
		{
			vec3_t	vecs[2];
			float	ang, sinv, cosv, ns, nt;
			int	i, j, sv, tv;
			
			if( g_bBrushPrimit == BRUSH_WORLDCRAFT_21 )
				TextureAxisFromPlane( &mapplanes[planenum], vecs[0], vecs[1] );
			if( !vects.hammer.scale[0] ) vects.hammer.scale[0] = 1.0f;
			if( !vects.hammer.scale[1] ) vects.hammer.scale[1] = 1.0f;

			if( g_bBrushPrimit == BRUSH_WORLDCRAFT_21 )
			{
				// rotate axis
				if( vects.hammer.rotate == 0 )
				{
					sinv = 0;
					cosv = 1;
				}
				else if( vects.hammer.rotate == 90 )
				{
					sinv = 1;
					cosv = 0;
				}
				else if( vects.hammer.rotate == 180 )
				{
					sinv = 0;
					cosv = -1;
				}
				else if( vects.hammer.rotate == 270 )
				{
					sinv = -1;
					cosv = 0;
				}
				else
				{
					ang = vects.hammer.rotate / 180 * M_PI;
					sinv = sin( ang );
					cosv = cos( ang );
				}
				if( vecs[0][0] ) sv = 0;
				else if( vecs[0][1] ) sv = 1;
				else sv = 2;

				if( vecs[1][0] ) tv = 0;
				else if( vecs[1][1] ) tv = 1;
				else tv = 2;
			
				for( i = 0; i < 2; i++ )
				{
					ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
					nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
					vecs[i][sv] = ns;
					vecs[i][tv] = nt;
				}

				for( i = 0; i < 2; i++ )
					for( j = 0; j < 3; j++ )
						side->vecs[i][j] = vecs[i][j] / vects.hammer.scale[i];
			}
			else if( g_bBrushPrimit == BRUSH_WORLDCRAFT_22 || g_bBrushPrimit == BRUSH_GEARCRAFT_40 )
			{
				float	scale;

				scale = 1.0f / vects.hammer.scale[0];
				VectorScale( vects.hammer.UAxis, scale, side->vecs[0] );
				scale = 1.0f / vects.hammer.scale[1];
				VectorScale( vects.hammer.VAxis, scale, side->vecs[1] );
			}

			// add shifts
			side->vecs[0][3] = vects.hammer.shift[0];
			side->vecs[1][3] = vects.hammer.shift[1];
		}
	}
	
	if( g_bBrushPrimit == BRUSH_RADIANT )
	{
		Com_SaveToken( mapfile, &token );
		Com_CheckToken( mapfile, "}" );
		Com_CheckToken( mapfile, "}" );
	}
}
Esempio n. 10
0
/*
=================
ParseMapEntity

parses a single entity out of a map file
=================
*/
static bool ParseMapEntity( bool onlyLights )
{
	epair_t		*ep;
	token_t		token;
	const char	*classname, *value;
	float		lightmapScale;
	char		shader[ MAX_SHADERPATH ];
	shaderInfo_t	*celShader = NULL;
	brush_t		*brush;
	parseMesh_t	*patch;
	bool		funcGroup;
	int		castShadows, recvShadows;
	static bool	map_type = false;

	if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES|SC_COMMENT_SEMICOLON, &token ))
		return false; // end of .map file
	if( com.stricmp( token.string, "{" ))  Sys_Break( "ParseEntity: found %s instead {\n", token.string );
	if( numEntities >= MAX_MAP_ENTITIES ) Sys_Break( "MAX_MAP_ENTITIES limit exceeded\n" );	

	entitySourceBrushes = 0;
	mapEnt = &entities[numEntities];
	numEntities++;
	memset( mapEnt, 0, sizeof( *mapEnt ));
	
	mapEnt->mapEntityNum = numMapEntities;
	numMapEntities++;
	
	while( 1 )
	{
		if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES|SC_COMMENT_SEMICOLON, &token ))
			Sys_Break( "ParseEntity: EOF without closing brace\n" );

		if( !com.stricmp( token.string, "}" )) break;
		if( !com.stricmp( token.string, "{" ))
		{
			// parse a brush or patch
			if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES, &token )) break;
			
			if( !com.stricmp( token.string, "patchDef2" ))
			{
				numMapPatches++;
				ParsePatch( onlyLights );
				g_bBrushPrimit = BRUSH_RADIANT;
			}
			else if( !com.stricmp( token.string, "terrainDef" ))
			{
				MsgDev( D_WARN, "Terrain entity parsing not supported in this build.\n" );
				Com_SkipBracedSection( mapfile, 0 );
				g_bBrushPrimit = BRUSH_RADIANT;
			}
			else if( !com.stricmp( token.string, "brushDef" ))
			{
				// parse brush primitive
				g_bBrushPrimit = BRUSH_RADIANT;
				ParseBrush( onlyLights );
			}
			else
			{
				if( g_bBrushPrimit == BRUSH_RADIANT )
					Sys_Break( "mixed brush primitive with another format\n" );
				if( g_bBrushPrimit == BRUSH_UNKNOWN ) g_bBrushPrimit = BRUSH_WORLDCRAFT_21;
				
				// QuArK or WorldCraft map (unknown at this point)
				Com_SaveToken( mapfile, &token );
				ParseBrush( onlyLights );
			}
			entitySourceBrushes++;
		}
		else
		{
			// parse a key / value pair
			ep = ParseEpair( mapfile, &token );

			if( !com.strcmp( ep->key, "mapversion" ))
			{
				if( com.atoi( ep->value ) == VALVE_FORMAT )
				{
					Msg( "Valve Format Map detected\n" );
					g_bBrushPrimit = BRUSH_WORLDCRAFT_22;
				}
				else if( com.atoi( ep->value ) == GEARBOX_FORMAT )
				{
					Msg( "Gearcraft Format Map detected\n" );
					g_bBrushPrimit = BRUSH_GEARCRAFT_40;
				}
				else g_bBrushPrimit = BRUSH_WORLDCRAFT_21;
			}
			if( ep->key[0] != '\0' && ep->value[0] != '\0' )
			{
				ep->next = mapEnt->epairs;
				mapEnt->epairs = ep;
			}
		}
	}

	if( !map_type && g_bBrushPrimit != BRUSH_UNKNOWN )
	{
		MAPTYPE();
		map_type = true;
	}
	
	classname = ValueForKey( mapEnt, "classname" );
	
	if( onlyLights && com.strnicmp( classname, "light", 5 ))
	{
		numEntities--;
		return true;
	}
	
	if( !com.stricmp( "func_group", classname ))
		funcGroup = true;
	else funcGroup = false;
	
	// worldspawn (and func_groups) default to cast/recv shadows in worldspawn group
	if( funcGroup || mapEnt->mapEntityNum == 0 )
	{
		castShadows = WORLDSPAWN_CAST_SHADOWS;
		recvShadows = WORLDSPAWN_RECV_SHADOWS;
	}
	else // other entities don't cast any shadows, but recv worldspawn shadows
	{
		castShadows = ENTITY_CAST_SHADOWS;
		recvShadows = ENTITY_RECV_SHADOWS;
	}
	
	// get explicit shadow flags
	GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows );
	
	// get lightmap scaling value for this entity
	if( com.strcmp( "", ValueForKey( mapEnt, "lightmapscale" )) || com.strcmp( "", ValueForKey( mapEnt, "_lightmapscale" )))
	{
		// get lightmap scale from entity
		lightmapScale = FloatForKey( mapEnt, "lightmapscale" );
		if( lightmapScale <= 0.0f ) lightmapScale = FloatForKey( mapEnt, "_lightmapscale" );
		if( lightmapScale > 0.0f ) Msg( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale );
	}
	else lightmapScale = 0.0f;
	
	// get cel shader :) for this entity
	value = ValueForKey( mapEnt, "_celshader" );
	if( value[0] == '\0' ) value = ValueForKey( &entities[0], "_celshader" );
	if( value[0] != '\0' )
	{
		com.snprintf( shader, sizeof( shader ), "textures/%s", value );
		celShader = ShaderInfoForShader( shader );
		Msg( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader );
	}
	else celShader = NULL;
	
	// attach stuff to everything in the entity
	for( brush = mapEnt->brushes; brush != NULL; brush = brush->next )
	{
		brush->entityNum = mapEnt->mapEntityNum;
		brush->castShadows = castShadows;
		brush->recvShadows = recvShadows;
		brush->lightmapScale = lightmapScale;
		brush->celShader = celShader;
	}
	
	for( patch = mapEnt->patches; patch != NULL; patch = patch->next )
	{
		patch->entityNum = mapEnt->mapEntityNum;
		patch->castShadows = castShadows;
		patch->recvShadows = recvShadows;
		patch->lightmapScale = lightmapScale;
		patch->celShader = celShader;
	}
	
	SetEntityBounds( mapEnt );
	
	// load shader index map (equivalent to old terrain alphamap)
	LoadEntityIndexMap( mapEnt );
	
	// get entity origin and adjust brushes
	GetVectorForKey( mapEnt, "origin", mapEnt->origin );
	if( mapEnt->origin[0] || mapEnt->origin[1] || mapEnt->origin[2] )
		AdjustBrushesForOrigin( mapEnt );

	// group_info entities are just for editor grouping
	if( !com.stricmp( "group_info", classname ))
	{
		numEntities--;
		return true;
	}
	
	// group entities are just for editor convenience, toss all brushes into worldspawn
	if( funcGroup )
	{
		MoveBrushesToWorld( mapEnt );
		numEntities--;
		return true;
	}
	return true;
}
Esempio n. 11
0
static void PopulateWithPicoModel(int castShadows, picoModel_t * model, matrix_t transform)
{
	int             i, j, k, numSurfaces, numIndexes;
	picoSurface_t  *surface;
	picoShader_t   *shader;
	picoVec_t      *xyz, *st;
	picoIndex_t    *indexes;
	traceInfo_t     ti;
	traceWinding_t  tw;


	/* dummy check */
	if(model == NULL || transform == NULL)
		return;

	/* get info */
	numSurfaces = PicoGetModelNumSurfaces(model);

	/* walk the list of surfaces in this model and fill out the info structs */
	for(i = 0; i < numSurfaces; i++)
	{
		/* get surface */
		surface = PicoGetModelSurface(model, i);
		if(surface == NULL)
			continue;

		/* only handle triangle surfaces initially (fixme: support patches) */
		if(PicoGetSurfaceType(surface) != PICO_TRIANGLES)
			continue;

		/* get shader (fixme: support shader remapping) */
		shader = PicoGetSurfaceShader(surface);
		if(shader == NULL)
			continue;
		ti.si = ShaderInfoForShader(PicoGetShaderName(shader));
		if(ti.si == NULL)
			continue;

		/* translucent surfaces that are neither alphashadow or lightfilter don't cast shadows */
		if((ti.si->compileFlags & C_NODRAW))
			continue;
		if((ti.si->compileFlags & C_TRANSLUCENT) &&
		   !(ti.si->compileFlags & C_ALPHASHADOW) && !(ti.si->compileFlags & C_LIGHTFILTER))
			continue;

		/* setup trace info */
		ti.castShadows = castShadows;
		ti.surfaceNum = -1;
		ti.skipGrid = qtrue;	// also ignore picomodels when skipping patches

		/* setup trace winding */
		memset(&tw, 0, sizeof(tw));
		tw.infoNum = AddTraceInfo(&ti);
		tw.numVerts = 3;

		/* get info */
		numIndexes = PicoGetSurfaceNumIndexes(surface);
		indexes = PicoGetSurfaceIndexes(surface, 0);

		/* walk the triangle list */
		for(j = 0; j < numIndexes; j += 3, indexes += 3)
		{
			for(k = 0; k < 3; k++)
			{
				xyz = PicoGetSurfaceXYZ(surface, indexes[k]);
				st = PicoGetSurfaceST(surface, 0, indexes[k]);
				VectorCopy(xyz, tw.v[k].xyz);
				Vector2Copy(st, tw.v[k].st);
				MatrixTransformPoint2(transform, tw.v[k].xyz);
			}
			FilterTraceWindingIntoNodes_r(&tw, headNodeNum);
		}
	}
}
Esempio n. 12
0
/*
=================
LoadSurfaceExtraFile

reads a surface info file (<map>.srf)
=================
*/
void LoadSurfaceExtraFile( const char *path )
{
	char		srfPath[MAX_SYSPATH];
	surfaceExtra_t	*se;
	int		surfaceNum;
	script_t		*script;
	token_t		token;
	
	if( path == NULL || path[0] == '\0' )
		return;
	
	com.strcpy( srfPath, path );
	FS_StripExtension( srfPath );
	FS_DefaultExtension( srfPath, ".srf" );
	Msg( "Loading %s\n", srfPath );

	script = (void *)Com_OpenScript( srfPath, NULL, 0 );
	if( !script ) Sys_Break( "unable to load %s\n", srfPath ); // q3map is always crashed if this missed
	
	while( 1 )
	{
		if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token ))
			break;
		
		if( !com.stricmp( token.string, "default" )) se = &seDefault;
		else
		{
			surfaceNum = com.atoi( token.string );
			if( surfaceNum < 0 || surfaceNum > MAX_MAP_DRAW_SURFS )
				Sys_Error( "ReadSurfaceExtraFile(): %s, line %d: bogus surface num %d", srfPath, token.line, surfaceNum );
			while( surfaceNum >= numSurfaceExtras )
				se = AllocSurfaceExtra();
			se = &surfaceExtras[surfaceNum];
		}
		
		// handle { } section
		if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token ) || com.strcmp( token.string, "{" ))
			Sys_Error( "ReadSurfaceExtraFile(): %s, line %d: { not found\n", srfPath, token.line );
		while( 1 )
		{
			if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token ))
				break;
			if( !com.strcmp( token.string, "}" ))
				break;
			
			if( !com.stricmp( token.string, "shader" ))
			{
				Com_ReadToken( script, SC_ALLOW_PATHNAMES|SC_PARSE_GENERIC, &token );
				se->si = ShaderInfoForShader( token.string );
			}
			else if( !com.stricmp( token.string, "parent" ))
			{
				Com_ReadLong( script, false, &se->parentSurfaceNum );
			}
			else if( !com.stricmp( token.string, "entity" ))
			{
				Com_ReadLong( script, false, &se->entityNum );
			}
			else if( !com.stricmp( token.string, "castShadows" ))
			{
				Com_ReadLong( script, false, &se->castShadows );
			}
			else if( !com.stricmp( token.string, "receiveShadows" ))
			{
				Com_ReadLong( script, false, &se->recvShadows );
			}
			else if( !com.stricmp( token.string, "sampleSize" ))
			{
				Com_ReadLong( script, false, &se->sampleSize );
			}
			else if( !com.stricmp( token.string, "longestCurve" ))
			{
				Com_ReadFloat( script, false, &se->longestCurve );
			}
			else if( !com.stricmp( token.string, "lightmapAxis" ))
				Com_Parse1DMatrix( script, 3, se->lightmapAxis );
			
			// ignore all other tokens on the line
			Com_SkipRestOfLine( script );
		}
	}
	Com_CloseScript( script );
}
Esempio n. 13
0
static void ConvertBrush(FILE * f, int num, bspBrush_t * brush, vec3_t origin)
{
	int             i, j;
	bspBrushSide_t *side;
	side_t         *buildSide;
	bspShader_t    *shader;
	char           *texture;
	bspPlane_t     *plane;
	plane_t        *buildPlane;
	vec3_t          pts[3];
	bspDrawVert_t  *vert[3];
	int             valid;


	/* start brush */
	fprintf(f, "\t// brush %d\n", num);
	fprintf(f, "\t{\n");
	fprintf(f, "\tbrushDef\n");
	fprintf(f, "\t{\n");

	/* clear out build brush */
	for(i = 0; i < buildBrush->numsides; i++)
	{
		buildSide = &buildBrush->sides[i];
		if(buildSide->winding != NULL)
		{
			FreeWinding(buildSide->winding);
			buildSide->winding = NULL;
		}
	}
	buildBrush->numsides = 0;

	/* iterate through bsp brush sides */
	for(i = 0; i < brush->numSides; i++)
	{
		/* get side */
		side = &bspBrushSides[brush->firstSide + i];

		/* get shader */
		if(side->shaderNum < 0 || side->shaderNum >= numBSPShaders)
			continue;
		shader = &bspShaders[side->shaderNum];
		if(!Q_stricmp(shader->shader, "default") || !Q_stricmp(shader->shader, "noshader"))
			continue;

		/* get plane */
		plane = &bspPlanes[side->planeNum];

		/* add build side */
		buildSide = &buildBrush->sides[buildBrush->numsides];
		buildBrush->numsides++;

		/* tag it */
		buildSide->shaderInfo = ShaderInfoForShader(shader->shader);
		buildSide->planenum = side->planeNum;
		buildSide->winding = NULL;
	}

	/* make brush windings */
	if(!CreateBrushWindings(buildBrush))
		return;

	/* iterate through build brush sides */
	for(i = 0; i < buildBrush->numsides; i++)
	{
		/* get build side */
		buildSide = &buildBrush->sides[i];

		/* get plane */
		buildPlane = &mapplanes[buildSide->planenum];

		/* dummy check */
		if(buildSide->shaderInfo == NULL || buildSide->winding == NULL)
			continue;

		// st-texcoords -> texMat block
		// start out with dummy
		VectorSet(buildSide->texMat[0], 1 / 32.0, 0, 0);
		VectorSet(buildSide->texMat[1], 0, 1 / 32.0, 0);

		// find surface for this side (by brute force)
		// surface format:
		//   - meshverts point in pairs of three into verts
		//   - (triangles)
		//   - find the triangle that has most in common with our side
		GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
		valid = 0;

		if(vert[0] && vert[1] && vert[2])
		{
			int             i;
			vec3_t          texX, texY;
			vec3_t          xy1I, xy1J, xy1K;
			vec2_t          stI, stJ, stK;
			vec_t           D, D0, D1, D2;

			ComputeAxisBase(buildPlane->normal, texX, texY);

			VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
			VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
			VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
			stI[0] = vert[0]->st[0];
			stI[1] = vert[0]->st[1];
			stJ[0] = vert[1]->st[0];
			stJ[1] = vert[1]->st[1];
			stK[0] = vert[2]->st[0];
			stK[1] = vert[2]->st[1];

			//   - solve linear equations:
			//     - (x, y) := xyz . (texX, texY)
			//     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
			//       (for three vertices)
			D = Det3x3(xy1I[0], xy1I[1], 1, xy1J[0], xy1J[1], 1, xy1K[0], xy1K[1], 1);
			if(D != 0)
			{
				for(i = 0; i < 2; ++i)
				{
					D0 = Det3x3(stI[i], xy1I[1], 1, stJ[i], xy1J[1], 1, stK[i], xy1K[1], 1);
					D1 = Det3x3(xy1I[0], stI[i], 1, xy1J[0], stJ[i], 1, xy1K[0], stK[i], 1);
					D2 = Det3x3(xy1I[0], xy1I[1], stI[i], xy1J[0], xy1J[1], stJ[i], xy1K[0], xy1K[1], stK[i]);
					VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
					valid = 1;
				}
			}
			else
				fprintf(stderr,
						"degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
						buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2], vert[0]->normal[0],
						vert[0]->normal[1], vert[0]->normal[2], texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
						vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1], vert[1]->xyz[0], vert[1]->xyz[1],
						vert[1]->xyz[2], xy1J[0], xy1J[1], vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]);
		}
		else if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
			fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n",
					buildSide->shaderInfo->shader);

		/* get texture name */
		if(!Q_strncasecmp(buildSide->shaderInfo->shader, "textures/", 9))
			texture = buildSide->shaderInfo->shader + 9;
		else
			texture = buildSide->shaderInfo->shader;

		/* get plane points and offset by origin */
		for(j = 0; j < 3; j++)
		{
			VectorAdd(buildSide->winding->p[j], origin, pts[j]);
			//% pts[ j ][ 0 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 0 ] * SNAP_FLOAT_TO_INT + 0.5f );
			//% pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f );
			//% pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f );
		}

		/* print brush side */
		/* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
		fprintf(f,
				"\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
				pts[0][0], pts[0][1], pts[0][2], pts[1][0], pts[1][1], pts[1][2], pts[2][0], pts[2][1], pts[2][2],
				buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2], buildSide->texMat[1][0],
				buildSide->texMat[1][1], buildSide->texMat[1][2], texture,
				// DEBUG: valid ? 0 : C_DETAIL
				0);
		// TODO write brush primitives format here
	}

	/* end brush */
	fprintf(f, "\t}\n");
	fprintf(f, "\t}\n\n");
}
Esempio n. 14
0
/*
=================
ParsePatch

Creates a mapDrawSurface_t from the patch text
=================
*/
void ParsePatch( void ) {
	vec_t		info[5];
	int			i, j;
	parseMesh_t	*pm;
	char		texture[MAX_QPATH];
	char		shader[MAX_QPATH];
	mesh_t		m;
	drawVert_t	*verts;
  epair_t *ep;

	MatchToken( "{" );

	// get texture
	GetToken (qtrue);
	strcpy( texture, token );

	// save the shader name for retexturing
	if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
		Error( "MAX_MAP_BRUSHSIDES" );
	}
	strcpy( mapIndexedShaders[numMapIndexedShaders], texture );
	numMapIndexedShaders++;


	Parse1DMatrix( 5, info );
	m.width = info[0];
	m.height = info[1];
	m.verts = verts = 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 );
		}
		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( "}" );

	if ( noCurveBrushes ) {
		return;
	}

	// find default flags and values
	pm = malloc( sizeof( *pm ) );
	memset( pm, 0, sizeof( *pm ) );

	sprintf( shader, "textures/%s", texture );
	pm->shaderInfo = ShaderInfoForShader( shader ); 
	pm->mesh = m;

	// link to the entity
	pm->next = mapent->patches;
	mapent->patches = pm;
}
Esempio n. 15
0
void InsertModel(char *name, int frame, matrix_t transform, matrix_t nTransform, remap_t * remap, shaderInfo_t * celShader, int eNum, int castShadows,
				 int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle)
{
	int             i, j, k, s, numSurfaces;
	matrix_t        identity;
	picoModel_t    *model;
	picoShader_t   *shader;
	picoSurface_t  *surface;
	shaderInfo_t   *si;
	mapDrawSurface_t *ds;
	bspDrawVert_t  *dv;
	char           *picoShaderName;
	char            shaderName[MAX_QPATH];
	picoVec_t      *xyz, *normal, *st;
	byte           *color;
	picoIndex_t    *indexes;
	remap_t        *rm, *glob;
	double          normalEpsilon_save;
	double          distanceEpsilon_save;


	/* get model */
	model = LoadModel(name, frame);
	if(model == NULL)
		return;

	/* handle null matrix */
	if(transform == NULL)
	{
		MatrixIdentity(identity);
		transform = identity;
	}

	/* create transform matrix for normals */
#if 0
	MatrixCopy(transform, nTransform);
	if(MatrixInverse(nTransform))
	{
		Sys_FPrintf(SYS_VRB, "WARNING: Can't invert model transform matrix, using transpose instead\n");
		MatrixTranspose(transform, nTransform);
	}
#endif

	/* fix bogus lightmap scale */
	if(lightmapScale <= 0.0f)
		lightmapScale = 1.0f;

	/* fix bogus shade angle */
	if(shadeAngle <= 0.0f)
		shadeAngle = 0.0f;

	/* each surface on the model will become a new map drawsurface */
	numSurfaces = PicoGetModelNumSurfaces(model);
	//% Sys_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces );
	for(s = 0; s < numSurfaces; s++)
	{
		/* get surface */
		surface = PicoGetModelSurface(model, s);
		if(surface == NULL)
			continue;

		/* only handle triangle surfaces initially (fixme: support patches) */
		if(PicoGetSurfaceType(surface) != PICO_TRIANGLES)
			continue;

		/* fix the surface's normals */
		PicoFixSurfaceNormals(surface);

		/* allocate a surface (ydnar: gs mods) */
		ds = AllocDrawSurface(SURFACE_TRIANGLES);
		ds->entityNum = eNum;
		ds->castShadows = castShadows;
		ds->recvShadows = recvShadows;

		/* get shader name */
		shader = PicoGetSurfaceShader(surface);
		if(shader == NULL)
			picoShaderName = "";
		else
			picoShaderName = PicoGetShaderName(shader);

		/* handle shader remapping */
		glob = NULL;
		for(rm = remap; rm != NULL; rm = rm->next)
		{
			if(rm->from[0] == '*' && rm->from[1] == '\0')
				glob = rm;
			else if(!Q_stricmp(picoShaderName, rm->from))
			{
				Sys_FPrintf(SYS_VRB, "Remapping %s to %s\n", picoShaderName, rm->to);
				picoShaderName = rm->to;
				glob = NULL;
				break;
			}
		}

		if(glob != NULL)
		{
			Sys_FPrintf(SYS_VRB, "Globbing %s to %s\n", picoShaderName, glob->to);
			picoShaderName = glob->to;
		}

		/* shader renaming for sof2 */
		if(renameModelShaders)
		{
			strcpy(shaderName, picoShaderName);
			StripExtension(shaderName);
			if(spawnFlags & 1)
				strcat(shaderName, "_RMG_BSP");
			else
				strcat(shaderName, "_BSP");
			si = ShaderInfoForShader(shaderName);
		}
		else
		{
			si = ShaderInfoForShader(picoShaderName);

			// Tr3B: HACK to support the messy Doom 3 materials provided by .ASE files
			if(!si->explicitDef)
			{
				picoShaderName = PicoGetShaderMapName(shader);

				Q_strncpyz(shaderName, picoShaderName, sizeof(shaderName));
				StripExtension(shaderName);

				i = 0;
				while(shaderName[i])
				{
					if(shaderName[i] == '\\')
						shaderName[i] = '/';
					i++;
				}

				if(strstr(shaderName, "base/"))
				{
					si = ShaderInfoForShader(strstr(shaderName, "base/") + strlen("base/"));
					Sys_FPrintf(SYS_WRN, "WARNING: Applied .ASE material loader HACK to '%s' -> '%s'\n", picoShaderName, si->shader);
				}

			}
		}

		/* set shader */
		ds->shaderInfo = si;

		/* force to meta? */
		if((si != NULL && si->forceMeta) || (spawnFlags & 4))	/* 3rd bit */
			ds->type = SURFACE_FORCED_META;

		/* fix the surface's normals (jal: conditioned by shader info) */
		//if(!(spawnFlags & 64) && (shadeAngle == 0.0f || ds->type != SURFACE_FORCED_META))
		//	PicoFixSurfaceNormals(surface);

		/* set sample size */
		if(lightmapSampleSize > 0.0f)
			ds->sampleSize = lightmapSampleSize;

		/* set lightmap scale */
		if(lightmapScale > 0.0f)
			ds->lightmapScale = lightmapScale;

		/* set shading angle */
		if(shadeAngle > 0.0f)
			ds->shadeAngleDegrees = shadeAngle;

		/* set particulars */
		ds->numVerts = PicoGetSurfaceNumVertexes(surface);
		ds->verts = safe_malloc(ds->numVerts * sizeof(ds->verts[0]));
		memset(ds->verts, 0, ds->numVerts * sizeof(ds->verts[0]));

		ds->numIndexes = PicoGetSurfaceNumIndexes(surface);
		ds->indexes = safe_malloc(ds->numIndexes * sizeof(ds->indexes[0]));
		memset(ds->indexes, 0, ds->numIndexes * sizeof(ds->indexes[0]));

		/* copy vertexes */
		for(i = 0; i < ds->numVerts; i++)
		{
			/* get vertex */
			dv = &ds->verts[i];

			/* xyz and normal */
			xyz = PicoGetSurfaceXYZ(surface, i);
			VectorCopy(xyz, dv->xyz);
			MatrixTransformPoint2(transform, dv->xyz);

			normal = PicoGetSurfaceNormal(surface, i);
			VectorCopy(normal, dv->normal);
			MatrixTransformNormal2(nTransform, dv->normal);
			VectorNormalize2(dv->normal, dv->normal);

			/* ydnar: tek-fu celshading support for flat shaded shit */
			if(flat)
			{
				dv->st[0] = si->stFlat[0];
				dv->st[1] = si->stFlat[1];
			}

			/* ydnar: gs mods: added support for explicit shader texcoord generation */
			else if(si->tcGen)
			{
				/* project the texture */
				dv->st[0] = DotProduct(si->vecs[0], dv->xyz);
				dv->st[1] = DotProduct(si->vecs[1], dv->xyz);
			}

			/* normal texture coordinates */
			else
			{
				st = PicoGetSurfaceST(surface, 0, i);
				dv->st[0] = st[0];
				dv->st[1] = st[1];
			}

			/* set lightmap/color bits */
			color = PicoGetSurfaceColor(surface, 0, i);

			dv->paintColor[0] = color[0] / 255.0f;
			dv->paintColor[1] = color[1] / 255.0f;
			dv->paintColor[2] = color[2] / 255.0f;
			dv->paintColor[3] = color[3] / 255.0f;

			for(j = 0; j < MAX_LIGHTMAPS; j++)
			{
				dv->lightmap[j][0] = 0.0f;
				dv->lightmap[j][1] = 0.0f;

				dv->lightColor[j][0] = 255;
				dv->lightColor[j][1] = 255;
				dv->lightColor[j][2] = 255;
				dv->lightColor[j][3] = 255;
			}
		}

		/* copy indexes */
		indexes = PicoGetSurfaceIndexes(surface, 0);
		for(i = 0; i < ds->numIndexes; i++)
			ds->indexes[i] = indexes[i];

		/* set cel shader */
		ds->celShader = celShader;

		/* ydnar: giant hack land: generate clipping brushes for model triangles */
		if(si->clipModel || (spawnFlags & 2))	/* 2nd bit */
		{
			vec3_t          points[4], backs[3];
			vec4_t          plane, reverse, pa, pb, pc;


			/* temp hack */
			if(!si->clipModel &&
			   (((si->compileFlags & C_TRANSLUCENT) && !(si->compileFlags & C_COLLISION)) || !(si->compileFlags & C_SOLID)))
				continue;

			/* walk triangle list */
			for(i = 0; i < ds->numIndexes; i += 3)
			{
				/* overflow hack */
				AUTOEXPAND_BY_REALLOC(mapplanes, (nummapplanes + 64) << 1, allocatedmapplanes, 1024);

				/* make points and back points */
				for(j = 0; j < 3; j++)
				{
					/* get vertex */
					dv = &ds->verts[ds->indexes[i + j]];

					/* copy xyz */
					VectorCopy(dv->xyz, points[j]);
					VectorCopy(dv->xyz, backs[j]);

					/* find nearest axial to normal and push back points opposite */
					/* note: this doesn't work as well as simply using the plane of the triangle, below */
					for(k = 0; k < 3; k++)
					{
						if(fabs(dv->normal[k]) >= fabs(dv->normal[(k + 1) % 3]) &&
						   fabs(dv->normal[k]) >= fabs(dv->normal[(k + 2) % 3]))
						{
							backs[j][k] += dv->normal[k] < 0.0f ? 64.0f : -64.0f;
							break;
						}
					}
				}

				VectorCopy(points[0], points[3]);	// for cyclic usage

				/* make plane for triangle */
				// div0: add some extra spawnflags:
				//   0: snap normals to axial planes for extrusion
				//   8: extrude with the original normals
				//  16: extrude only with up/down normals (ideal for terrain)
				//  24: extrude by distance zero (may need engine changes)
				if(PlaneFromPoints(plane, points[0], points[1], points[2], qtrue))
				{
					vec3_t          bestNormal;
					float           backPlaneDistance = 2;

					if(spawnFlags & 8)	// use a DOWN normal
					{
						if(spawnFlags & 16)
						{
							// 24: normal as is, and zero width (broken)
							VectorCopy(plane, bestNormal);
						}
						else
						{
							// 8: normal as is
							VectorCopy(plane, bestNormal);
						}
					}
					else
					{
						if(spawnFlags & 16)
						{
							// 16: UP/DOWN normal
							VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
						}
						else
						{
							// 0: axial normal
							if(fabs(plane[0]) > fabs(plane[1]))	// x>y
								if(fabs(plane[1]) > fabs(plane[2]))	// x>y, y>z
									VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
								else	// x>y, z>=y
								if(fabs(plane[0]) > fabs(plane[2]))	// x>z, z>=y
									VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
								else	// z>=x, x>y
									VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
							else	// y>=x
							if(fabs(plane[1]) > fabs(plane[2]))	// y>z, y>=x
								VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
							else	// z>=y, y>=x
								VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
						}
					}

					/* build a brush */
					buildBrush = AllocBrush(48);
					buildBrush->entityNum = mapEntityNum;
					buildBrush->original = buildBrush;
					buildBrush->contentShader = si;
					buildBrush->compileFlags = si->compileFlags;
					buildBrush->contentFlags = si->contentFlags;

					buildBrush->generatedClipBrush = qtrue;

					normalEpsilon_save = normalEpsilon;
					distanceEpsilon_save = distanceEpsilon;

					if(si->compileFlags & C_STRUCTURAL)	// allow forced structural brushes here
					{
						buildBrush->detail = qfalse;

						// only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
						if(normalEpsilon > 0)
							normalEpsilon = 0;
						if(distanceEpsilon > 0)
							distanceEpsilon = 0;
					}
					else
						buildBrush->detail = qtrue;

					/* regenerate back points */
					for(j = 0; j < 3; j++)
					{
						/* get vertex */
						dv = &ds->verts[ds->indexes[i + j]];

						// shift by some units
						VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]);	// 64 prevents roundoff errors a bit
					}

					/* make back plane */
					VectorScale(plane, -1.0f, reverse);
					reverse[3] = -plane[3];
					if((spawnFlags & 24) != 24)
						reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
					// that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)

					if(PlaneFromPoints(pa, points[2], points[1], backs[1], qtrue) &&
					   PlaneFromPoints(pb, points[1], points[0], backs[0], qtrue) && PlaneFromPoints(pc, points[0], points[2], backs[2], qtrue))
					{
						/* set up brush sides */
						buildBrush->numsides = 5;
						buildBrush->sides[0].shaderInfo = si;
						for(j = 1; j < buildBrush->numsides; j++)
							buildBrush->sides[j].shaderInfo = NULL;	// don't emit these faces as draw surfaces, should make smaller BSPs; hope this works

						buildBrush->sides[0].planenum = FindFloatPlane(plane, plane[3], 3, points);
						buildBrush->sides[1].planenum = FindFloatPlane(pa, pa[3], 2, &points[1]);	// pa contains points[1] and points[2]
						buildBrush->sides[2].planenum = FindFloatPlane(pb, pb[3], 2, &points[0]);	// pb contains points[0] and points[1]
						buildBrush->sides[3].planenum = FindFloatPlane(pc, pc[3], 2, &points[2]);	// pc contains points[2] and points[0] (copied to points[3]
						buildBrush->sides[4].planenum = FindFloatPlane(reverse, reverse[3], 3, backs);
					}
					else
					{
						free(buildBrush);
						continue;
					}

					normalEpsilon = normalEpsilon_save;
					distanceEpsilon = distanceEpsilon_save;

					/* add to entity */
					if(CreateBrushWindings(buildBrush))
					{
						AddBrushBevels();
						//% EmitBrushes( buildBrush, NULL, NULL );
						buildBrush->next = entities[mapEntityNum].brushes;
						entities[mapEntityNum].brushes = buildBrush;
						entities[mapEntityNum].numBrushes++;
					}
					else
						free(buildBrush);
				}
			}
		}
	}
}
Esempio n. 16
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;
}
Esempio n. 17
0
void CreateMapFogs(void)
{
	int             i;
	entity_t       *entity;
	brush_t        *brush;
	fog_t          *fog;
	vec3_t          invFogDir;
	const char     *globalFog;


	/* skip? */
	if(nofog)
		return;

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

	/* walk entities */
	for(i = 0; i < numEntities; i++)
	{
		/* get entity */
		entity = &entities[i];

		/* walk entity brushes */
		for(brush = entity->brushes; brush != NULL; brush = brush->next)
		{
			/* ignore non-fog brushes */
			if(brush->contentShader->fogParms == qfalse)
				continue;

			/* test limit */
			if(numMapFogs >= MAX_MAP_FOGS)
				Error("Exceeded MAX_MAP_FOGS (%d)", MAX_MAP_FOGS);

			/* set up fog */
			fog = &mapFogs[numMapFogs++];
			fog->si = brush->contentShader;
			fog->brush = brush;
			fog->visibleSide = -1;

			/* if shader specifies an explicit direction, then find a matching brush side with an opposed normal */
			if(VectorLength(fog->si->fogDir))
			{
				/* flip it */
				VectorScale(fog->si->fogDir, -1.0f, invFogDir);

				/* find the brush side */
				for(i = 0; i < brush->numsides; i++)
				{
					if(VectorCompare(invFogDir, mapplanes[brush->sides[i].planenum].normal))
					{
						fog->visibleSide = i;
						//% Sys_Printf( "Brush num: %d Side num: %d\n", fog->brushNum, fog->visibleSide );
						break;
					}
				}
			}
		}
	}

	/* ydnar: global fog */
	globalFog = ValueForKey(&entities[0], "_fog");
	if(globalFog[0] == '\0')
		globalFog = ValueForKey(&entities[0], "fog");
	if(globalFog[0] != '\0')
	{
		/* test limit */
		if(numMapFogs >= MAX_MAP_FOGS)
			Error("Exceeded MAX_MAP_FOGS (%d) trying to add global fog", MAX_MAP_FOGS);

		/* note it */
		Sys_FPrintf(SYS_VRB, "Map has global fog shader %s\n", globalFog);

		/* set up fog */
		fog = &mapFogs[numMapFogs++];
		fog->si = ShaderInfoForShader(globalFog);
		if(fog->si == NULL)
			Error("Invalid shader \"%s\" referenced trying to add global fog", globalFog);
		fog->brush = NULL;
		fog->visibleSide = -1;

		/* set as default fog */
		defaultFogNum = numMapFogs - 1;

		/* mark all worldspawn brushes as fogged */
		for(brush = entities[0].brushes; brush != NULL; brush = brush->next)
			ApplySurfaceParm("fog", &brush->contentFlags, NULL, &brush->compileFlags);
	}

	/* emit some stats */
	Sys_FPrintf(SYS_VRB, "%9d fogs\n", numMapFogs);
}
Esempio n. 18
0
void AddTriangleModels(entity_t * e)
{
	int             num, frame, castShadows, recvShadows, spawnFlags;
	entity_t       *e2;
	const char     *targetName;
	const char     *target, *model, *value;
	char            shader[MAX_QPATH];
	shaderInfo_t   *celShader;
	float           temp, baseLightmapScale, lightmapScale;
	float           shadeAngle;
	int             lightmapSampleSize;
	vec3_t          origin, scale, angles;
	matrix_t        rotation, rotationScaled, transform;
	epair_t        *ep;
	remap_t        *remap, *remap2;
	char           *split;


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

	/* get current brush entity targetname */
	if(e == entities)
		targetName = "";
	else
	{
		targetName = ValueForKey(e, "name");

		/* misc_model entities target non-worldspawn brush model entities */
		if(targetName[0] == '\0')
			return;
	}

	/* get lightmap scale */
	/* vortex: added _ls key (short name of lightmapscale) */
	baseLightmapScale = 0.0f;
	if(strcmp("", ValueForKey(e, "lightmapscale")) ||
	   strcmp("", ValueForKey(e, "_lightmapscale")) || strcmp("", ValueForKey(e, "_ls")))
	{
		baseLightmapScale = FloatForKey(e, "lightmapscale");
		if(baseLightmapScale <= 0.0f)
			baseLightmapScale = FloatForKey(e, "_lightmapscale");
		if(baseLightmapScale <= 0.0f)
			baseLightmapScale = FloatForKey(e, "_ls");
		if(baseLightmapScale < 0.0f)
			baseLightmapScale = 0.0f;
		if(baseLightmapScale > 0.0f)
			Sys_Printf("World Entity has lightmap scale of %.4f\n", baseLightmapScale);
	}

	/* walk the entity list */
	for(num = 1; num < numEntities; num++)
	{
		/* get e2 */
		e2 = &entities[num];

		/* convert misc_models into raw geometry */
		if(Q_stricmp("misc_model", ValueForKey(e2, "classname")))
			continue;

		/* ydnar: added support for md3 models on non-worldspawn models */
		target = ValueForKey(e2, "target");
		if(strcmp(target, targetName))
			continue;

		/* get model name */
		model = ValueForKey(e2, "model");
		if(model[0] == '\0')
		{
			Sys_Printf("WARNING: misc_model at %i %i %i without a model key\n", (int)origin[0], (int)origin[1], (int)origin[2]);
			continue;
		}

		/* get model frame */
		frame = IntForKey(e2, "_frame");

		/* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
		if(e == entities)
		{
			castShadows = WORLDSPAWN_CAST_SHADOWS;
			recvShadows = WORLDSPAWN_RECV_SHADOWS;
		}

		/* other entities don't cast any shadows, but recv worldspawn shadows */
		else
		{
			castShadows = ENTITY_CAST_SHADOWS;
			recvShadows = ENTITY_RECV_SHADOWS;
		}

		/* get explicit shadow flags */
		GetEntityShadowFlags(e2, e, &castShadows, &recvShadows);

		/* get spawnflags */
		spawnFlags = IntForKey(e2, "spawnflags");

		/* Tr3B: added clipModel option */
		spawnFlags |= (IntForKey(e2, "clipModel") > 0) ? 2 : 0;

		/* Tr3B: added forceMeta option */
		spawnFlags |= (IntForKey(e2, "forceMeta") > 0) ? 4 : 0;

		/* get origin */
		GetVectorForKey(e2, "origin", origin);
		VectorSubtract(origin, e->origin, origin);	/* offset by parent */

		/* get "angle" (yaw) or "angles" (pitch yaw roll) */
		MatrixIdentity(rotation);
		angles[0] = angles[1] = angles[2] = 0.0f;

		value = ValueForKey(e2, "angle");
		if(value[0] != '\0')
		{
			angles[1] = atof(value);
			MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]);
		}

		value = ValueForKey(e2, "angles");
		if(value[0] != '\0')
		{
			sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
			MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]);
		}

		value = ValueForKey(e2, "rotation");
		if(value[0] != '\0')
		{
			sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2],
				   &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]);
		}

		/* get scale */
		scale[0] = scale[1] = scale[2] = 1.0f;
		temp = FloatForKey(e2, "modelscale");
		if(temp != 0.0f)
			scale[0] = scale[1] = scale[2] = temp;
		value = ValueForKey(e2, "modelscale_vec");
		if(value[0] != '\0')
			sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]);

		MatrixCopy(rotation, rotationScaled);
		MatrixMultiplyScale(rotationScaled, scale[0], scale[1], scale[2]);

		/* set transform matrix */
		MatrixIdentity(transform);
		MatrixSetupTransformFromRotation(transform, rotationScaled, origin);

		/* get shader remappings */
		remap = NULL;
		for(ep = e2->epairs; ep != NULL; ep = ep->next)
		{
			/* look for keys prefixed with "_remap" */
			if(ep->key != NULL && ep->value != NULL &&
			   ep->key[0] != '\0' && ep->value[0] != '\0' && !Q_strncasecmp(ep->key, "_remap", 6))
			{
				/* create new remapping */
				remap2 = remap;
				remap = safe_malloc(sizeof(*remap));
				remap->next = remap2;
				strcpy(remap->from, ep->value);

				/* split the string */
				split = strchr(remap->from, ';');
				if(split == NULL)
				{
					Sys_Printf("WARNING: Shader _remap key found in misc_model without a ; character\n");
					free(remap);
					remap = remap2;
					continue;
				}

				/* store the split */
				*split = '\0';
				strcpy(remap->to, (split + 1));

				/* note it */
				//% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to );
			}
		}

		/* ydnar: cel shader support */
		value = ValueForKey(e2, "_celshader");
		if(value[0] == '\0')
			value = ValueForKey(&entities[0], "_celshader");
		if(value[0] != '\0')
		{
			sprintf(shader, "textures/%s", value);
			celShader = ShaderInfoForShader(shader);
		}
		else
			celShader = NULL;

		/* jal : entity based _samplesize */
		lightmapSampleSize = 0;
		if(strcmp("", ValueForKey(e2, "_lightmapsamplesize")))
			lightmapSampleSize = IntForKey(e2, "_lightmapsamplesize");
		else if(strcmp("", ValueForKey(e2, "_samplesize")))
			lightmapSampleSize = IntForKey(e2, "_samplesize");

		if(lightmapSampleSize < 0)
			lightmapSampleSize = 0;

		if(lightmapSampleSize > 0.0f)
			Sys_Printf("misc_model has lightmap sample size of %.d\n", lightmapSampleSize);

		/* get lightmap scale */
		/* vortex: added _ls key (short name of lightmapscale) */
		lightmapScale = 0.0f;
		if(strcmp("", ValueForKey(e2, "lightmapscale")) ||
		   strcmp("", ValueForKey(e2, "_lightmapscale")) || strcmp("", ValueForKey(e2, "_ls")))
		{
			lightmapScale = FloatForKey(e2, "lightmapscale");
			if(lightmapScale <= 0.0f)
				lightmapScale = FloatForKey(e2, "_lightmapscale");
			if(lightmapScale <= 0.0f)
				lightmapScale = FloatForKey(e2, "_ls");
			if(lightmapScale < 0.0f)
				lightmapScale = 0.0f;
			if(lightmapScale > 0.0f)
				Sys_Printf("misc_model has lightmap scale of %.4f\n", lightmapScale);
		}

		/* jal : entity based _shadeangle */
		shadeAngle = 0.0f;
		if(strcmp("", ValueForKey(e2, "_shadeangle")))
			shadeAngle = FloatForKey(e2, "_shadeangle");
		/* vortex' aliases */
		else if(strcmp("", ValueForKey(mapEnt, "_smoothnormals")))
			shadeAngle = FloatForKey(mapEnt, "_smoothnormals");
		else if(strcmp("", ValueForKey(mapEnt, "_sn")))
			shadeAngle = FloatForKey(mapEnt, "_sn");
		else if(strcmp("", ValueForKey(mapEnt, "_smooth")))
			shadeAngle = FloatForKey(mapEnt, "_smooth");

		if(shadeAngle < 0.0f)
			shadeAngle = 0.0f;

		if(shadeAngle > 0.0f)
			Sys_Printf("misc_model has shading angle of %.4f\n", shadeAngle);

		/* insert the model */
		InsertModel((char *)model, frame, transform, rotation, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags,
					lightmapScale, lightmapSampleSize, shadeAngle);

		/* free shader remappings */
		while(remap != NULL)
		{
			remap2 = remap->next;
			free(remap);
			remap = remap2;
		}
	}
}
Esempio n. 19
0
void AddTriangleModel(entity_t * e)
{
	int             frame, castShadows, recvShadows, spawnFlags;
	const char     *name, *model, *value;
	char            shader[MAX_QPATH];
	shaderInfo_t   *celShader;
	float           temp, baseLightmapScale, lightmapScale;
	float           shadeAngle;
	int             lightmapSampleSize;
	vec3_t          scale;
	matrix_t        rotation, transform;
	epair_t        *ep;
	remap_t        *remap, *remap2;
	char           *split;

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

	/* get current brush entity name */
	name = ValueForKey(e, "name");

	/* misc_model entities target non-worldspawn brush model entities */
	if(name[0] == '\0')
		return;

	/* get model name */
	model = ValueForKey(e, "model");
	if(model[0] == '\0')
		return;

	/* Tr3B: skip triggers and other entities */
	if(!Q_stricmp(name, model))
		return;

	/* get model frame */
	frame = IntForKey(e, "_frame");

	/* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */
	if(e == entities)
	{
		castShadows = WORLDSPAWN_CAST_SHADOWS;
		recvShadows = WORLDSPAWN_RECV_SHADOWS;
	}

	/* other entities don't cast any shadows, but recv worldspawn shadows */
	else
	{
		castShadows = ENTITY_CAST_SHADOWS;
		recvShadows = ENTITY_RECV_SHADOWS;
	}

	/* get explicit shadow flags */
	GetEntityShadowFlags(NULL, e, &castShadows, &recvShadows);

	/* get spawnflags */
	spawnFlags = IntForKey(e, "spawnflags");

	/* Tr3B: added clipModel option */
	spawnFlags |= (IntForKey(e, "clipModel") > 0) ? 2 : 0;

	/* Tr3B: added forceMeta option */
	spawnFlags |= (IntForKey(e, "forceMeta") > 0) ? 4 : 0;

	/* get scale */
	scale[0] = scale[1] = scale[2] = 1.0f;
	temp = FloatForKey(e, "modelscale");
	if(temp != 0.0f)
		scale[0] = scale[1] = scale[2] = temp;
	value = ValueForKey(e, "modelscale_vec");
	if(value[0] != '\0')
		sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]);

	/* set transform matrix */
	MatrixIdentity(transform);
	MatrixMultiplyScale(transform, scale[0], scale[1], scale[2]);
	MatrixIdentity(rotation);

	/* get shader remappings */
	remap = NULL;
	for(ep = e->epairs; ep != NULL; ep = ep->next)
	{
		/* look for keys prefixed with "_remap" */
		if(ep->key != NULL && ep->value != NULL &&
		   ep->key[0] != '\0' && ep->value[0] != '\0' && !Q_strncasecmp(ep->key, "_remap", 6))
		{
			/* create new remapping */
			remap2 = remap;
			remap = safe_malloc(sizeof(*remap));
			remap->next = remap2;
			strcpy(remap->from, ep->value);

			/* split the string */
			split = strchr(remap->from, ';');
			if(split == NULL)
			{
				Sys_Printf("WARNING: Shader _remap key found in misc_model without a ; character\n");
				free(remap);
				remap = remap2;
				continue;
			}

			/* store the split */
			*split = '\0';
			strcpy(remap->to, (split + 1));

			/* note it */
			//% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to );
		}
	}

	/* ydnar: cel shader support */
	value = ValueForKey(e, "_celshader");
	if(value[0] == '\0')
		value = ValueForKey(&entities[0], "_celshader");
	if(value[0] != '\0')
	{
		sprintf(shader, "textures/%s", value);
		celShader = ShaderInfoForShader(shader);
	}
	else
		celShader = NULL;

	/* get lightmap scale */
	/* jal : entity based _samplesize */
	lightmapSampleSize = 0;
	if(strcmp("", ValueForKey(e, "_lightmapsamplesize")))
		lightmapSampleSize = IntForKey(e, "_lightmapsamplesize");
	else if(strcmp("", ValueForKey(e, "_samplesize")))
		lightmapSampleSize = IntForKey(e, "_samplesize");

	if(lightmapSampleSize < 0)
		lightmapSampleSize = 0;

	if(lightmapSampleSize > 0.0f)
		Sys_Printf(" has lightmap sample size of %.d\n", lightmapSampleSize);

	/* get lightmap scale */
	/* vortex: added _ls key (short name of lightmapscale) */
	lightmapScale = 0.0f;
	if(strcmp("", ValueForKey(e, "lightmapscale")) ||
	   strcmp("", ValueForKey(e, "_lightmapscale")) || strcmp("", ValueForKey(e, "_ls")))
	{
		lightmapScale = FloatForKey(e, "lightmapscale");
		if(lightmapScale <= 0.0f)
			lightmapScale = FloatForKey(e, "_lightmapscale");
		if(lightmapScale <= 0.0f)
			lightmapScale = FloatForKey(e, "_ls");
		if(lightmapScale < 0.0f)
			lightmapScale = 0.0f;
		if(lightmapScale > 0.0f)
			Sys_Printf("misc_model has lightmap scale of %.4f\n", lightmapScale);
	}

	/* jal : entity based _shadeangle */
	shadeAngle = 0.0f;
	if(strcmp("", ValueForKey(e, "_shadeangle")))
		shadeAngle = FloatForKey(e, "_shadeangle");
	/* vortex' aliases */
	else if(strcmp("", ValueForKey(e, "_smoothnormals")))
		shadeAngle = FloatForKey(e, "_smoothnormals");
	else if(strcmp("", ValueForKey(e, "_sn")))
		shadeAngle = FloatForKey(e, "_sn");
	else if(strcmp("", ValueForKey(e, "_smooth")))
		shadeAngle = FloatForKey(e, "_smooth");

	if(shadeAngle < 0.0f)
		shadeAngle = 0.0f;

	if(shadeAngle > 0.0f)
		Sys_Printf("misc_model has shading angle of %.4f\n", shadeAngle);

	/* insert the model */
	InsertModel((char *)model, frame, transform, rotation, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags,
				lightmapScale, lightmapSampleSize, shadeAngle);

	/* free shader remappings */
	while(remap != NULL)
	{
		remap2 = remap->next;
		free(remap);
		remap = remap2;
	}
}
Esempio n. 20
0
/*
================
SetTerrainTextures
================
*/
void SetTerrainTextures( void ) {
	int				i;
	int				x, y;
	int				layer;
	int				minlayer, maxlayer;
	float			s, t;
	float			min_s, min_t;
	int				alpha[ MAX_POINTS_ON_WINDING ];
	shaderInfo_t	*si, *terrainShader;
	bspbrush_t		*brush;
	side_t			*side;
	const char		*shadername;
	vec3_t			mins, maxs;
	vec3_t			size;
	int				surfwidth, surfheight, surfsize;
	terrainSurf_t	*surf;
	byte			*alphamap;
	int				alphawidth, alphaheight;
	int				num_layers;
	extern qboolean	onlyents;

	if ( onlyents ) {
		return;
	}

	shadername = ValueForKey( mapent, "shader" );
	if ( !shadername[ 0 ] ) {
		Error ("SetTerrainTextures: shader not specified" );
	}

	alphamap = LoadAlphaMap( &num_layers, &alphawidth, &alphaheight );
	num_layers = 3;

	mapent->firstDrawSurf = numMapDrawSurfs;

	// calculate the size of the terrain
	CalcTerrainSize( mins, maxs, size );

	surfwidth	= ( size[ 0 ] + SURF_WIDTH - 1 ) / SURF_WIDTH;
	surfheight	= ( size[ 1 ] + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
	surfsize = surfwidth * surfheight;

	lastSurface = NULL;
	numsurfaces = 0;
	maxsurfaces = 0;
	for( i = num_layers; i > 0; i-- ) {
		maxsurfaces += i * surfsize;
	}
	surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
	memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );

	terrainShader = ShaderInfoForShader( "textures/common/terrain" );

	for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
		// only create surfaces for sides marked as terrain
		for( side = brush->sides; side < &brush->sides[ brush->numsides ]; side++ ) {
			if ( !side->shaderInfo ) {
				continue;
			}

			if ( ( ( side->surfaceFlags | side->shaderInfo->surfaceFlags ) & SURF_NODRAW ) && !strstr( side->shaderInfo->shader, "terrain" ) ) {
				continue;
			}

			minlayer = num_layers;
			maxlayer = 0;

			// project each point of the winding onto the alphamap to determine which
			// textures to blend
			min_s = 1.0;
			min_t = 1.0;
			for( i = 0; i < side->winding->numpoints; i++ ) {
				s = floor( side->winding->p[ i ][ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
				t = floor( maxs[ 1 ] - side->winding->p[ i ][ 1 ] + 0.1f ) / size[ 1 ];

				if ( s < 0 ) {
					s = 0;
				}
				
				if ( t < 0 ) {
					t = 0;
				}

				if ( s >= 1.0 ) {
					s = 1.0;
				}

				if ( t >= 1.0 ) {
					t = 1.0;
				}

				if ( s < min_s ) {
					min_s = s;
				}

				if ( t < min_t ) {
					min_t = t;
				}

				x = ( alphawidth - 1 ) * s;
				y = ( alphaheight - 1 ) * t;

				layer = alphamap[ x + y * alphawidth ];
				if ( layer < minlayer ) {
					minlayer = layer;
				}

				if ( layer > maxlayer ) {
					maxlayer = layer;
				}

				alpha[ i ] = layer;
			}

			x = min_s * surfwidth;
			if ( x >= surfwidth ) {
				x = surfwidth - 1;
			}

			y = min_t * surfheight;
			if ( y >= surfheight ) {
				y = surfheight - 1;
			}

			if ( strstr( side->shaderInfo->shader, "terrain" ) ) {
				si = ShaderForLayer( minlayer, maxlayer, shadername );
				if ( showseams ) {
					for( i = 0; i < side->winding->numpoints; i++ ) {
						if ( ( alpha[ i ] != minlayer ) && ( alpha[ i ] != maxlayer ) ) {
							si = ShaderInfoForShader( "textures/common/white" );
							break;
						}
					}
				}
				surf = SurfaceForShader( si, x, y );
				EmitTerrainVerts( side, surf, maxlayer, alpha, qtrue );
			} else {
				si = side->shaderInfo;
				side->shaderInfo = terrainShader;
				surf = SurfaceForShader( si, x, y );
				EmitTerrainVerts( side, surf, maxlayer, alpha, qfalse );
			}
		}
	}

	// create the final surfaces
	for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
		if ( surf->numVerts ) {
			CreateTerrainSurface( surf, surf->shader );
		}
	}

	//
	// clean up any allocated memory
	//
	for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
		if ( surf->verts ) {
			free( surf->verts );
			free( surf->indexes );
		}
	}
	free( alphamap );
	free( surfaces );

	surfaces = NULL;
	lastSurface = NULL;
	numsurfaces = 0;
	maxsurfaces = 0;
}
Esempio n. 21
0
int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags ){
	int i;
	shaderInfo_t    *si;


	/* handle special cases */
	if ( shader == NULL ) {
		shader = "noshader";
	}

	/* try to find an existing shader */
	for ( i = 0; i < numBSPShaders; i++ )
	{
		/* ydnar: handle custom surface/content flags */
#ifndef SMOKINGUNS
		if ( surfaceFlags != NULL && bspShaders[ i ].surfaceFlags != *surfaceFlags ) {
			continue;
		}
		if ( contentFlags != NULL && bspShaders[ i ].contentFlags != *contentFlags ) {
			continue;
		}
#endif

		/* compare name */
		if ( !Q_stricmp( shader, bspShaders[ i ].shader ) ) {
			return i;
		}
	}

	/* get shaderinfo */
	si = ShaderInfoForShader( shader );

	/* emit a new shader */
	if ( i == MAX_MAP_SHADERS ) {
		Error( "MAX_MAP_SHADERS" );
	}
	numBSPShaders++;
	strcpy( bspShaders[ i ].shader, shader );
	bspShaders[ i ].surfaceFlags = si->surfaceFlags;
#ifdef SMOKINGUNS
	bspShaders[ i ].surfaceFlags |= GetSurfaceParm(si->shader);
#endif
	bspShaders[ i ].contentFlags = si->contentFlags;

	/* handle custom content/surface flags */
#ifndef SMOKINGUNS
	if ( surfaceFlags != NULL ) {
		bspShaders[ i ].surfaceFlags = *surfaceFlags;
	}
	if ( contentFlags != NULL ) {
		bspShaders[ i ].contentFlags = *contentFlags;
	}
#endif

	/* recursively emit any damage shaders */
	if ( si->damageShader != NULL && si->damageShader[ 0 ] != '\0' ) {
		Sys_FPrintf( SYS_VRB, "Shader %s has damage shader %s\n", si->shader, si->damageShader );
		EmitShader( si->damageShader, NULL, NULL );
	}

	/* return it */
	return i;
}