// Copyright (C) 2001-2002 Raven Software.
//
// cg_effects.c -- these functions generate localentities, usually as a result
// of event processing

#include "cg_local.h"

/*
==================
CG_BubbleTrail

Bullets shot underwater
==================
*/
void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
	vec3_t		move;
	vec3_t		vec;
	float		len;
	int			i;

	if ( cg_noProjectileTrail.integer ) {
		return;
	}

	VectorCopy (start, move);
	VectorSubtract (end, start, vec);
	len = VectorNormalize (vec);

	// advance a random amount first
	i = rand() % (int)spacing;
	VectorMA( move, i, vec, move );

	VectorScale (vec, spacing, vec);

	for ( ; i < len; i += spacing ) {
		localEntity_t	*le;
		refEntity_t		*re;

		le = CG_AllocLocalEntity();
		le->leFlags = LEF_PUFF_DONT_SCALE;
		le->leType = LE_MOVE_SCALE_FADE;
		le->startTime = cg.time;
		le->endTime = cg.time + 1000 + random() * 250;
		le->lifeRate = 1.0 / ( le->endTime - le->startTime );

		re = &le->refEntity;
		re->shaderTime = cg.time / 1000.0f;

		re->reType = RT_SPRITE;
		re->rotation = 0;
		re->radius = 3;
		re->customShader = cgs.media.waterBubbleShader;
		re->shaderRGBA[0] = 0xff;
		re->shaderRGBA[1] = 0xff;
		re->shaderRGBA[2] = 0xff;
		re->shaderRGBA[3] = 0xff;

		le->color[3] = 1.0;

		le->pos.trType = TR_LINEAR;
		le->pos.trTime = cg.time;
		VectorCopy( move, le->pos.trBase );
		le->pos.trDelta[0] = crandom()*5;
		le->pos.trDelta[1] = crandom()*5;
		le->pos.trDelta[2] = crandom()*5 + 6;

		VectorAdd (move, vec, move);
	}
}


void CG_TestLine( vec3_t start, vec3_t end, int time, unsigned int color, int radius) 
{
	localEntity_t	*le;
	refEntity_t		*re;

	le = CG_AllocLocalEntity();
	le->leType = LE_LINE;
	le->startTime = cg.time;
	le->endTime = cg.time + time;
	le->lifeRate = 1.0 / ( le->endTime - le->startTime );

	re = &le->refEntity;
	VectorCopy( start, re->origin );
	VectorCopy( end, re->oldorigin);
	re->shaderTime = cg.time / 1000.0f;

	re->reType = RT_LINE;
	re->radius = 0.5*radius;
	re->customShader = cgs.media.whiteShader; //trap_R_RegisterShaderNoMip("textures/colombia/canvas_doublesided");

	re->shaderTexCoord[0] = re->shaderTexCoord[1] = 1.0f;

	if (color==0)
	{
		re->shaderRGBA[0] = re->shaderRGBA[1] = re->shaderRGBA[2] = re->shaderRGBA[3] = 0xff;
	}
	else
	{
		re->shaderRGBA[0] = color & 0xff;
		color >>= 8;
		re->shaderRGBA[1] = color & 0xff;
		color >>= 8;
		re->shaderRGBA[2] = color & 0xff;
		re->shaderRGBA[3] = 0xff;
	}

	le->color[3] = 1.0;
}

/*
==================
CG_ThrowShard
==================
*/
void CG_ThrowShard( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
	localEntity_t	*le;
	refEntity_t		*re;

	le = CG_AllocLocalEntity();
	re = &le->refEntity;

	le->leType = LE_FRAGMENT;
	le->startTime = cg.time;
	le->endTime = le->startTime + 5000 + random() * 3000;

	VectorCopy( origin, re->origin );
	AxisCopy( axisDefault, re->axis );
	re->hModel = hModel;

	le->pos.trType = TR_GRAVITY;
	le->angles.trType = TR_GRAVITY;
	VectorCopy( origin, le->pos.trBase );
	VectorCopy( velocity, le->pos.trDelta );
	VectorSet(le->angles.trBase, 20, 20, 20);
	VectorCopy( velocity, le->angles.trDelta );
	le->pos.trTime = cg.time;
	le->angles.trTime = cg.time;

	le->leFlags = LEF_TUMBLE;

	le->angles.trBase[YAW] = 180;

	le->bounceFactor = 0.3f;
}

