Esempio n. 1
0
/*
================
CL_DrawLine

================
*/
static void CL_DrawLine( const vec3_t start, const vec3_t end, int pcolor, float life, float gap )
{
	particle_t	*p;
	float		len, curdist;
	vec3_t		diff;
	int		i;

	// Determine distance;
	VectorSubtract( end, start, diff );
	len = VectorNormalizeLength( diff );
	curdist = 0;

	while( curdist <= len )
	{
		p = CL_AllocParticle( NULL );
		if( !p ) return;

		for( i = 0; i < 3; i++ )
			p->org[i] = start[i] + curdist * diff[i];

		p->color = pcolor;
		p->type = pt_static;
		p->die += life;
		curdist += gap;
	}
}
Esempio n. 2
0
/*
===============
CL_TracerEffect

===============
*/
void CL_TracerEffect( const vec3_t start, const vec3_t end )
{
	particle_t	*p;
	byte		*color;
	vec3_t		dir;
	float		life, dist;

	p = CL_AllocParticle( CL_BulletTracerDraw );
	if( !p ) return;

	// get out shot direction and length
	VectorSubtract( end, start, dir );
	VectorCopy( dir, p->vel );

	dist = VectorNormalizeLength( dir );

	// don't make small tracers
	if( dist <= traceroffset->value )
		return;

	p->ramp = Com_RandomFloat( 200.0f, 256.0f ) * tracerlength->value;

	color = gTracerColors[4];
	life = ( dist + p->ramp ) / ( max( 1.0f, tracerspeed->value ));
	p->color = CL_LookupColor( color[0], color[1], color[2] );
	VectorCopy( start, p->org );
	p->type = pt_tracer;
	p->die += life;
}
Esempio n. 3
0
/*
=====================
PlaneFromPoints

Returns false if the triangle is degenrate.
The normal will point out of the clock for clockwise ordered points
=====================
*/
bool PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c )
{
	vec3_t	d1, d2;

	VectorSubtract( b, a, d1 );
	VectorSubtract( c, a, d2 );
	CrossProduct( d2, d1, plane );
	if( VectorNormalizeLength( plane ) == 0.0f )
		return false;
	plane[3] = DotProduct( a, plane );

	return true;
}
Esempio n. 4
0
/*
===============
CL_RocketTrail

===============
*/
void CL_RocketTrail( vec3_t start, vec3_t end, int type )
{
	vec3_t		vec;
	float		len;
	particle_t	*p;
	int		j, dec;
	static int	tracercount;

	VectorSubtract( end, start, vec );
	len = VectorNormalizeLength( vec );

	if( type < 128 )
	{
		dec = 3;
	}
	else
	{
		dec = 1;
		type -= 128;
	}

	while( len > 0 )
	{
		len -= dec;

		p = CL_AllocParticle( NULL );
		if( !p ) return;
		
		p->die += 2.0f;

		switch( type )
		{
		case 0:	// rocket trail
			p->ramp = Com_RandomLong( 0, 4 );
			p->color = ramp3[(int)p->ramp];
			p->type = pt_fire;
			for( j = 0; j < 3; j++ )
				p->org[j] = start[j] + ((rand() % 6 ) - 3 );
			break;
		case 1:	// smoke smoke
			p->ramp = Com_RandomLong( 2, 6 );
			p->color = ramp3[(int)p->ramp];
			p->type = pt_fire;
			for( j = 0; j < 3; j++ )
				p->org[j] = start[j] + ((rand() % 6 ) - 3 );
			break;
		case 2:	// blood
			p->type = pt_grav;
			p->color = Com_RandomLong( 67, 71 );
			for( j = 0; j < 3; j++ )
				p->org[j] = start[j] + ((rand() % 6 ) - 3 );
			break;
		case 3:
		case 5:	// tracer
			p->die += 0.5f;
			p->type = pt_static;

			if( type == 3 ) p->color = 52 + (( tracercount & 4 )<<1 );
			else p->color = 230 + (( tracercount & 4 )<<1 );

			tracercount++;
			VectorCopy( start, p->org );

			if( tracercount & 1 )
			{
				p->vel[0] = 30 *  vec[1];
				p->vel[1] = 30 * -vec[0];
			}
			else
			{
				p->vel[0] = 30 * -vec[1];
				p->vel[1] = 30 *  vec[0];
			}
			break;
		case 4:	// slight blood
			p->type = pt_grav;
			p->color = Com_RandomLong( 67, 71 );
			for( j = 0; j < 3; j++ )
				p->org[j] = start[j] + Com_RandomFloat( -3.0f, 3.0f );
			len -= 3;
			break;
		case 6:	// voor trail
			p->color = Com_RandomLong( 152, 156 );
			p->type = pt_static;
			p->die += 0.3f;
			for( j = 0; j < 3; j++ )
				p->org[j] = start[j] + Com_RandomFloat( -16.0f, 16.0f );
			break;
		}
		VectorAdd( start, vec, start );
	}
}
Esempio n. 5
0
static void CL_BulletTracerDraw( particle_t *p, float frametime )
{
	vec3_t	lineDir, viewDir, cross;
	vec3_t	vecEnd, vecStart, vecDir;
	float	sDistance, eDistance, totalDist;
	float	dDistance, dTotal, fOffset;
	int	alpha = (int)(traceralpha->value * 255);
	float	width = 3.0f, life, frac, length;
	vec3_t	tmp;

	// calculate distance
	VectorCopy( p->vel, vecDir );
	totalDist = VectorNormalizeLength( vecDir );

	length = p->ramp; // ramp used as length

	// calculate fraction
	life = ( totalDist + length ) / ( max( 1.0f, tracerspeed->value ));
	frac = life - ( p->die - cl.time ) + frametime;

	// calculate our distance along our path
	sDistance = tracerspeed->value * frac;
	eDistance = sDistance - length;
	
	// clip to start
	sDistance = max( 0.0f, sDistance );
	eDistance = max( 0.0f, eDistance );

	if(( sDistance == 0.0f ) && ( eDistance == 0.0f ))
		return;

	// clip it
	if( totalDist != 0.0f )
	{
		sDistance = min( sDistance, totalDist );
		eDistance = min( eDistance, totalDist );
	}

	// get our delta to calculate the tc offset
	dDistance	= fabs( sDistance - eDistance );
	dTotal = ( length != 0.0f ) ? length : 0.01f;
	fOffset = ( dDistance / dTotal );

	// find our points along our path
	VectorMA( p->org, sDistance, vecDir, vecEnd );
	VectorMA( p->org, eDistance, vecDir, vecStart );

	// setup our info for drawing the line
	VectorSubtract( vecEnd, vecStart, lineDir );
	VectorSubtract( vecEnd, RI.vieworg, viewDir );
	
	CrossProduct( lineDir, viewDir, cross );
	VectorNormalize( cross );

	GL_SetRenderMode( kRenderTransTexture );

	GL_Bind( GL_TEXTURE0, cls.particleImage );
	pglBegin( GL_QUADS );

	pglColor4ub( clgame.palette[p->color][0], clgame.palette[p->color][1], clgame.palette[p->color][2], alpha );

	VectorMA( vecStart, -width, cross, tmp );	
	pglTexCoord2f( 1.0f, 0.0f );
	pglVertex3fv( tmp );

	VectorMA( vecStart, width, cross, tmp );
	pglTexCoord2f( 0.0f, 0.0f );
	pglVertex3fv( tmp );

	VectorMA( vecEnd, width, cross, tmp );
	pglTexCoord2f( 0.0f, fOffset );
	pglVertex3fv( tmp );

	VectorMA( vecEnd, -width, cross, tmp );
	pglTexCoord2f( 1.0f, fOffset );
	pglVertex3fv( tmp );

	pglEnd();
}
Esempio n. 6
0
float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent)
#endif
{
	float maxfrac, maxrealfrac;
	int n;
	entity_render_t *ent;
	float tracemins[3], tracemaxs[3];
	trace_t trace;
	float tempnormal[3], starttransformed[3], endtransformed[3];
#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
	vec3_t end;
	vec_t len = 0;

	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
	{
		// TRICK: make the trace 1 qu longer!
		VectorSubtract(pEnd, start, end);
		len = VectorNormalizeLength(end);
		VectorMA(pEnd, collision_endposnudge.value, end, end);
	}
	else
		VectorCopy(pEnd, end);
#endif

	memset (&trace, 0 , sizeof(trace_t));
	trace.fraction = 1;
	trace.realfraction = 1;
	VectorCopy (end, trace.endpos);

	if (hitent)
		*hitent = 0;
	if (cl.worldmodel && cl.worldmodel->TraceLine)
		cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, start, end, SUPERCONTENTS_SOLID);

	if (normal)
		VectorCopy(trace.plane.normal, normal);
	maxfrac = trace.fraction;
	maxrealfrac = trace.realfraction;

	tracemins[0] = min(start[0], end[0]);
	tracemaxs[0] = max(start[0], end[0]);
	tracemins[1] = min(start[1], end[1]);
	tracemaxs[1] = max(start[1], end[1]);
	tracemins[2] = min(start[2], end[2]);
	tracemaxs[2] = max(start[2], end[2]);

	// look for embedded bmodels
	for (n = 0;n < cl.num_entities;n++)
	{
		if (!cl.entities_active[n])
			continue;
		ent = &cl.entities[n].render;
		if (!BoxesOverlap(ent->mins, ent->maxs, tracemins, tracemaxs))
			continue;
		if (!ent->model || !ent->model->TraceLine)
			continue;
		if ((ent->flags & RENDER_EXTERIORMODEL) && !chase_active.integer)
			continue;
		// if transparent and not selectable, skip entity
		if (!(cl.entities[n].state_current.effects & EF_SELECTABLE) && (ent->alpha < 1 || (ent->effects & (EF_ADDITIVE | EF_NODEPTHTEST))))
			continue;
		if (ent == ignoreent)
			continue;
		Matrix4x4_Transform(&ent->inversematrix, start, starttransformed);
		Matrix4x4_Transform(&ent->inversematrix, end, endtransformed);
		Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID, 0, NULL);
