map.c

来自「quake3工具源码。包括生成bsp文件」· C语言 代码 · 共 1,228 行 · 第 1/2 页

C
1,228
字号
*/
vec3_t	baseaxis[18] =
{
{0,0,1}, {1,0,0}, {0,-1,0},			// floor
{0,0,-1}, {1,0,0}, {0,-1,0},		// ceiling
{1,0,0}, {0,1,0}, {0,0,-1},			// west wall
{-1,0,0}, {0,1,0}, {0,0,-1},		// east wall
{0,1,0}, {1,0,0}, {0,0,-1},			// south wall
{0,-1,0}, {1,0,0}, {0,0,-1}			// north wall
};

void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
{
	int		bestaxis;
	vec_t	dot,best;
	int		i;
	
	best = 0;
	bestaxis = 0;
	
	for (i=0 ; i<6 ; i++)
	{
		dot = DotProduct (pln->normal, baseaxis[i*3]);
		if (dot > best)
		{
			best = dot;
			bestaxis = i;
		}
	}
	
	VectorCopy (baseaxis[bestaxis*3+1], xv);
	VectorCopy (baseaxis[bestaxis*3+2], yv);
}



/*
=================
QuakeTextureVecs

Creates world-to-texture mapping vecs for crappy quake plane arrangements
=================
*/
void QuakeTextureVecs( 	plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2],
					  vec_t mappingVecs[2][4] ) {
 
	vec3_t	vecs[2];
	int		sv, tv;
	vec_t	ang, sinv, cosv;
	vec_t	ns, nt;
	int		i, j;

	TextureAxisFromPlane(plane, vecs[0], vecs[1]);

	if (!scale[0])
		scale[0] = 1;
	if (!scale[1])
		scale[1] = 1;

	// rotate axis
	if (rotate == 0)
		{ sinv = 0 ; cosv = 1; }
	else if (rotate == 90)
		{ sinv = 1 ; cosv = 0; }
	else if (rotate == 180)
		{ sinv = 0 ; cosv = -1; }
	else if (rotate == 270)
		{ sinv = -1 ; cosv = 0; }
	else
	{	
		ang = rotate / 180 * Q_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++)
			mappingVecs[i][j] = vecs[i][j] / scale[i];

	mappingVecs[0][3] = shift[0];
	mappingVecs[1][3] = shift[1];
}

//======================================================================

/*
=================
ParseRawBrush

Just parses the sides into buildBrush->sides[], nothing else.
no validation, back plane removal, etc.

Timo - 08/26/99
added brush epairs parsing ( ignoring actually )
Timo - 08/04/99
added exclusive brush primitive parsing
Timo - 08/08/99
support for old brush format back in
NOTE : it would be "cleaner" to have seperate functions to parse between old and new brushes
=================
*/
void	ParseRawBrush( ) {
	side_t		*side;
	vec3_t		planepts[3];
	int			planenum;
	shaderInfo_t	*si;
	// old brushes
	vec_t		shift[2];
	vec_t		rotate;
	vec_t		scale[2];
	char		name[MAX_QPATH];
	char		shader[MAX_QPATH];
	int			flags;

	buildBrush->numsides = 0;
	buildBrush->detail = qfalse;

	if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
		MatchToken( "{" );

	do
	{
		if (!GetToken (qtrue))
			break;
		if (!strcmp (token, "}") )
			break;
		//Timo : brush primitive : here we may have to jump over brush epairs ( only used in editor )
		if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
		{
			do
			{
				if (strcmp (token, "(") )
					GetToken( qfalse );
				else
					break;
				GetToken( qtrue );
			} while (1);
		}
		UnGetToken();

		if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
			Error( "MAX_BUILD_SIDES" );
		}

		side = &buildBrush->sides[ buildBrush->numsides ];
		memset( side, 0, sizeof( *side ) );
		buildBrush->numsides++;

		// read the three point plane definition
		Parse1DMatrix( 3, planepts[0] );
		Parse1DMatrix( 3, planepts[1] );
		Parse1DMatrix( 3, planepts[2] );

		if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
			// read the texture matrix
			Parse2DMatrix( 2, 3, (float *)side->texMat );

		// read the texturedef
		GetToken (qfalse);
		strcpy (name, token);

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

		if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
		{
			GetToken (qfalse);
			shift[0] = atoi(token);
			GetToken (qfalse);
			shift[1] = atoi(token);
			GetToken (qfalse);
			rotate = atoi(token);	
			GetToken (qfalse);
			scale[0] = atof(token);
			GetToken (qfalse);
			scale[1] = atof(token);
		}

		// find default flags and values
		sprintf( shader, "textures/%s", name );
		si = ShaderInfoForShader( shader );
		side->shaderInfo = si;
		side->surfaceFlags = si->surfaceFlags;
		side->value = si->value;
		side->contents = si->contents;

		// allow override of default flags and values
		// in Q3, the only thing you can override is DETAIL
		if (TokenAvailable())
		{
			GetToken (qfalse);
//			side->contents = atoi(token);
			flags = atoi(token);
			if ( flags & CONTENTS_DETAIL ) {
				side->contents |= CONTENTS_DETAIL;
			}

			GetToken (qfalse);
//			td.flags = atoi(token);

			GetToken (qfalse);
//			td.value = atoi(token);
		}


		// find the plane number
		planenum = MapPlaneFromPoints (planepts[0], planepts[1], planepts[2]);
		side->planenum = planenum;

		if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
			// get the texture mapping for this texturedef / plane combination
			QuakeTextureVecs( &mapplanes[planenum], shift, rotate, scale, side->vecs );

	} while (1);

	if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
	{
		UnGetToken();
		MatchToken( "}" );
		MatchToken( "}" );
	}
}

