Example #1
0
/*
 * @brief Updates the clipping planes for the view frustum based on the origin
 * and angles for this frame.
 */
void R_UpdateFrustum(void) {
	int32_t i;

	if (!r_cull->value)
		return;

	cm_bsp_plane_t *p = r_locals.frustum;

	const vec_t fov_x = r_view.fov[0];
	const vec_t fov_y = r_view.fov[1];

	// rotate r_view.forward right by fov_x degrees
	RotatePointAroundVector(r_view.forward, r_view.right, -(90.0 - fov_x), (p++)->normal);
	// rotate r_view.forward left by fov_x degrees
	RotatePointAroundVector(r_view.forward, r_view.right, 90.0 - fov_x, (p++)->normal);
	// rotate r_view.forward up by fov_y degrees
	RotatePointAroundVector(r_view.forward, r_view.up, 90.0 - fov_y, (p++)->normal);
	// rotate r_view.forward down by fov_y degrees
	RotatePointAroundVector(r_view.forward, r_view.up, -(90.0 - fov_y), p->normal);

	for (i = 0; i < 4; i++) {
		r_locals.frustum[i].type = PLANE_ANY_Z;
		r_locals.frustum[i].dist = DotProduct(r_view.origin, r_locals.frustum[i].normal);
		r_locals.frustum[i].sign_bits = Cm_SignBitsForPlane(&r_locals.frustum[i]);
	}
}
Example #2
0
/*
 * @brief Updates the clipping planes for the view frustum based on the origin
 * and angles for this frame.
 */
void R_UpdateFrustum(void) {
	int32_t i;

	if (!r_cull->value)
		return;

	// rotate r_view.forward right by fov_x / 2 degrees
	RotatePointAroundVector(r_locals.frustum[0].normal, r_view.up, r_view.forward,
			-(90 - r_view.fov[0] / 2));
	// rotate r_view.forward left by fov_x / 2 degrees
	RotatePointAroundVector(r_locals.frustum[1].normal, r_view.up, r_view.forward,
			90 - r_view.fov[0] / 2);
	// rotate r_view.forward up by fov_x / 2 degrees
	RotatePointAroundVector(r_locals.frustum[2].normal, r_view.right, r_view.forward,
			90 - r_view.fov[1] / 2);
	// rotate r_view.forward down by fov_x / 2 degrees
	RotatePointAroundVector(r_locals.frustum[3].normal, r_view.right, r_view.forward,
			-(90 - r_view.fov[1] / 2));

	for (i = 0; i < 4; i++) {
		r_locals.frustum[i].type = PLANE_ANYZ;
		r_locals.frustum[i].dist = DotProduct(r_view.origin, r_locals.frustum[i].normal);
		r_locals.frustum[i].sign_bits = SignBitsForPlane(&r_locals.frustum[i]);
	}
}
Example #3
0
void R_SetFrustum (void)
{
	int		i;

	if (r_refdef.fov_x == 90) 
	{
		// front side is visible

		VectorAdd (vpn, vright, frustum[0].normal);
		VectorSubtract (vpn, vright, frustum[1].normal);

		VectorAdd (vpn, vup, frustum[2].normal);
		VectorSubtract (vpn, vup, frustum[3].normal);
	}
	else
	{
		// rotate VPN right by FOV_X/2 degrees
		RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
		// rotate VPN left by FOV_X/2 degrees
		RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
		// rotate VPN up by FOV_X/2 degrees
		RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
		// rotate VPN down by FOV_X/2 degrees
		RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
	}

	for (i=0 ; i<4 ; i++)
	{
		frustum[i].type = PLANE_ANYZ;
		frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
	}
}
Example #4
0
/*
* R_SetupFrustum
*/
void R_SetupFrustum( const refdef_t *rd, float farClip, cplane_t *frustum )
{
	int i;
	vec3_t forward, left, up;

	// 0 - left
	// 1 - right
	// 2 - down
	// 3 - up
	// 4 - farclip

	VectorCopy( &rd->viewaxis[AXIS_FORWARD], forward );
	VectorCopy( &rd->viewaxis[AXIS_RIGHT], left );
	VectorCopy( &rd->viewaxis[AXIS_UP], up );

	if( rd->rdflags & RDF_USEORTHO ) {
		VectorNegate( left, frustum[0].normal );
		VectorCopy( left, frustum[1].normal );
		VectorNegate( up, frustum[2].normal );
		VectorCopy( up, frustum[3].normal );

		for( i = 0; i < 4; i++ ) {
			frustum[i].type = PLANE_NONAXIAL;
			frustum[i].dist = DotProduct( rd->vieworg, frustum[i].normal );
			frustum[i].signbits = SignbitsForPlane( &frustum[i] );
		}

		frustum[0].dist -= rd->ortho_x;
		frustum[1].dist -= rd->ortho_x;
		frustum[2].dist -= rd->ortho_y;
		frustum[3].dist -= rd->ortho_y;
	}
	else {
		vec3_t right;

		VectorNegate( left, right );
		// rotate rn.vpn right by FOV_X/2 degrees
		RotatePointAroundVector( frustum[0].normal, up, forward, -( 90-rd->fov_x / 2 ) );
		// rotate rn.vpn left by FOV_X/2 degrees
		RotatePointAroundVector( frustum[1].normal, up, forward, 90-rd->fov_x / 2 );
		// rotate rn.vpn up by FOV_X/2 degrees
		RotatePointAroundVector( frustum[2].normal, right, forward, 90-rd->fov_y / 2 );
		// rotate rn.vpn down by FOV_X/2 degrees
		RotatePointAroundVector( frustum[3].normal, right, forward, -( 90 - rd->fov_y / 2 ) );

		for( i = 0; i < 4; i++ ) {
			frustum[i].type = PLANE_NONAXIAL;
			frustum[i].dist = DotProduct( rd->vieworg, frustum[i].normal );
			frustum[i].signbits = SignbitsForPlane( &frustum[i] );
		}
	}

	// farclip
	VectorNegate( forward, frustum[4].normal );
	frustum[4].type = PLANE_NONAXIAL;
	frustum[4].dist = DotProduct( rd->vieworg, frustum[4].normal ) - farClip;
	frustum[4].signbits = SignbitsForPlane( &frustum[4] );
}
Example #5
0
void R_SetupFrustum (void)
{
	int i;

	/* build the transformation matrix for the given view angles */
	AngleVectors(refdef.viewAngles, r_locals.forward, r_locals.right, r_locals.up);

#if 0
	/* if we are not drawing world model, we are on the UI code. It break the default UI SCISSOR
	 * Anyway we should merge that code into R_CleanupDepthBuffer (with some rework), it looks better */

	/* clear out the portion of the screen that the NOWORLDMODEL defines */
	if (refdef.rendererFlags & RDF_NOWORLDMODEL) {
		glEnable(GL_SCISSOR_TEST);
		glScissor(viddef.x, viddef.height - viddef.viewHeight - viddef.y, viddef.viewWidth, viddef.viewHeight);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		R_CheckError();
		glDisable(GL_SCISSOR_TEST);
	}
#endif
	if (r_isometric->integer) {
		/* 4 planes of a cube */
		VectorScale(r_locals.right, +1, r_locals.frustum[0].normal);
		VectorScale(r_locals.right, -1, r_locals.frustum[1].normal);
		VectorScale(r_locals.up, +1, r_locals.frustum[2].normal);
		VectorScale(r_locals.up, -1, r_locals.frustum[3].normal);

		for (i = 0; i < 4; i++) {
			r_locals.frustum[i].type = PLANE_ANYZ;
			r_locals.frustum[i].dist = DotProduct(refdef.viewOrigin, r_locals.frustum[i].normal);
		}
		r_locals.frustum[0].dist -= 10 * refdef.fieldOfViewX;
		r_locals.frustum[1].dist -= 10 * refdef.fieldOfViewX;
		r_locals.frustum[2].dist -= 10 * refdef.fieldOfViewX * ((float) viddef.viewHeight / viddef.viewWidth);
		r_locals.frustum[3].dist -= 10 * refdef.fieldOfViewX * ((float) viddef.viewHeight / viddef.viewWidth);
	} else {
		/* rotate VPN right by FOV_X/2 degrees */
		RotatePointAroundVector(r_locals.frustum[0].normal, r_locals.up, r_locals.forward, -(90 - refdef.fieldOfViewX / 2));
		/* rotate VPN left by FOV_X/2 degrees */
		RotatePointAroundVector(r_locals.frustum[1].normal, r_locals.up, r_locals.forward, 90 - refdef.fieldOfViewX / 2);
		/* rotate VPN up by FOV_X/2 degrees */
		RotatePointAroundVector(r_locals.frustum[2].normal, r_locals.right, r_locals.forward, 90 - refdef.fieldOfViewY / 2);
		/* rotate VPN down by FOV_X/2 degrees */
		RotatePointAroundVector(r_locals.frustum[3].normal, r_locals.right, r_locals.forward, -(90 - refdef.fieldOfViewY / 2));

		for (i = 0; i < 4; i++) {
			r_locals.frustum[i].type = PLANE_ANYZ;
			r_locals.frustum[i].dist = DotProduct(refdef.viewOrigin, r_locals.frustum[i].normal);
		}
	}
}
Example #6
0
/**
 * @brief rotate a planet (sun or moon) with respect to the earth
 */
