Beispiel #1
0
/*
===================
R_ParseImageProgram_r

If pic is NULL, the timestamps will be filled in, but no image will be generated
If both pic and timestamps are NULL, it will just advance past it, which can be
used to parse an image program from a text stream.
===================
*/
static bool R_ParseImageProgram_r( idLexer &src, byte **pic, int *width, int *height,
								  ID_TIME_T *timestamps, textureDepth_t *depth ) {
	idToken		token;
	float		scale;
	ID_TIME_T		timestamp;

	src.ReadToken( &token );
	AppendToken( token );

	if ( !token.Icmp( "heightmap" ) ) {
		MatchAndAppendToken( src, "(" );

		if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) {
			return false;
		}

		MatchAndAppendToken( src, "," );

		src.ReadToken( &token );
		AppendToken( token );
		scale = token.GetFloatValue();
		
		// process it
		if ( pic ) {
			R_HeightmapToNormalMap( *pic, *width, *height, scale );
			if ( depth ) {
				*depth = TD_BUMP;
			}
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "addnormals" ) ) {
		byte	*pic2;
		int		width2, height2;

		MatchAndAppendToken( src, "(" );

		if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) {
			return false;
		}

		MatchAndAppendToken( src, "," );

		if ( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, depth ) ) {
			if ( pic ) {
				R_StaticFree( *pic );
				*pic = NULL;
			}
			return false;
		}
		
		// process it
		if ( pic ) {
			R_AddNormalMaps( *pic, *width, *height, pic2, width2, height2 );
			R_StaticFree( pic2 );
			if ( depth ) {
				*depth = TD_BUMP;
			}
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "smoothnormals" ) ) {
		MatchAndAppendToken( src, "(" );

		if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) {
			return false;
		}

		if ( pic ) {
			R_SmoothNormalMap( *pic, *width, *height );
			if ( depth ) {
				*depth = TD_BUMP;
			}
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "add" ) ) {
		byte	*pic2;
		int		width2, height2;

		MatchAndAppendToken( src, "(" );

		if ( !R_ParseImageProgram_r( src, pic, width, height, timestamps, depth ) ) {
			return false;
		}

		MatchAndAppendToken( src, "," );

		if ( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, depth ) ) {
			if ( pic ) {
				R_StaticFree( *pic );
				*pic = NULL;
			}
			return false;
		}
		
		// process it
		if ( pic ) {
			R_ImageAdd( *pic, *width, *height, pic2, width2, height2 );
			R_StaticFree( pic2 );
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "scale" ) ) {
		float	scale[4];
		int		i;

		MatchAndAppendToken( src, "(" );

		R_ParseImageProgram_r( src, pic, width, height, timestamps, depth );

		for ( i = 0 ; i < 4 ; i++ ) {
			MatchAndAppendToken( src, "," );
			src.ReadToken( &token );
			AppendToken( token );
			scale[i] = token.GetFloatValue();
		}

		// process it
		if ( pic ) {
			R_ImageScale( *pic, *width, *height, scale );
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "invertAlpha" ) ) {
		MatchAndAppendToken( src, "(" );

		R_ParseImageProgram_r( src, pic, width, height, timestamps, depth );

		// process it
		if ( pic ) {
			R_InvertAlpha( *pic, *width, *height );
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "invertColor" ) ) {
		MatchAndAppendToken( src, "(" );

		R_ParseImageProgram_r( src, pic, width, height, timestamps, depth );

		// process it
		if ( pic ) {
			R_InvertColor( *pic, *width, *height );
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "makeIntensity" ) ) {
		int		i;

		MatchAndAppendToken( src, "(" );

		R_ParseImageProgram_r( src, pic, width, height, timestamps, depth );

		// copy red to green, blue, and alpha
		if ( pic ) {
			int		c;
			c = *width * *height * 4;
			for ( i = 0 ; i < c ; i+=4 ) {
				(*pic)[i+1] = 
				(*pic)[i+2] = 
				(*pic)[i+3] = (*pic)[i];
			}
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	if ( !token.Icmp( "makeAlpha" ) ) {
		int		i;

		MatchAndAppendToken( src, "(" );

		R_ParseImageProgram_r( src, pic, width, height, timestamps, depth );

		// average RGB into alpha, then set RGB to white
		if ( pic ) {
			int		c;
			c = *width * *height * 4;
			for ( i = 0 ; i < c ; i+=4 ) {
				(*pic)[i+3] = ( (*pic)[i+0] + (*pic)[i+1] + (*pic)[i+2] ) / 3;
				(*pic)[i+0] = 
				(*pic)[i+1] = 
				(*pic)[i+2] = 255;
			}
		}

		MatchAndAppendToken( src, ")" );
		return true;
	}

	// if we are just parsing instead of loading or checking,
	// don't do the R_LoadImage
	if ( !timestamps && !pic ) {
		return true;
	}

	// load it as an image
	R_LoadImage( token.c_str(), pic, width, height, &timestamp, true );

	if ( timestamp == -1 ) {
		return false;
	}

	// add this to the timestamp
	if ( timestamps ) {
		if ( timestamp > *timestamps ) {
			*timestamps = timestamp;
		}
	}

	return true;
}
/*
===================
R_ParseImageProgram_r

If pic is NULL, the timestamps will be filled in, but no image will be generated
If both pic and timestamps are NULL, it will just advance past it, which can be
used to parse an image program from a text stream.
===================
*/
static bool R_ParseImageProgram_r( idLexer& src, byte** pic, int* width, int* height,
								   ID_TIME_T* timestamps, textureUsage_t* usage )
{
	idToken		token;
	float		scale;
	ID_TIME_T		timestamp;
	
	src.ReadToken( &token );
	
	// Since all interaction shaders now assume YCoCG diffuse textures.  We replace all entries for the intrinsic
	// _black texture to the black texture on disk.  Doing this will cause a YCoCG compliant texture to be generated.
	// Without a YCoCG compliant black texture we will get color artifacts for any interaction
	// material that specifies the _black texture.
	if( token == "_black" )
	{
		token = "textures/black";
	}
	
	// also check for _white
	if( token == "_white" )
	{
		token = "guis/assets/white";
	}
	
	AppendToken( token );
	
	if( !token.Icmp( "heightmap" ) )
	{
		MatchAndAppendToken( src, "(" );
		
		if( !R_ParseImageProgram_r( src, pic, width, height, timestamps, usage ) )
		{
			return false;
		}
		
		MatchAndAppendToken( src, "," );
		
		src.ReadToken( &token );
		AppendToken( token );
		scale = token.GetFloatValue();
		
		// process it
		if( pic )
		{
			R_HeightmapToNormalMap( *pic, *width, *height, scale );
			if( usage )
			{
				*usage = TD_BUMP;
			}
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "addnormals" ) )
	{
		byte*	pic2 = NULL;
		int		width2, height2;
		
		MatchAndAppendToken( src, "(" );
		
		if( !R_ParseImageProgram_r( src, pic, width, height, timestamps, usage ) )
		{
			return false;
		}
		
		MatchAndAppendToken( src, "," );
		
		if( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, usage ) )
		{
			if( pic )
			{
				R_StaticFree( *pic );
				*pic = NULL;
			}
			return false;
		}
		
		// process it
		if( pic )
		{
			R_AddNormalMaps( *pic, *width, *height, pic2, width2, height2 );
			R_StaticFree( pic2 );
			if( usage )
			{
				*usage = TD_BUMP;
			}
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "smoothnormals" ) )
	{
		MatchAndAppendToken( src, "(" );
		
		if( !R_ParseImageProgram_r( src, pic, width, height, timestamps, usage ) )
		{
			return false;
		}
		
		if( pic )
		{
			R_SmoothNormalMap( *pic, *width, *height );
			if( usage )
			{
				*usage = TD_BUMP;
			}
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "add" ) )
	{
		byte*	pic2 = NULL;
		int		width2, height2;
		
		MatchAndAppendToken( src, "(" );
		
		if( !R_ParseImageProgram_r( src, pic, width, height, timestamps, usage ) )
		{
			return false;
		}
		
		MatchAndAppendToken( src, "," );
		
		if( !R_ParseImageProgram_r( src, pic ? &pic2 : NULL, &width2, &height2, timestamps, usage ) )
		{
			if( pic )
			{
				R_StaticFree( *pic );
				*pic = NULL;
			}
			return false;
		}
		
		// process it
		if( pic )
		{
			R_ImageAdd( *pic, *width, *height, pic2, width2, height2 );
			R_StaticFree( pic2 );
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "scale" ) )
	{
		float	scale[4];
		int		i;
		
		MatchAndAppendToken( src, "(" );
		
		R_ParseImageProgram_r( src, pic, width, height, timestamps, usage );
		
		for( i = 0 ; i < 4 ; i++ )
		{
			MatchAndAppendToken( src, "," );
			src.ReadToken( &token );
			AppendToken( token );
			scale[i] = token.GetFloatValue();
		}
		
		// process it
		if( pic )
		{
			R_ImageScale( *pic, *width, *height, scale );
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "invertAlpha" ) )
	{
		MatchAndAppendToken( src, "(" );
		
		R_ParseImageProgram_r( src, pic, width, height, timestamps, usage );
		
		// process it
		if( pic )
		{
			R_InvertAlpha( *pic, *width, *height );
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "invertColor" ) )
	{
		MatchAndAppendToken( src, "(" );
		
		R_ParseImageProgram_r( src, pic, width, height, timestamps, usage );
		
		// process it
		if( pic )
		{
			R_InvertColor( *pic, *width, *height );
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "makeIntensity" ) )
	{
		int		i;
		
		MatchAndAppendToken( src, "(" );
		
		R_ParseImageProgram_r( src, pic, width, height, timestamps, usage );
		
		// copy red to green, blue, and alpha
		if( pic )
		{
			int		c;
			c = *width * *height * 4;
			for( i = 0 ; i < c ; i += 4 )
			{
				( *pic )[i + 1] =
					( *pic )[i + 2] =
						( *pic )[i + 3] = ( *pic )[i];
			}
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	if( !token.Icmp( "makeAlpha" ) )
	{
		int		i;
		
		MatchAndAppendToken( src, "(" );
		
		R_ParseImageProgram_r( src, pic, width, height, timestamps, usage );
		
		// average RGB into alpha, then set RGB to white
		if( pic )
		{
			int		c;
			c = *width * *height * 4;
			for( i = 0 ; i < c ; i += 4 )
			{
				( *pic )[i + 3] = ( ( *pic )[i + 0] + ( *pic )[i + 1] + ( *pic )[i + 2] ) / 3;
				( *pic )[i + 0] =
					( *pic )[i + 1] =
						( *pic )[i + 2] = 255;
			}
		}
		
		MatchAndAppendToken( src, ")" );
		return true;
	}
	
	// if we are just parsing instead of loading or checking,
	// don't do the R_LoadImage
	if( !timestamps && !pic )
	{
		return true;
	}
	
	// load it as an image
	R_LoadImage( token.c_str(), pic, width, height, &timestamp, true );
	
	if( timestamp == -1 )
	{
		return false;
	}
	
	// add this to the timestamp
	if( timestamps )
	{
		if( timestamp > *timestamps )
		{
			*timestamps = timestamp;
		}
	}
	
	return true;
}