/*
=================
RemoveDuplicateBrushPlanes

Returns false if the brush has a mirrored set of planes,
meaning it encloses no volume.
Also removes planes without any normal
=================
*/
qboolean RemoveDuplicateBrushPlanes( bspbrush_t * b ) {
	int			i, j, k;
	side_t		*sides;

	sides = b->sides;

	for ( i = 1 ; i < b->numsides ; i++ ) {

		// check for a degenerate plane
		if ( sides[i].planenum == -1) {
			_printf ("Entity %i, Brush %i: degenerate plane\n"
				, b->entitynum, b->brushnum);
			// remove it
			for ( k = i + 1 ; k < b->numsides ; k++ ) {
				sides[k-1] = sides[k];
			}
			b->numsides--;
			i--;
			continue;
		}

		// check for duplication and mirroring
		for ( j = 0 ; j < i ; j++ ) {
			if ( sides[i].planenum == sides[j].planenum ) {
				_printf ("Entity %i, Brush %i: duplicate plane\n"
					, b->entitynum, b->brushnum);
				// remove the second duplicate
				for ( k = i + 1 ; k < b->numsides ; k++ ) {
					sides[k-1] = sides[k];
				}
				b->numsides--;
				i--;
				break;
			}

			if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
				// mirror plane, brush is invalid
				_printf ("Entity %i, Brush %i: mirrored plane\n"
					, b->entitynum, b->brushnum);
				return qfalse;
			}
		}
	}
	return qtrue;
}


/*
=================
ParseBrush

  qboolean parameter to true -> parse new brush primitive format ( else use old format )
=================
*/
void ParseBrush (void) {
	bspbrush_t	*b;

	ParseRawBrush();

	buildBrush->portalareas[0] = -1;
	buildBrush->portalareas[1] = -1;
	buildBrush->entitynum = num_entities-1;
	buildBrush->brushnum = entitySourceBrushes;

	// if there are mirrored planes, the entire brush is invalid
	if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
		return;
	}

	// get the content for the entire brush
	SetBrushContents( buildBrush );

	// allow detail brushes to be removed 
	if (nodetail && (buildBrush->contents & CONTENTS_DETAIL) ) {
		FreeBrush( buildBrush );
		return;
	}

	// allow water brushes to be removed
	if (nowater && (buildBrush->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) {
		FreeBrush( buildBrush );
		return;
	}

	b = FinishBrush( );
	if ( !b ) {
		return;
	}
}


/*
================
MoveBrushesToWorld

Takes all of the brushes from the current entity and
adds them to the world's brush list.

Used by func_group
================
*/
void MoveBrushesToWorld (entity_t *mapent) {
	bspbrush_t	*b, *next;
	parseMesh_t	*pm;

	// move brushes
	for ( b = mapent->brushes ; b ; b = next ) {
		next = b->next;

		b->next = entities[0].brushes;
		entities[0].brushes = b;
	}
	mapent->brushes = NULL;

	// move patches
	if ( mapent->patches ) {

		for ( pm = mapent->patches ; pm->next ; pm = pm->next ) {
		}

		pm->next = entities[0].patches;
		entities[0].patches = mapent->patches;

		mapent->patches = NULL;
	}
}


/*
================
AdjustBrushesForOrigin
================
*/
void AdjustBrushesForOrigin( entity_t *ent ) {
	bspbrush_t	*b;
	int			i;
	side_t		*s;
	vec_t		newdist;
	parseMesh_t	*p;

	for ( b = ent->brushes ; b ; b = b->next ) {
		for (i=0 ; i<b->numsides ; i++) {
			s = &b->sides[i];
			newdist = mapplanes[s->planenum].dist -
				DotProduct (mapplanes[s->planenum].normal, ent->origin);
			s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
		}
		CreateBrushWindings(b);
	}

	for ( p = ent->patches ; p ; p = p->next ) {
		for ( i = 0 ; i < p->mesh.width*p->mesh.height ; i++ ) {
			VectorSubtract( p->mesh.verts[i].xyz, ent->origin, p->mesh.verts[i].xyz );
		}
	}

}