static inline void R_RotateCelestialBody (const vec4_t v, vec4_t r, const vec3_t rotate, const vec3_t earthPos, const float celestialDist)
{
	vec4_t v1;
	vec3_t v2;
	vec3_t rotationAxis;

	VectorSet(v2, v[1], v[0], v[2]);
	VectorSet(rotationAxis, 0, 0, 1);
	RotatePointAroundVector(v1, rotationAxis, v2, -rotate[PITCH]);
	VectorSet(rotationAxis, 0, 1, 0);
	RotatePointAroundVector(v2, rotationAxis, v1, -rotate[YAW]);

	Vector4Set(r, earthPos[0] + celestialDist * v2[1], earthPos[1] + celestialDist * v2[0], -celestialDist * v2[2], 0);
}
Example #7
0
/*
===============
CG_smoothWJTransitions
===============
*/
static void CG_smoothWJTransitions( playerState_t *ps, const vec3_t in, vec3_t out )
{
	int      i;
	float    stLocal, sFraction;
	qboolean performed = qfalse;
	vec3_t   inAxis[ 3 ], outAxis[ 3 ];

	Q_UNUSED(ps);

	if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
	{
		VectorCopy( in, out );
		return;
	}

	AnglesToAxis( in, inAxis );

	//iterate through ops
	for ( i = MAXSMOOTHS - 1; i >= 0; i-- )
	{
		//if this op has time remaining, perform it
		if ( cg.time < cg.sList[ i ].time + cg_wwSmoothTime.integer )
		{
			stLocal = ( ( cg.sList[ i ].time + cg_wwSmoothTime.integer ) - cg.time ) / cg_wwSmoothTime.integer;
			sFraction = 1.0f - ( ( cos( stLocal * M_PI * 2.0f ) + 1.0f ) / 2.0f );

			RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis,
			                         inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle );
			RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis,
			                         inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle );
			RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis,
			                         inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle );

			AxisCopy( outAxis, inAxis );
			performed = qtrue;
		}
	}

	//if we performed any ops then return the smoothed angles
	//otherwise simply return the in angles
	if ( performed )
	{
		AxisToAngles( outAxis, out );
	}
	else
	{
		VectorCopy( in, out );
	}
}
Example #8
0
/*
** RB_SurfaceLightningBolt
*/
static void RB_SurfaceLightningBolt( void ) {
	refEntity_t *e;
	int			len;
	vec3_t		right;
	vec3_t		vec;
	vec3_t		start, end;
	vec3_t		v1, v2;
	int			i;

	e = &backEnd.currentEntity->e;

	VectorCopy( e->oldorigin, end );
	VectorCopy( e->origin, start );

	// compute variables
	VectorSubtract( end, start, vec );
	len = VectorNormalize( vec );

	// compute side vector
	VectorSubtract( start, backEnd.viewParms.or.origin, v1 );
	VectorNormalize( v1 );
	VectorSubtract( end, backEnd.viewParms.or.origin, v2 );
	VectorNormalize( v2 );
	CrossProduct( v1, v2, right );
	VectorNormalize( right );

	for ( i = 0 ; i < 4 ; i++ ) {
		vec3_t	temp;

		DoRailCore( start, end, right, len, 8 );
		RotatePointAroundVector( temp, vec, right, 45 );
		VectorCopy( temp, right );
	}
}
Example #9
0
static bool BOT_DMclass_FindRocket( edict_t *self, vec3_t away_from_rocket )
{
#define AI_ROCKET_DETECT_RADIUS 1000
#define AI_ROCKET_DANGER_RADIUS 200
	int i, numtargets;
	int targets[MAX_EDICTS];
	edict_t *target;
	float min_roxx_time = 1.0f;
	bool any_rocket = false;

	numtargets = GClip_FindRadius( self->s.origin, AI_ROCKET_DETECT_RADIUS, targets, MAX_EDICTS );
	for( i = 0; i < numtargets; i++ )
	{
		target = game.edicts + targets[i];

		// Missile detection code
		if( target->r.svflags & SVF_PROJECTILE && target->s.type != ET_PLASMA ) // (plasmas come in bunchs so are too complex for the bot to dodge)
		{
			if( target->r.owner && target->r.owner != self )
			{
				vec3_t end;
				trace_t trace;

				VectorMA( target->s.origin, 2, target->velocity, end );
				G_Trace( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_SOLID );
				if( trace.fraction < min_roxx_time )
				{
					vec_t l;

					any_rocket = true;
					min_roxx_time = trace.fraction;
					VectorSubtract( trace.endpos, self->s.origin, end );
					// ok... end is where the impact will be.
					// trace.fraction is the time.

					if( ( l = VectorLengthFast( end ) ) < AI_ROCKET_DANGER_RADIUS )
					{
						RotatePointAroundVector( away_from_rocket, &axis_identity[AXIS_UP], end, -self->s.angles[YAW] );
						VectorNormalize( away_from_rocket );

						if( fabs( away_from_rocket[0] ) < 0.3 ) away_from_rocket[0] = 0;
						if( fabs( away_from_rocket[1] ) < 0.3 ) away_from_rocket[1] = 0;
						away_from_rocket[2] = 0;
						away_from_rocket[0] *= -1.0f;
						away_from_rocket[1] *= -1.0f;

						if( nav.debugMode && bot_showcombat->integer > 2 )
							G_PrintChasersf( self, "%s: ^1projectile dodge: ^2%f, %f d=%f^7\n", self->ai->pers.netname, away_from_rocket[0], away_from_rocket[1], l );
					}
				}
			}
		}
	}

	return any_rocket;

#undef AI_ROCKET_DETECT_RADIUS
#undef AI_ROCKET_DANGER_RADIUS
}
Example #10
0
void CG_ImpactMark(qhandle_t markShader, vec3_t origin, vec4_t projection, float radius, float orientation, float r, float g, float b, float a, int lifeTime)
{
	int    i;
	vec3_t pushedOrigin, axis[3];
	vec4_t color;
	int    fadeTime;
	vec3_t points[4];

	// early out
	if (lifeTime == 0)
	{
		return;
	}

	// set projection (inverse of dir)
	//VectorSubtract( vec3_origin, dir, projection );
	//VectorNormalize( projection );
	//projection[ 3 ] = radius * 8;

	// make rotated polygon axis
	VectorCopy(projection, axis[0]);
	PerpendicularVector(axis[1], axis[0]);
	RotatePointAroundVector(axis[2], axis[0], axis[1], -orientation);
	CrossProduct(axis[0], axis[2], axis[1]);

	// push the origin out a bit
	VectorMA(origin, -1.0f, axis[0], pushedOrigin);

	// create the full polygon
	for (i = 0; i < 3; i++)
	{
		// new
		points[0][i] = pushedOrigin[i] - radius * axis[1][i] - radius * axis[2][i];
		points[1][i] = pushedOrigin[i] - radius * axis[1][i] + radius * axis[2][i];
		points[2][i] = pushedOrigin[i] + radius * axis[1][i] + radius * axis[2][i];
		points[3][i] = pushedOrigin[i] + radius * axis[1][i] - radius * axis[2][i];
	}

	// debug code
	#if 0
	VectorSet(points[0], origin[0] - radius, origin[1] - radius, origin[2]);
	VectorSet(points[1], origin[0] - radius, origin[1] + radius, origin[2]);
	VectorSet(points[2], origin[0] + radius, origin[1] + radius, origin[2]);
	VectorSet(points[3], origin[0] + radius, origin[1] - radius, origin[2]);
	CG_Printf("Dir: %f %f %f\n", dir[0], dir[1], dir[2]);
	#endif

	// set color
	color[0] = r;
	color[1] = g;
	color[2] = b;
	color[3] = a;

	// set decal times (in seconds)
	fadeTime = lifeTime >> 4;

	// add the decal
	trap_R_ProjectDecal(markShader, 4, points, projection, color, lifeTime, fadeTime);
}
Example #11
0
/**
 * @brief Get the next point in the object path based on movement converting the positions from
 * polar coordinates to vector for the calculation and back again to be returned.
 * @param[in] movement The distance that the object needs to move.
 * @param[in] originalPoint The point from which the object is moving.
 * @param[in] orthogonalVector The orthogonal vector.
 * @param[out] finalPoint The next point from the original point + movement in "angle" direction.
 */
