void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) {
	int		i;

	Com_MatchToken( buf_p, "(" );

	for (i = 0 ; i < z ; i++) {
		Com_Parse2DMatrix (buf_p, y, x, m + i * x*y);
	}

	Com_MatchToken( buf_p, ")" );
}
Exemple #2
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, "}" );
	}
}