/*
================
ParseMapEntity
================
*/
qboolean	ParseMapEntity (void) {
	epair_t		*e;

	if (!GetToken (qtrue))
		return qfalse;

	if (strcmp (token, "{") )
	{
		Error ("ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...", token, scriptline, entities[num_entities].origin[0], entities[num_entities].origin[1], entities[num_entities].origin[2]);
	}
	
	if (num_entities == MAX_MAP_ENTITIES)
		Error ("num_entities == MAX_MAP_ENTITIES");

	entitySourceBrushes = 0;

	mapent = &entities[num_entities];
	num_entities++;
	memset (mapent, 0, sizeof(*mapent));

	do
	{
		if (!GetToken (qtrue))
			Error ("ParseEntity: EOF without closing brace");
		if (!strcmp (token, "}") )
			break;

		if (!strcmp (token, "{") ) {
			// parse a brush or patch
			if (!GetToken (qtrue))
				break;
			if ( !strcmp( token, "patchDef2" ) ) {
				numMapPatches++;
				ParsePatch();
			} else if ( !strcmp( token, "brushDef" ) ) {
				if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
					Error("old brush format not allowed in new brush format map");
				g_bBrushPrimit=BPRIMIT_NEWBRUSHES;
				// parse brush primitive
				ParseBrush();
			}
			else
			{
				if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
					Error("new brush format not allowed in old brush format map");
				g_bBrushPrimit=BPRIMIT_OLDBRUSHES;
				// parse old brush format
				UnGetToken();
				ParseBrush();
			}
			entitySourceBrushes++;
		}
		else
		{
			// parse a key / value pair
			e = ParseEpair ();
			e->next = mapent->epairs;
			mapent->epairs = e;
		}
	} while (1);

	GetVectorForKey (mapent, "origin", mapent->origin);

	//
	// if there was an origin brush, offset all of the planes and texinfo
	// for all the brushes in the entity
	if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
		AdjustBrushesForOrigin( mapent );
	}

  // group_info entities are just for editor grouping
  // ignored
  // FIXME: leak!
  if (!strcmp("group_info", ValueForKey (mapent, "classname")))
  {
    num_entities--;
    return qtrue;
  }

	// group entities are just for editor convenience
	// toss all brushes into the world entity
	if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
	{
		if ( !strcmp ("1", ValueForKey (mapent, "terrain"))) {
			SetTerrainTextures();
		}
		MoveBrushesToWorld (mapent);
		num_entities--;
		return qtrue;
	}

	return qtrue;
}

//===================================================================


/*
================
LoadMapFile
================
*/
void LoadMapFile (char *filename) {		
	bspbrush_t	*b;

	qprintf ("--- LoadMapFile ---\n");
	_printf ("Loading map file %s\n", filename);

	LoadScriptFile (filename);

	num_entities = 0;
	numMapDrawSurfs = 0;
	c_detail = 0;

	g_bBrushPrimit = BPRIMIT_UNDEFINED;

	// allocate a very large temporary brush for building
	// the brushes as they are loaded
	buildBrush = AllocBrush( MAX_BUILD_SIDES );

	while (ParseMapEntity ())
	{
	}

	ClearBounds (map_mins, map_maxs);
	for ( b = entities[0].brushes ; b ; b=b->next ) {
		AddPointToBounds( b->mins, map_mins, map_maxs );
		AddPointToBounds( b->maxs, map_mins, map_maxs );
	}

	qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) );
	qprintf ("%5i detail brushes\n", c_detail );
	qprintf ("%5i patches\n", numMapPatches);
	qprintf ("%5i boxbevels\n", c_boxbevels);
	qprintf ("%5i edgebevels\n", c_edgebevels);
	qprintf ("%5i entities\n", num_entities);
	qprintf ("%5i planes\n", nummapplanes);
	qprintf ("%5i areaportals\n", c_areaportals);
	qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
		map_maxs[0],map_maxs[1],map_maxs[2]);

	if ( fakemap ) {
		WriteBspBrushMap ("fakemap.map", entities[0].brushes );
	}

	if ( testExpand ) {
		TestExpandBrushes ();
	}
}


//====================================================================


/*
================
TestExpandBrushes

Expands all the brush planes and saves a new map out to
allow visual inspection of the clipping bevels
================
*/
void TestExpandBrushes( void ) {
	side_t	*s;
	int		i, j;
	bspbrush_t	*brush, *list, *copy;
	vec_t	dist;
	plane_t		*plane;

	list = NULL;

	for ( brush = entities[0].brushes ; brush ; brush = brush->next ) {
		copy = CopyBrush( brush );
		copy->next = list;
		list = copy;

		// expand all the planes
		for ( i=0 ; i<brush->numsides ; i++ ) {
			s = brush->sides + i;
			plane = &mapplanes[s->planenum];
			dist = plane->dist;
			for (j=0 ; j<3 ; j++) {
				dist += fabs( 16 * plane->normal[j] );
			}
			s->planenum = FindFloatPlane( plane->normal, dist );
		}

	}

	WriteBspBrushMap ( "expanded.map", entities[0].brushes );

	Error ("can't proceed after expanding brushes");
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?