static void AIRFIGHT_GetNextPointInPathFromVector (const float *movement, const vec2_t originalPoint, const vec3_t orthogonalVector, vec2_t finalPoint)
{
	vec3_t startPoint, finalVectorPoint;

	PolarToVec(originalPoint, startPoint);
	RotatePointAroundVector(finalVectorPoint, orthogonalVector, startPoint, *movement);
	VecToPolar(finalVectorPoint, finalPoint);
}
Example #12
0
/**
 * @brief Return longitude and latitude of a point of the screen for 3D geoscape (globe)
 * @param[in] node The current menuNode we have clicked on (3dmap or map)
 * @param[in] x,y Coordinates on the screen that were clicked on
 * @param[out] pos vec2_t was filled with longitude and latitude
 * @sa MAP_3DMapToScreen
 */
void uiGeoscapeNode::screenTo3DMap (const uiNode_t* node, int x, int y, vec2_t pos)
{
    vec2_t mid;
    vec3_t v, v1, rotationAxis;
    float dist;
    const float radius = GLOBE_RADIUS;

    /* set mid to the coordinates of the center of the globe */
    Vector2Set(mid, UI_MAPEXTRADATACONST(node).mapPos[0] + UI_MAPEXTRADATACONST(node).mapSize[0] / 2.0f,
               UI_MAPEXTRADATACONST(node).mapPos[1] + UI_MAPEXTRADATACONST(node).mapSize[1] / 2.0f);

    /* stop if we click outside the globe (distance is the distance of the point to the center of the globe) */
    dist = sqrt((x - mid[0]) * (x - mid[0]) + (y - mid[1]) * (y - mid[1]));
    if (dist > radius) {
        Vector2Set(pos, -1.0, -1.0);
        return;
    }

    /* calculate the coordinates in the local frame
     * this frame is the frame of the screen.
     * v[0] is the vertical axis of the screen
     * v[1] is the horizontal axis of the screen
     * v[2] is the axis perpendicular to the screen - we get its value knowing that norm of v is egal to radius
     *  (because the point is on the globe) */
    v[0] = - (y - mid[1]);
    v[1] = - (x - mid[0]);
    v[2] = - sqrt(radius * radius - (x - mid[0]) * (x - mid[0]) - (y - mid[1]) * (y - mid[1]));
    VectorNormalize(v);

    /* rotate the vector to switch of reference frame
     * note the ccs.angles[ROLL] is always 0, so there is only 2 rotations and not 3
     * and that GLOBE_ROTATE is already included in ccs.angles[YAW]
     * first rotation is along the horizontal axis of the screen, to put north-south axis of the earth
     * perpendicular to the screen */
    VectorSet(rotationAxis, 0, 1, 0);
    RotatePointAroundVector(v1, rotationAxis, v, UI_MAPEXTRADATACONST(node).angles[YAW]);

    /* second rotation is to rotate the earth around its north-south axis
     * so that Greenwich meridian is along the vertical axis of the screen */
    VectorSet(rotationAxis, 0, 0, 1);
    RotatePointAroundVector(v, rotationAxis, v1, UI_MAPEXTRADATACONST(node).angles[PITCH]);

    /* we therefore got in v the coordinates of the point in the static frame of the earth
     * that we can convert in polar coordinates to get its latitude and longitude */
    VecToPolar(v, pos);
}
Example #13
0
/*
=============
CG_DrawDir

Draw dot marking the direction to an enemy
=============
*/
static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
	vec3_t        drawOrigin;
	vec3_t        noZOrigin;
	vec3_t        normal, antinormal, normalDiff;
	vec3_t        view, noZview;
	vec3_t        up = { 0.0f, 0.0f,   1.0f };
	vec3_t        top = { 0.0f, -1.0f,  0.0f };
	float         angle;
	playerState_t *ps = &cg.snap->ps;

	if ( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
	{
		if ( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
		{
			VectorSet( normal, 0.0f, 0.0f, -1.0f );
		}
		else
		{
			VectorCopy( ps->grapplePoint, normal );
		}
	}
	else
	{
		VectorSet( normal, 0.0f, 0.0f, 1.0f );
	}

	AngleVectors( entityPositions.vangles, view, NULL, NULL );

	ProjectPointOnPlane( noZOrigin, origin, normal );
	ProjectPointOnPlane( noZview, view, normal );
	VectorNormalize( noZOrigin );
	VectorNormalize( noZview );

	//calculate the angle between the images of the blip and the view
	angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) );
	CrossProduct( noZOrigin, noZview, antinormal );
	VectorNormalize( antinormal );

	//decide which way to rotate
	VectorSubtract( normal, antinormal, normalDiff );

	if ( VectorLength( normalDiff ) < 1.0f )
	{
		angle = 360.0f - angle;
	}

	RotatePointAroundVector( drawOrigin, up, top, angle );

	trap_R_SetColor( colour );
	CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ),
	            rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ),
	            BLIPX2, BLIPY2, cgs.media.scannerBlipShader );
	trap_R_SetColor( NULL );
}
Example #14
0
/*
===============
R_SetupFrustum
===============
*/
void R_SetupFrustum( void )
{
	vec3_t	farPoint;
	int	i;

	// 0 - left
	// 1 - right
	// 2 - down
	// 3 - up
	// 4 - farclip
	// 5 - nearclip

	if( RI.drawOrtho )
	{
		R_SetupFrustumOrtho();
		return;
	}

	// rotate RI.vforward right by FOV_X/2 degrees
	RotatePointAroundVector( RI.frustum[0].normal, RI.cull_vup, RI.cull_vforward, -( 90 - RI.refdef.fov_x / 2 ));
	// rotate RI.vforward left by FOV_X/2 degrees
	RotatePointAroundVector( RI.frustum[1].normal, RI.cull_vup, RI.cull_vforward, 90 - RI.refdef.fov_x / 2 );
	// rotate RI.vforward up by FOV_X/2 degrees
	RotatePointAroundVector( RI.frustum[2].normal, RI.cull_vright, RI.cull_vforward, 90 - RI.refdef.fov_y / 2 );
	// rotate RI.vforward down by FOV_X/2 degrees
	RotatePointAroundVector( RI.frustum[3].normal, RI.cull_vright, RI.cull_vforward, -( 90 - RI.refdef.fov_y / 2 ));
	// negate forward vector
	VectorNegate( RI.cull_vforward, RI.frustum[4].normal );

	for( i = 0; i < 4; i++ )
	{
		RI.frustum[i].type = PLANE_NONAXIAL;
		RI.frustum[i].dist = DotProduct( RI.cullorigin, RI.frustum[i].normal );
		RI.frustum[i].signbits = SignbitsForPlane( RI.frustum[i].normal );
	}

	VectorMA( RI.cullorigin, R_GetFarClip(), RI.cull_vforward, farPoint );
	RI.frustum[i].type = PLANE_NONAXIAL;
	RI.frustum[i].dist = DotProduct( farPoint, RI.frustum[i].normal );
	RI.frustum[i].signbits = SignbitsForPlane( RI.frustum[i].normal );
}
Example #15
0
static void BestJumpingDirection (gedict_t* self)
{
	float raw_avg_angle = AverageTraceAngle (self, false, self->fb.debug_path);
	float avg_angle;

	if (raw_avg_angle < 0)
		avg_angle = min (raw_avg_angle, -15);
	else
		avg_angle = max (raw_avg_angle, 15);

	RotatePointAroundVector (self->fb.dir_move_, g_globalvars.v_up, g_globalvars.v_forward, avg_angle);
}
Example #16
0
/*
=============
CG_DrawBlips

Draw blips and stalks for the human scanner
=============
*/
static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour )
{
	vec3_t drawOrigin;
	vec3_t up = { 0, 0, 1 };
	float  alphaMod = 1.0f;
	float  timeFractionSinceRefresh = 1.0f -
	                                  ( ( float )( cg.time - entityPositions.lastUpdateTime ) /
	                                    ( float ) HUMAN_SCANNER_UPDATE_PERIOD );
	vec4_t localColour;

	Vector4Copy( colour, localColour );

	RotatePointAroundVector( drawOrigin, up, origin, -entityPositions.vangles[ 1 ] - 90 );
	drawOrigin[ 0 ] /= ( 2 * HELMET_RANGE / rect->w );
	drawOrigin[ 1 ] /= ( 2 * HELMET_RANGE / rect->h );
	drawOrigin[ 2 ] /= ( 2 * HELMET_RANGE / rect->w );

	alphaMod = FAR_ALPHA +
	           ( ( drawOrigin[ 1 ] + ( rect->h / 2.0f ) ) / rect->h ) * ( NEAR_ALPHA - FAR_ALPHA );

	localColour[ 3 ] *= alphaMod;
	localColour[ 3 ] *= ( 0.5f + ( timeFractionSinceRefresh * 0.5f ) );

	if ( localColour[ 3 ] > 1.0f )
	{
		localColour[ 3 ] = 1.0f;
	}
	else if ( localColour[ 3 ] < 0.0f )
	{
		localColour[ 3 ] = 0.0f;
	}

	trap_R_SetColor( localColour );

	if ( drawOrigin[ 2 ] > 0 )
	{
		CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
		            rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
		            STALKWIDTH, drawOrigin[ 2 ], cgs.media.scannerLineShader );
	}
	else
	{
		CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ],
		            rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ],
		            STALKWIDTH, -drawOrigin[ 2 ], cgs.media.scannerLineShader );
	}

	CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX / 2 ) - drawOrigin[ 0 ],
	            rect->y + ( rect->h / 2 ) - ( BLIPY / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ],
	            BLIPX, BLIPY, cgs.media.scannerBlipShader );
	trap_R_SetColor( NULL );
}
Example #17
0
/***
Rotates point around a given vector.
@function RotatePointAround
@param dir Vector to rotate around (must be normalized).
@param point Point to be rotated.
@param degrees How many degrees to rotate.
@param dest Point after rotation.
*/
static int Vector_RotatePointAround(lua_State *L) {
	vec_t	*dst, *dir, *point;
	vec_t	degrees;

	dst = Lua_GetVector(L, 1);
	dir = Lua_GetVector(L, 2);
	point = Lua_GetVector(L, 3);
	degrees = luaL_checknumber(L, 4);

	RotatePointAroundVector(dst, dir, point, degrees);

	return 0;
}
Example #18
0
static void
ShowStats(edict_t *ent, edict_t *player)
{
//	float dist = 0.0;
	vec3_t v;
	int j;
	char stats[500];
	BlinkyClient_t * bdata;
	char pname[11];
	int health, armor, armorpow;
	int xd,yd,zd;
	vec3_t dp, normal={0,0,-1};
	static int CellsIndex = -1;
	int index;

	j = 0;
	if (-1 == CellsIndex)
		CellsIndex = ITEM_INDEX(FindItem("cells"));

	bdata = &ent->client->blinky_client;

	VectorSubtract(ent->s.origin, player->s.origin, v);
	zd = -v[2]/SCANNER_UNIT; // save height differential
	v[2] = 0; // remove height component

	RotatePointAroundVector(dp, normal, v, ent->s.angles[1]);
	xd = -dp[0]/SCANNER_UNIT;
	yd = dp[1]/SCANNER_UNIT;
	if (player->client)
		strncpy(pname, player->client->pers.netname, sizeof(pname)-1);
	else
		strncpy(pname, player->classname, sizeof(pname)-1);
	pname[sizeof(pname)-1] = 0;
	health = player->health;

	armorpow = 0;
	if (PowerArmorType(ent))
		armorpow = ent->client->pers.inventory[CellsIndex];

	index = ArmorIndex (ent);
	if (index)
		armor = ent->client->pers.inventory[index];

	if (armorpow)
		sprintf(stats+j, "%s: armor=%3d(%3d), health=%3d (f=%+5d,r=%+5d,u=%+5d)\n"
			, pname, armor,armorpow,health,xd, yd, zd);
	else
		sprintf(stats+j, "%s: armor=%3d, health=%3d (f=%+5d,r=%+5d,u=%+5d)\n"
			, pname, armor,health,xd, yd, zd);
	gi.cprintf(ent, PRINT_CHAT, "%s", stats);
}
Example #19
0
void FrustumCheck::R_SetFrustum (vec3_t vangles, vec3_t vorigin, float view_hor, float view_ver, float dist)
{
	int i;
	vec3_t vpn, vright, vup;

	AngleVectors (vangles, vpn, vright, vup);

	// rotate VPN right by FOV_X/2 degrees
	RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-view_hor / 2 ) );
	// rotate VPN left by FOV_X/2 degrees
	RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-view_hor / 2 );
	// rotate VPN up by FOV_X/2 degrees
	RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-(view_ver) / 2 );
	// rotate VPN down by FOV_X/2 degrees
	RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 -(view_ver) / 2 ) );

	for (i=0 ; i<4 ; i++)
	{
		frustum[i].type = PLANE_ANYZ;
		frustum[i].dist = DotProduct (vorigin, frustum[i].normal);
		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
	}

	// buz: set also clipping by distance
	vec3_t farpoint = vorigin + (vpn * dist);
	farclip.normal = vpn * -1;
	farclip.type = PLANE_ANYZ;
	farclip.dist = DotProduct (farpoint, farclip.normal);
	farclip.signbits = SignbitsForPlane (&farclip);
	farclipset = 1;

	// save params for building stencil clipping volume
	VectorCopy(vorigin, m_origin);
	VectorCopy(vangles, m_angles);
	m_fov_hor = view_hor;
	m_fov_ver = view_ver;
	m_dist = dist;
}
Example #20
0
void FrustumCheck::R_SetFrustum (vec3_t vangles, vec3_t vorigin, float viewsize)
{
	int i;
	vec3_t vpn, vright, vup;

	AngleVectors (vangles, vpn, vright, vup);
	if (viewsize == 90) 
	{
		// front side is visible

		VectorAdd (vpn, vright, frustum[0].normal);
		VectorSubtract (vpn, vright, frustum[1].normal);

		VectorAdd (vpn, vup, frustum[2].normal);
		VectorSubtract (vpn, vup, frustum[3].normal);
	}
	else
	{
		// rotate VPN right by FOV_X/2 degrees
		RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-viewsize / 2 ) );
		// rotate VPN left by FOV_X/2 degrees
		RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-viewsize / 2 );
		// rotate VPN up by FOV_X/2 degrees
		RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-(viewsize*0.75) / 2 );
		// rotate VPN down by FOV_X/2 degrees
		RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 -(viewsize*0.75) / 2 ) );
	}

	for (i=0 ; i<4 ; i++)
	{
		frustum[i].type = PLANE_ANYZ;
		frustum[i].dist = DotProduct (vorigin, frustum[i].normal);
		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
	}

	farclipset = 0; // buz
}
Example #21
0
void
R_SetFrustum (void)
{
	int         i;

	// rotate VPN right by FOV_X/2 degrees
	RotatePointAroundVector (frustum[0].normal, vup, vpn,
							 -(90 - r_refdef.fov_x / 2));
	// rotate VPN left by FOV_X/2 degrees
	RotatePointAroundVector (frustum[1].normal, vup, vpn,
							 90 - r_refdef.fov_x / 2);
	// rotate VPN up by FOV_Y/2 degrees
	RotatePointAroundVector (frustum[2].normal, vright, vpn,
							 90 - r_refdef.fov_y / 2);
	// rotate VPN down by FOV_Y/2 degrees
	RotatePointAroundVector (frustum[3].normal, vright, vpn,
							 -(90 - r_refdef.fov_y / 2));

	for (i = 0; i < 4; i++) {
		frustum[i].type = PLANE_ANYZ;
		frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
	}
}
Example #22
0
static void BotMoveTowardsLinkedMarker(gedict_t* self, vec3_t dir_move) {
	vec3_t temp;
	gedict_t* goalentity_ = &g_edicts[self->s.v.goalentity];
	gedict_t* linked = self->fb.linked_marker;
	qbool onGround = ((int)self->s.v.flags & FL_ONGROUND);
	qbool curlJump = ((int)self->fb.path_state & BOTPATH_CURLJUMP_HINT);

	VectorAdd(linked->s.v.absmin, linked->s.v.view_ofs, temp);
	VectorSubtract(temp, self->s.v.origin, temp);
	normalize(temp, dir_move);

	if (curlJump && (onGround || self->s.v.velocity[2] > 0)) {
		vec3_t up = { 0, 0, 1 };

		if (self->isBot && self->fb.debug_path) {
			G_bprint (PRINT_HIGH, "%3.2f: Moving %3d > %3d, dir %3.1f %3.1f %3.1f\n", g_globalvars.time, self->fb.touch_marker->fb.index + 1, self->fb.linked_marker->fb.index + 1, PASSVEC3 (dir_move));
		}

		RotatePointAroundVector (dir_move, up, dir_move, self->fb.angle_hint);

		if (self->isBot && self->fb.debug_path) {
			G_bprint (PRINT_HIGH, "%3.2f: Rotating %d, %3.1f %3.1f %3.1f\n", g_globalvars.time, self->fb.angle_hint, PASSVEC3 (dir_move));
		}
	}

	if (self->isBot && self->fb.debug_path) {
		//G_bprint (PRINT_HIGH, "%3.2f: Moving %3d > %3d, dir %3.1f %3.1f %3.1f\n", g_globalvars.time, self->fb.touch_marker->fb.index + 1, self->fb.linked_marker->fb.index + 1, PASSVEC3 (dir_move));
	}

	if (self->fb.path_state & DELIBERATE_BACKUP) {
		if (linked->fb.arrow_time > g_globalvars.time) {
			VectorInverse (dir_move);
		}
		else {
			self->fb.path_state &= ~DELIBERATE_BACKUP;
		}
	}
	else if (linked == self->fb.touch_marker) {
		if (goalentity_ == self->fb.touch_marker) {
			if (WaitingToRespawn(self->fb.touch_marker)) {
				VectorClear(dir_move);
			}
		}
		else {
			VectorClear(dir_move);
		}
	}
}
Example #23
0
static int vector_RotatePointAround(lua_State * L)
{
	vec_t          *dst;
	vec_t          *dir;
	vec_t          *point;
	vec_t           degrees;

	dst = lua_getvector(L, 1);
	dir = lua_getvector(L, 2);
	point = lua_getvector(L, 3);
	degrees = luaL_checknumber(L, 4);

	RotatePointAroundVector(dst, dir, point, degrees);

	return 1;
}
Example #24
0
void RotateAroundDirection( vector3 axis[3], float yaw ) {

	// create an arbitrary axis[1]
	PerpendicularVector( &axis[1], &axis[0] );

	// rotate it around axis[0] by yaw
	if ( yaw ) {
		vector3	temp;

		VectorCopy( &axis[1], &temp );
		RotatePointAroundVector( &axis[1], &axis[0], &temp, yaw );
	}

	// cross to get axis[2]
	CrossProduct( &axis[0], &axis[1], &axis[2] );
}
Example #25
0
static void Tess_SurfaceSprite()
{
	vec3_t delta, left, up;
	float  radius;
	vec4_t color;

	GLimp_LogComment( "--- Tess_SurfaceSprite ---\n" );

	radius = backEnd.currentEntity->e.radius;

	if( tess.surfaceShader->autoSpriteMode == 1 ) {
		// the calculations are done in GLSL shader

		Tess_AddSprite( backEnd.currentEntity->e.origin, 
				backEnd.currentEntity->e.shaderRGBA,
				radius, backEnd.currentEntity->e.rotation );
		return;
	}

	VectorSubtract( backEnd.currentEntity->e.origin, backEnd.viewParms.pvsOrigin, delta );

	if( VectorNormalize( delta ) < NORMAL_EPSILON )
		return;

	CrossProduct( backEnd.viewParms.orientation.axis[ 2 ], delta, left );

	if( VectorNormalize( left ) < NORMAL_EPSILON )
		VectorSet( left, 1, 0, 0 );

	if( backEnd.currentEntity->e.rotation != 0 )
		RotatePointAroundVector( left, delta, left, backEnd.currentEntity->e.rotation );

	CrossProduct( delta, left, up );

	VectorScale( left, radius, left );
	VectorScale( up, radius, up );

	if ( backEnd.viewParms.isMirror )
		VectorSubtract( vec3_origin, left, left );

	color[ 0 ] = backEnd.currentEntity->e.shaderRGBA[ 0 ] * ( 1.0 / 255.0 );
	color[ 1 ] = backEnd.currentEntity->e.shaderRGBA[ 1 ] * ( 1.0 / 255.0 );
	color[ 2 ] = backEnd.currentEntity->e.shaderRGBA[ 2 ] * ( 1.0 / 255.0 );
	color[ 3 ] = backEnd.currentEntity->e.shaderRGBA[ 3 ] * ( 1.0 / 255.0 );

	Tess_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, color );
}
Example #26
0
void hover_dodge (edict_t *self, edict_t *attacker, float eta) /* FS: Zaero specific game dll changes */
{
	int delta = 0;
	vec3_t forward, right;
	vec3_t dir;
	int count  = 0;
	if (self->monsterinfo.currentmove == &hover_move_attack1)
		if (random() < 0.75) // if we're attacking, stop attacking and dodge 1/4 the time
			return;

	self->monsterinfo.attack_state = AS_FLY_STRAFE;
	 // TODO choose an angle to move based on what's around me

	// start at a random value
	self->monsterinfo.flyStrafePitch = crandom() * 180;
	
	// choose a random delta dir
	delta = (random() < 0.5 ? 10 : -10);
	AngleVectors(self->s.angles, forward, right, NULL);

	// now try to find a direction that'll give us sufficient room to move
	// (ie. away from walls)
	count = 36;
	while(1)
	{
		trace_t tr;
		vec3_t end;
		RotatePointAroundVector(dir, forward, right, self->monsterinfo.flyStrafePitch);
		VectorMA(self->s.origin, 96, dir, end);

		// trace out in this direction
		tr = gi.trace(self->s.origin, self->mins, self->maxs, end, self, MASK_MONSTERSOLID);
		if (tr.fraction >= 1.0)
			break;

		if (count-- <= 0)
			break; // we've tried enough times;

		self->monsterinfo.flyStrafePitch += delta;
	}

	self->monsterinfo.flyStrafeTimeout = level.time + /*eta + */ 1.0;
	
	//if (random() < 0.5)
	//	self->monsterinfo.currentmove = &hover_move_run;
}
Example #27
0
static void RocketThink( gentity_t *self )
{
	vec3_t currentDir, targetDir, newDir, rotAxis;
	float  rotAngle;

	if ( level.time > self->timestamp )
	{
		self->think     = G_ExplodeMissile;
		self->nextthink = level.time;

		return;
	}

	self->nextthink = level.time + ROCKET_TURN_PERIOD;

	// Calculate current and target direction.
	VectorNormalize2( self->s.pos.trDelta, currentDir );
	VectorSubtract( self->target->r.currentOrigin, self->r.currentOrigin, targetDir );
	VectorNormalize( targetDir );

	// Don't turn anymore after the target was passed.
	if ( DotProduct( currentDir, targetDir ) < 0 )
	{
		return;
	}

	// Calculate new direction. Use a fixed turning angle.
	CrossProduct( currentDir, targetDir, rotAxis );
	rotAngle = RAD2DEG( acos( DotProduct( currentDir, targetDir ) ) );
	RotatePointAroundVector( newDir, rotAxis, currentDir,
	                         Math::Clamp( rotAngle, -ROCKET_TURN_ANGLE, ROCKET_TURN_ANGLE ) );

	// Check if new direction is safe. Turn anyway if old direction is unsafe, too.
	if ( !G_RocketpodSafeShot( ENTITYNUM_NONE, self->r.currentOrigin, newDir ) &&
	     G_RocketpodSafeShot( ENTITYNUM_NONE, self->r.currentOrigin, currentDir ) )
	{
		return;
	}

	// Update trajectory.
	VectorScale( newDir, BG_Missile( self->s.modelindex )->speed, self->s.pos.trDelta );
	SnapVector( self->s.pos.trDelta );
	VectorCopy( self->r.currentOrigin, self->s.pos.trBase ); // TODO: Snap this, too?
	self->s.pos.trTime = level.time;
}
Example #28
0
void CTerrainMap::AddPlayer(vec3_t origin, vec3_t angles)
{
	// draw player start on automap
	CDraw32 draw;

	vec3_t up;
	vec3_t pt[4] = {{0,0,0},{-5,-5,0},{10,0,0},{-5,5,0}};
	vec3_t p;
	int x,y,i;
	float facing;
	POINT poly[4];

	facing = angles[1];
	
	up[0] = 0;
	up[1] = 0;
	up[2] = 1;

	x = (int)origin[0];
	y = (int)origin[1];
	ConvertPos(x, y);
	x++; y++;

	for (i=0; i<4; i++)
	{
		RotatePointAroundVector( p, up, pt[i], facing );
		poly[i].x = (int)(-p[0] + x);
		poly[i].y = (int)(p[1] + y);
	}

	// draw arrowhead shadow
	draw.DrawPolygon(4, poly, CPixel32(0,0,0,128), CPixel32(0,0,0,128));

	// draw arrowhead
	for (i=0; i<4; i++)
	{
		poly[i].x--;
		poly[i].y--;
	}
	draw.DrawPolygon(4, poly, CPixel32(255,255,255), CPixel32(255,255,255));
}
Example #29
0
/*
==============
CG_SurfaceLightningBolt
==============
*/
void CG_SurfaceLightningBolt( const refEntity_t *originEnt ) {
	int			len;
	vec3_t		forward = { 1, 0, 0 };
	vec3_t		right = { 0, 0, 1 };
	vec3_t		vec;
	vec3_t		start, end;
	int			i;
#define NUM_BOLT_POLYS 4
	polyVert_t	verts[NUM_BOLT_POLYS*4];
	refEntity_t re;

	re = *originEnt;
	re.reType = RT_POLY_LOCAL;
	re.renderfx |= RF_AUTOAXIS2;

	VectorCopy( re.oldorigin, end );
	VectorCopy( re.origin, start );

	// compute variables
	VectorSubtract( end, start, vec );
	len = VectorNormalize( vec );

	// setup start and end in local space
	VectorMA( vec3_origin, -len/2.0f, forward, start );
	VectorMA( start, len, forward, end );

	for ( i = 0 ; i < NUM_BOLT_POLYS ; i++ ) {
		vec3_t	temp;

		CG_DoRailCore( &verts[i*4], re.shaderRGBA, start, end, right, len, 8 );
		RotatePointAroundVector( temp, vec, right, 180.0f / NUM_BOLT_POLYS );
		VectorCopy( temp, right );
	}

	trap_R_AddPolyRefEntityToScene( &re, 4, verts, NUM_BOLT_POLYS );
}
Example #30
0
/*
===============
CG_smoothWWTransitions
===============
*/
static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t out )
{
  vec3_t    surfNormal, rotAxis, temp;
  vec3_t    refNormal     = { 0.0f, 0.0f,  1.0f };
  vec3_t    ceilingNormal = { 0.0f, 0.0f, -1.0f };
  int       i;
  float     stLocal, sFraction, rotAngle;
  float     smoothTime, timeMod;
  qboolean  performed = qfalse;
  vec3_t    inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ];

  if( cg.snap->ps.pm_flags & PMF_FOLLOW )
  {
    VectorCopy( in, out );
    return;
  }

  //set surfNormal
  BG_GetClientNormal( ps, surfNormal );

  AnglesToAxis( in, inAxis );

  //if we are moving from one surface to another smooth the transition
  if( !VectorCompare( surfNormal, cg.lastNormal ) )
  {
    //if we moving from the ceiling to the floor special case
    //( x product of colinear vectors is undefined)
    if( VectorCompare( ceilingNormal, cg.lastNormal ) &&
        VectorCompare( refNormal,     surfNormal ) )
    {
      AngleVectors( in, temp, NULL, NULL );
      ProjectPointOnPlane( rotAxis, temp, refNormal );
      VectorNormalize( rotAxis );
      rotAngle = 180.0f;
      timeMod = 1.5f;
    }
    else
    {
      AnglesToAxis( cg.lastVangles, lastAxis );
      rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) +
                 DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) +
                 DotProduct( inAxis[ 2 ], lastAxis[ 2 ] );

      rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) );

      CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp );
      VectorCopy( temp, rotAxis );
      CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp );
      VectorAdd( rotAxis, temp, rotAxis );
      CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp );
      VectorAdd( rotAxis, temp, rotAxis );

      VectorNormalize( rotAxis );

      timeMod = 1.0f;
    }

    //add the op
    CG_addSmoothOp( rotAxis, rotAngle, timeMod );
  }

  //iterate through ops
  for( i = MAXSMOOTHS - 1; i >= 0; i-- )
  {
    smoothTime = (int)( cg_wwSmoothTime.integer * cg.sList[ i ].timeMod );

    //if this op has time remaining, perform it
    if( cg.time < cg.sList[ i ].time + smoothTime )
    {
      stLocal = 1.0f - ( ( ( cg.sList[ i ].time + smoothTime ) - cg.time ) / smoothTime );
      sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f;

      RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis,
        inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle );
      RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis,
        inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle );
      RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis,
        inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle );

      AxisCopy( outAxis, inAxis );
      performed = qtrue;
    }
  }

  //if we performed any ops then return the smoothed angles
  //otherwise simply return the in angles
  if( performed )
    AxisToAngles( outAxis, out );
  else
    VectorCopy( in, out );

  //copy the current normal to the lastNormal
  VectorCopy( in, cg.lastVangles );
  VectorCopy( surfNormal, cg.lastNormal );
}