#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
		if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
			Collision_ShortenTrace(&trace, len / (len + collision_endposnudge.value), pEnd);
#endif
		if (maxrealfrac < trace.realfraction)
			continue;

		ent->model->TraceLine(ent->model, ent->frameblend, ent->skeleton, &trace, starttransformed, endtransformed, SUPERCONTENTS_SOLID);

		if (maxrealfrac > trace.realfraction)
		{
			if (hitent)
				*hitent = n;
			maxfrac = trace.fraction;
			maxrealfrac = trace.realfraction;
			if (normal)
			{
				VectorCopy(trace.plane.normal, tempnormal);
				Matrix4x4_Transform3x3(&ent->matrix, tempnormal, normal);
			}
		}
	}
	maxfrac = bound(0, maxfrac, 1);
	maxrealfrac = bound(0, maxrealfrac, 1);
	//if (maxfrac < 0 || maxfrac > 1) Con_Printf("fraction out of bounds %f %s:%d\n", maxfrac, __FILE__, __LINE__);
	if (impact)
		VectorLerp(start, maxfrac, end, impact);
	return maxfrac;
}
Esempio n. 7
0
trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
#endif
{
	vec3_t hullmins, hullmaxs;
	int i, bodysupercontents;
	int passedictprog;
	qboolean pointtrace;
	prvm_edict_t *traceowner, *touch;
	trace_t trace;
	// bounding box of entire move area
	vec3_t clipboxmins, clipboxmaxs;
	// size of the moving object
	vec3_t clipmins, clipmaxs;
	// size when clipping against monsters
	vec3_t clipmins2, clipmaxs2;
	// start and end origin of move
	vec3_t clipstart, clipend;
	// trace results
	trace_t cliptrace;
	// matrices to transform into/out of other entity's space
	matrix4x4_t matrix, imatrix;
	// model of other entity
	dp_model_t *model;
	// list of entities to test for collisions
	int numtouchedicts;
	static prvm_edict_t *touchedicts[MAX_EDICTS];
#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
	vec3_t end;
	vec_t len = 0;

	if (VectorCompare(mins, maxs))
	{
		vec3_t shiftstart, shiftend;
		VectorAdd(start, mins, shiftstart);
		VectorAdd(pEnd, mins, shiftend);
		if (VectorCompare(start, pEnd))
			trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
		else
			trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false);
		VectorSubtract(trace.endpos, mins, trace.endpos);
		return trace;
	}

	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
	{
		// TRICK: make the trace 1 qu longer!
		VectorSubtract(pEnd, start, end);
		len = VectorNormalizeLength(end);
		VectorMA(pEnd, collision_endposnudge.value, end, end);
	}
	else
		VectorCopy(pEnd, end);