/*
==================
CG_GlassShatter
Throws glass shards from within a given bounding box in the world
==================
*/
void CG_GlassShatter(int entnum, vec3_t org, vec3_t mins, vec3_t maxs)
{
	vec3_t velocity, a, shardorg, dif, difx;
	float windowmass;
	float shardsthrow = 0;

	trap_S_StartSound(org, entnum, CHAN_BODY, cgs.media.glassBreakSound, -1, -1 );

	VectorSubtract(maxs, mins, a);

	windowmass = VectorLength(a); //should give us some idea of how big the chunk of glass is

	while (shardsthrow < windowmass)
	{
		velocity[0] = crandom()*150;
		velocity[1] = crandom()*150;
		velocity[2] = 150 + crandom()*75;

		VectorCopy(org, shardorg);
	
		dif[0] = (maxs[0]-mins[0])/2;
		dif[1] = (maxs[1]-mins[1])/2;
		dif[2] = (maxs[2]-mins[2])/2;

		if (dif[0] < 2)
		{
			dif[0] = 2;
		}
		if (dif[1] < 2)
		{
			dif[1] = 2;
		}
		if (dif[2] < 2)
		{
			dif[2] = 2;
		}

		difx[0] = (float) Q_irand(1, (int)((dif[0]*0.9)*2));
		difx[1] = (float) Q_irand(1, (int)((dif[1]*0.9)*2));
		difx[2] = (float) Q_irand(1, (int)((dif[2]*0.9)*2));

		if (difx[0] > dif[0])
		{
			shardorg[0] += difx[0]-(dif[0]);
		}
		else
		{
			shardorg[0] -= difx[0];
		}
		if (difx[1] > dif[1])
		{
			shardorg[1] += difx[1]-(dif[1]);
		}
		else
		{
			shardorg[1] -= difx[1];
		}
		if (difx[2] > dif[2])
		{
			shardorg[2] += difx[2]-(dif[2]);
		}
		else
		{
			shardorg[2] -= difx[2];
		}

		trap_FX_PlayEffectID( cgs.media.glassChunkEffect, shardorg, velocity, -1, -1 );

		shardsthrow += 20;
	}
}

qboolean CG_PointLineIntersect ( vec3_t start, vec3_t end, vec3_t point, float rad, vec3_t intersection )
{
	vec3_t dir;
	vec3_t distance;
	float  len;
	float  lineSize;

	VectorSubtract ( end, start, dir );
	lineSize = VectorNormalize ( dir );

	// Calculate the distnace from the shooter to the target
	VectorSubtract ( point, start, distance );

	// Use that distnace to determine the point of tangent in relation to
	// the center of the player entity
	VectorMA ( start, DotProduct ( dir, distance ), dir, intersection );

	VectorSubtract ( intersection, point, distance );
	len = VectorLengthSquared ( distance );

	// Is the intersection point within the given radius requirements?
	if ( len < rad * rad )
	{
		// Make sure its not past the end of the given line
		VectorSubtract ( intersection, start, distance );
		len = VectorLengthSquared ( distance );

		// If the len
		if ( len < lineSize * lineSize )
		{
			return qtrue;
		}
	}

	return qfalse;
}

void CG_BulletFlyBySound ( vec3_t start, vec3_t end )
{
	// make the incidental sounds - all of these should already be precached on the server
	vec3_t	soundPoint;
	if( CG_PointLineIntersect(start, end, cg.refdef.vieworg, 100, soundPoint ) )
	{
		if (irand(1, 10) < 5)
		{
			int which = irand(0, NUMFLYBYS - 1);
			
			trap_S_StartSound (soundPoint, cg.predictedPlayerState.clientNum, CHAN_AUTO, cgs.media.flybySounds[which], -1, -1 );
		}
	}
}