#else
	if (VectorCompare(mins, maxs))
	{
		vec3_t shiftstart, shiftend;
		VectorAdd(start, mins, shiftstart);
		VectorAdd(end, mins, shiftend);
		if (VectorCompare(start, end))
			trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
		else
			trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
		VectorSubtract(trace.endpos, mins, trace.endpos);
		return trace;
	}
#endif

	if (hitnetworkentity)
		*hitnetworkentity = 0;

	VectorCopy(start, clipstart);
	VectorCopy(end, clipend);
	VectorCopy(mins, clipmins);
	VectorCopy(maxs, clipmaxs);
	VectorCopy(mins, clipmins2);
	VectorCopy(maxs, clipmaxs2);
#if COLLISIONPARANOID >= 3
	Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
#endif

	// clip to world
	Collision_ClipToWorld(&cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
	cliptrace.bmodelstartsolid = cliptrace.startsolid;
	if (cliptrace.startsolid || cliptrace.fraction < 1)
		cliptrace.ent = prog ? prog->edicts : NULL;
	if (type == MOVE_WORLDONLY)
		goto finished;

	if (type == MOVE_MISSILE)
	{
		// LordHavoc: modified this, was = -15, now -= 15
		for (i = 0;i < 3;i++)
		{
			clipmins2[i] -= 15;
			clipmaxs2[i] += 15;
		}
	}

	// get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
	if (cl.worldmodel && cl.worldmodel->brush.RoundUpToHullSize)
		cl.worldmodel->brush.RoundUpToHullSize(cl.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs);
	else
	{
		VectorCopy(clipmins, hullmins);
		VectorCopy(clipmaxs, hullmaxs);
	}

	// create the bounding box of the entire move
	for (i = 0;i < 3;i++)
	{
		clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
		clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
	}

	// debug override to test against everything
	if (sv_debugmove.integer)
	{
		clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
		clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
	}

	// if the passedict is world, make it NULL (to avoid two checks each time)
	// this checks prog because this function is often called without a CSQC
	// VM context
	if (prog == NULL || passedict == prog->edicts)
		passedict = NULL;
	// precalculate prog value for passedict for comparisons
	passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0;
	// figure out whether this is a point trace for comparisons
	pointtrace = VectorCompare(clipmins, clipmaxs);
	// precalculate passedict's owner edict pointer for comparisons
	traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->fields.client->owner) : NULL;

	// collide against network entities
	if (hitnetworkbrushmodels)
	{
		for (i = 0;i < cl.num_brushmodel_entities;i++)
		{
			entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
			if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
				continue;
			Collision_ClipToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask);
			if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
				*hitnetworkentity = cl.brushmodel_entities[i];
			Collision_CombineTraces(&cliptrace, &trace, NULL, true);
		}
	}

	// collide against player entities
	if (hitnetworkplayers)
	{
		vec3_t origin, entmins, entmaxs;
		matrix4x4_t entmatrix, entinversematrix;

		if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
		{
			// don't hit network players, if we are a nonsolid player
			if(cl.scores[cl.playerentity-1].frags == -666 || cl.scores[cl.playerentity-1].frags == -616)
				goto skipnetworkplayers;
		}

		for (i = 1;i <= cl.maxclients;i++)
		{
			entity_render_t *ent = &cl.entities[i].render;

			// don't hit ourselves
			if (i == cl.playerentity)
				continue;

			// don't hit players that don't exist
			if (!cl.scores[i-1].name[0])
				continue;

			if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
			{
				// don't hit spectators or nonsolid players
				if(cl.scores[i-1].frags == -666 || cl.scores[i-1].frags == -616)
					continue;
			}

			Matrix4x4_OriginFromMatrix(&ent->matrix, origin);
			VectorAdd(origin, cl.playerstandmins, entmins);
			VectorAdd(origin, cl.playerstandmaxs, entmaxs);
			if (!BoxesOverlap(clipboxmins, clipboxmaxs, entmins, entmaxs))
				continue;
			Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]);
			Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]);
			Collision_ClipToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, mins, maxs, end, hitsupercontentsmask);
			if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
				*hitnetworkentity = i;
			Collision_CombineTraces(&cliptrace, &trace, NULL, false);
		}

skipnetworkplayers:
		;
	}

	// clip to entities
	// because this uses World_EntitiestoBox, we know all entity boxes overlap
	// the clip region, so we can skip culling checks in the loop below
	// note: if prog is NULL then there won't be any linked entities
	numtouchedicts = 0;
	if (hitcsqcentities && prog != NULL)
	{
		numtouchedicts = World_EntitiesInBox(&cl.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
		if (numtouchedicts > MAX_EDICTS)
		{
			// this never happens
			Con_Printf("CL_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
			numtouchedicts = MAX_EDICTS;
		}
	}
	for (i = 0;i < numtouchedicts;i++)
	{
		touch = touchedicts[i];

		if (touch->fields.client->solid < SOLID_BBOX)
			continue;
		if (type == MOVE_NOMONSTERS && touch->fields.client->solid != SOLID_BSP)
			continue;

		if (passedict)
		{
			// don't clip against self
			if (passedict == touch)
				continue;
			// don't clip owned entities against owner
			if (traceowner == touch)
				continue;
			// don't clip owner against owned entities
			if (passedictprog == touch->fields.client->owner)
				continue;
			// don't clip points against points (they can't collide)
			if (pointtrace && VectorCompare(touch->fields.client->mins, touch->fields.client->maxs) && (type != MOVE_MISSILE || !((int)touch->fields.client->flags & FL_MONSTER)))
				continue;
		}

		bodysupercontents = touch->fields.client->solid == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;

		// might interact, so do an exact clip
		model = NULL;
		if ((int) touch->fields.client->solid == SOLID_BSP || type == MOVE_HITMODEL)
			model = CL_GetModelFromEdict(touch);
		if (model)
			Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2], touch->fields.client->angles[0], touch->fields.client->angles[1], touch->fields.client->angles[2], 1);
		else
			Matrix4x4_CreateTranslate(&matrix, touch->fields.client->origin[0], touch->fields.client->origin[1], touch->fields.client->origin[2]);
		Matrix4x4_Invert_Simple(&imatrix, &matrix);
		if ((int)touch->fields.client->flags & FL_MONSTER)
			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
		else
			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touch->fields.client->mins, touch->fields.client->maxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);

		if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
			*hitnetworkentity = 0;
		Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.client->solid == SOLID_BSP);
	}

finished:
#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
		Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
#endif
	return cliptrace;
}
Esempio n. 8
0
/*
=================
AddBrushBevels

adds any additional planes necessary to allow the brush being
built to be expanded against axial bounding boxes
2003-01-20: added mr.Elusive fixes
=================
*/
void AddBrushBevels( void )
{
	int		axis, dir;
	int		i, j, k, l, order = 0;
	side_t		sidetemp;
	side_t		*s, *s2;
	winding_t		*w, *w2;
	vec3_t		normal;
	float		dist;
	vec3_t		vec, vec2;
	float		d, minBack;

	// add the axial planes
	for( axis = 0; axis < 3; axis++ )
	{
		for( dir = -1; dir <= 1; dir += 2, order++ )
		{
			// see if the plane is allready present
			for( i = 0, s = buildBrush->sides; i < buildBrush->numsides; i++, s++ )
			{
				if( mapplanes[s->planenum].normal[axis] == dir )
					break;
			}

			if( i == buildBrush->numsides )
			{
				// add a new side
				if( buildBrush->numsides == MAX_BUILD_SIDES )
					Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum );

				Mem_Set( s, 0, sizeof( *s ));
				buildBrush->numsides++;
				VectorClear (normal);
				normal[axis] = dir;

				if( dir == 1 )
				{
					// adding bevel plane snapping for fewer bsp planes
					if( bevelSnap > 0 )
						dist = floor( buildBrush->maxs[axis] / bevelSnap ) * bevelSnap;
					else
						dist = buildBrush->maxs[axis];
				}
				else
				{
					// adding bevel plane snapping for fewer bsp planes
					if( bevelSnap > 0 )
						dist = -ceil( buildBrush->mins[axis] / bevelSnap ) * bevelSnap;
					else
						dist = -buildBrush->mins[axis];
				}

				s->planenum = FindFloatPlane( normal, dist, 0, NULL );
				s->contentFlags = buildBrush->sides[0].contentFlags;
				s->bevel = true;
				c_boxbevels++;
			}

			// if the plane is not in it canonical order, swap it
			if( i != order )
			{
				sidetemp = buildBrush->sides[order];
				buildBrush->sides[order] = buildBrush->sides[i];
				buildBrush->sides[i] = sidetemp;
			}
		}
	}

	// add the edge bevels
	if( buildBrush->numsides == 6 )
		return; // pure axial

	// test the non-axial plane edges
	for( i = 6; i < buildBrush->numsides; i++ )
	{
		s = buildBrush->sides + i;
		w = s->winding;
		if( !w ) continue;

		for( j = 0; j < w->numpoints; j++ )
		{
			k = (j+1)%w->numpoints;
			VectorSubtract( w->p[j], w->p[k], vec );

			if( VectorNormalizeLength( vec ) < 0.5f )
				continue;
			SnapNormal( vec );
			for( k = 0; k < 3; k++ )
			{
				if( vec[k] == -1.0f || vec[k] == 1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f))
					break;	// axial
			}
			if( k != 3 ) continue; // only test non-axial edges

			// try the six possible slanted axials from this edge
			for( axis = 0; axis < 3; axis++ )
			{
				for( dir = -1; dir <= 1; dir += 2 )
				{
					// construct a plane
					VectorClear( vec2 );
					vec2[axis] = dir;
					CrossProduct( vec, vec2, normal );
					if( VectorNormalizeLength( normal ) < 0.5f )
						continue;
					dist = DotProduct( w->p[j], normal );
					
					// if all the points on all the sides are
					// behind this plane, it is a proper edge bevel
					for( k = 0; k < buildBrush->numsides; k++ )
					{
						// if this plane has allready been used, skip it
						if( PlaneEqual( &mapplanes[buildBrush->sides[k].planenum], normal, dist ))
							break;

						w2 = buildBrush->sides[k].winding;
						if( !w2 ) continue;

						minBack = 0.0f;
						for( l = 0; l < w2->numpoints; l++ )
						{
							d = DotProduct( w2->p[l], normal ) - dist;
							if( d > 0.1f ) break; // point in front
							if( d < minBack ) minBack = d;
						}
						// if some point was at the front
						if( l != w2->numpoints )
							break;

						// if no points at the back then the winding is on the bevel plane
						if( minBack > -0.1f )
							break;
					}

					if( k != buildBrush->numsides )
						continue;	// wasn't part of the outer hull
					
					// add this plane
					if( buildBrush->numsides == MAX_BUILD_SIDES )
						Sys_Break( "Entity %i, Brush %i MAX_BUILD_SIDES\n", buildBrush->entityNum, buildBrush->brushNum );

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

					s2->planenum = FindFloatPlane( normal, dist, 1, &w->p[j] );
					s2->contentFlags = buildBrush->sides[0].contentFlags;
					s2->bevel = true;
					c_edgebevels++;
				}
			}
		}
	}
}
Esempio n. 9
0
/*
==================
CM_AddFacetBevels
==================
*/
static void CM_AddFacetBevels( cfacet_t *facet )
{

	int		i, j, k, l;
	int		axis, dir, order, flipped;
	float		plane[4], d, newplane[4];
	vec3_t		mins, maxs, vec, vec2;
	cwinding_t	*w, *w2;

	Vector4Copy( planes[facet->surfacePlane].plane, plane );

	w = CM_BaseWindingForPlane( plane, plane[3] );

	for( j = 0; j < facet->numBorders && w; j++ )
	{
		if( facet->borderPlanes[j] == facet->surfacePlane )
			continue;
		Vector4Copy( planes[facet->borderPlanes[j]].plane, plane );

		if( !facet->borderInward[j] )
		{
			VectorNegate( plane, plane );
			plane[3] = -plane[3];
		}
		CM_ChopWindingInPlace( &w, plane, plane[3], ON_EPSILON );
	}

	if( !w ) return;

	CM_WindingBounds( w, mins, maxs );

	//
	// add the axial planes
	//
	order = 0;
	for( axis = 0; axis < 3; axis++ )
	{
		for( dir = -1; dir <= 1; dir += 2, order++ )
		{
			VectorClear( plane );
			plane[axis] = dir;

			if( dir == 1 ) plane[3] = maxs[axis];
			else plane[3] = -mins[axis];

			// if it's the surface plane
			if( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ))
				continue;

			// see if the plane is allready present
			for( i = 0; i < facet->numBorders; i++ )
			{
				if( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ))
					break;
			}

			if( i == facet->numBorders )
			{
				if( facet->numBorders > MAX_FACET_BEVELS )
					MsgDev( D_ERROR, "CM_AddFacetBevels: too many bevels\n" );

				facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
				facet->borderNoAdjust[facet->numBorders] = 0;
				facet->borderInward[facet->numBorders] = flipped;
				facet->numBorders++;
			}
		}
	}

	//
	// add the edge bevels
	//

	// test the non-axial plane edges
	for( j = 0; j < w->numpoints; j++ )
	{
		k = (j + 1) % w->numpoints;
		VectorSubtract( w->p[j], w->p[k], vec );

		// if it's a degenerate edge
		if( VectorNormalizeLength( vec ) < 0.5f )
			continue;

		CM_SnapVector( vec );
		for( k = 0; k < 3; k++ )
		{
			if( vec[k] == -1 || vec[k] == 1 )
				break; // axial
		}

		if( k < 3 ) continue; // only test non-axial edges

		// try the six possible slanted axials from this edge
		for( axis = 0; axis < 3; axis++ )
		{
			for( dir = -1; dir <= 1; dir += 2 )
			{
				// construct a plane
				VectorClear( vec2 );
				vec2[axis] = dir;
				CrossProduct( vec, vec2, plane );
				if( VectorNormalizeLength( plane ) < 0.5f )
					continue;
				plane[3] = DotProduct( w->p[j], plane );

				// if all the points of the facet winding are
				// behind this plane, it is a proper edge bevel
				for( l = 0; l < w->numpoints; l++ )
				{
					d = DotProduct( w->p[l], plane ) - plane[3];
					if( d > ON_EPSILON ) break; // point in front
				}

				if( l < w->numpoints ) continue;

				// if it's the surface plane
				if( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ))
					continue;

				// see if the plane is allready present
				for( i = 0; i < facet->numBorders; i++ )
				{
					if( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ))
						break;
				}

				if( i == facet->numBorders )
				{
					if( facet->numBorders > MAX_FACET_BEVELS )
						MsgDev( D_ERROR, "CM_AddFacetBevels: too many bevels\n" );
					facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped );

					for( k = 0; k < facet->numBorders; k++ )
					{
						if( facet->borderPlanes[facet->numBorders] == facet->borderPlanes[k] )
							MsgDev( D_WARN, "CM_AddFacetBevels: bevel plane already used\n" );
					}

					facet->borderNoAdjust[facet->numBorders] = 0;
					facet->borderInward[facet->numBorders] = flipped;

					w2 = CM_CopyWinding( w );
					Vector4Copy( planes[facet->borderPlanes[facet->numBorders]].plane, newplane );

					if( !facet->borderInward[facet->numBorders] )
					{
						VectorNegate( newplane, newplane );
						newplane[3] = -newplane[3];
					}

					CM_ChopWindingInPlace( &w2, newplane, newplane[3], ON_EPSILON );

					if( !w2 )
					{
						cm.numInvalidBevels++;
						continue;
					}
					else CM_FreeWinding( w2 );

					facet->numBorders++;
					// already got a bevel
				}
			}
		}
	}
	CM_FreeWinding( w );

	// add opposite plane
	facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
	facet->borderNoAdjust[facet->numBorders] = 0;
	facet->borderInward[facet->numBorders] = true;
	facet->numBorders++;
}