//-----------------------------------------------------------------------------
//
//  $Logfile:: /Source/r_sprite.c                                             $
// $Revision:: 3                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 8/8/01 4:42 PM                                                 $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
//

#include "r_local.h"

extern polydesc_t r_polydesc;
extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];

/*
** R_DrawSprite
**
** Draw currententity / currentmodel as a single texture
** mapped polygon
*/
void R_DrawSprite (void)
{
	vec3_t		left, up, right, down;
	dsprite_t	*s_psprite;
	dsprframe_t	*s_psprframe;
	vec3_t		light;
	float		dot, angle, sr, cr;
	int			i,j;
	triangle_t	tri;
	vec3_t		angles;
	float		yaw_inc;
	int			num_sprites = 1;
	qboolean	sprite_lefthanded;
	qboolean	use_base = false;

	s_psprite = (dsprite_t *)currentmodel->extradata;
	currententity->frame %= s_psprite->numframes;

	s_psprframe = &s_psprite->frames[currententity->frame];

	yaw_inc = 0;/* silence compiler */
	VectorCopy( currententity->angles, angles );
	if (s_psprite->type == SPR_VP_PARALLEL)
	{
		/* generate the sprite's axes, completely parallel to the viewplane. There */
		/* are no problem situations, because the sprite is always in the same */
		/* position relative to the viewer */
		VectorCopy (vup, r_polydesc.vup);
		VectorCopy (vright, r_polydesc.vright);
		VectorCopy (vpn, r_polydesc.vpn);
	}
	else if (s_psprite->type == SPR_VP_PARALLEL_UPRIGHT)
	{
		/* generate the sprite's axes, with vup straight up in worldspace, and */
		/* svright parallel to the viewplane. */
		/* This will not work if the view direction is very close to straight up or */
		/* down, because the cross product will be between two nearly parallel */
		/* vectors and starts to approach an undefined state, so we don't draw if */
		/* the two vectors are less than 1 degree apart */
		dot = vpn[2];	// same as DotProduct (vpn, svup) because
						//  svup is 0, 0, 1
		if ((dot > 0.999848) || (dot < -0.999848))	// cos(1 degree) = 0.999848
			return;
		r_polydesc.vup[0] = 0;
		r_polydesc.vup[1] = 0;
		r_polydesc.vup[2] = 1;
		r_polydesc.vright[0] = vpn[1];
										// CrossProduct (r_polydesc.vup, vpn,
		r_polydesc.vright[1] = -vpn[0];	//  r_polydesc.vright)
		r_polydesc.vright[2] = 0;
		VectorNormalize (r_polydesc.vright);
		r_polydesc.vpn[0] = -r_polydesc.vright[1];
		r_polydesc.vpn[1] = r_polydesc.vright[0];
		r_polydesc.vpn[2] = 0;
					// CrossProduct (r_polydesc.vright, r_polydesc.vup,
					//  r_polydesc.vpn)
	}
	else if (s_psprite->type == SPR_ORIENTED)
	{
		// generate the sprite's axes, according to the sprite's world orientation
		AngleVectors (currententity->angles, r_polydesc.vpn, r_polydesc.vright, r_polydesc.vup);
	}
	else if (s_psprite->type == SPR_ORIENTED_CROSS)
	{
		// generate the sprite's axes, according to the sprite's world orientation
		yaw_inc = 90;
		AngleVectors (currententity->angles, r_polydesc.vpn, r_polydesc.vright, r_polydesc.vup);
		num_sprites = 2;
	}
	else if (s_psprite->type == SPR_ORIENTED_STAR)
	{
		// generate the sprite's axes, according to the sprite's world orientation
		yaw_inc = 45;
		AngleVectors (currententity->angles, r_polydesc.vpn, r_polydesc.vright, r_polydesc.vup);
		num_sprites = 4;
	}
	else if (s_psprite->type == SPR_VP_PARALLEL_ORIENTED)
	{
	// generate the sprite's axes, parallel to the viewplane, but rotated in
	// that plane around the center according to the sprite entity's roll
	// angle. So vpn stays the same, but vright and vup rotate
		angle = currententity->angles[ROLL] * (M_PI*2 / 360);
		sr = sin(angle);
		cr = cos(angle);

		for (i=0 ; i<3 ; i++)
		{
			r_polydesc.vpn[i] = vpn[i];
			r_polydesc.vright[i] = vright[i] * cr + vup[i] * sr;
			r_polydesc.vup[i] = vright[i] * -sr + vup[i] * cr;
		}
	}
	else
	{
		Sys_Error ("R_DrawSprite: Bad sprite type %d", s_psprite->type);
	}

	if ( s_psprite->flags & SPRITE_HASBASE )
		num_sprites++;

	for (j=0;j<num_sprites;j++)
	{
		if (j > 0)
		{
			if ( ( j == num_sprites - 1 ) && ( s_psprite->flags & SPRITE_HASBASE ) )
			{
				use_base = true;
				s_psprframe = &s_psprite->base;
				AngleVectors (currententity->angles, r_polydesc.vup, r_polydesc.vright, r_polydesc.vpn);
			}
			else
			{
				use_base = false;
				if ( yaw_inc == 90 )
				{
					vec3_t swap;
					VectorCopy(r_polydesc.vpn, swap);
					VectorCopy(r_polydesc.vright, r_polydesc.vpn);
					VectorCopy(swap, r_polydesc.vright);
				}
				else
				{
					angles[ YAW ] += yaw_inc;
					while ( angles[ YAW ] >= 360 )
						angles[ YAW ] -= 360;
					AngleVectors( angles, r_polydesc.vpn, r_polydesc.vright, r_polydesc.vup );
				}
			}
		}
		else
		{
			use_base = false;
		}

		// build the sprite poster in worldspace
		VectorScale (r_polydesc.vright, 
			s_psprite->scale * currententity->scale * (s_psprframe->width - s_psprframe->origin_x), right);
		VectorScale (r_polydesc.vup, 
			s_psprite->scale * currententity->scale * (s_psprframe->height - s_psprframe->origin_y), up);
		VectorScale (r_polydesc.vright,
			-s_psprframe->origin_x * s_psprite->scale * currententity->scale, left);
		VectorScale (r_polydesc.vup,
			-s_psprframe->origin_y * s_psprite->scale * currententity->scale, down);

		memset( &tri, 0, sizeof( tri ) );

		sprite_lefthanded = false;
		if (currententity->flags & RF_WEAPONMODEL)
		{
			if ( r_lefthand->value == 2 )
				continue;
			if ( r_lefthand->value == 1.0F )
				sprite_lefthanded = true;
			if ( currententity->flags & RF_XFLIP )
				sprite_lefthanded ^= true;
			if (sprite_lefthanded)
			{
				vec3_t delta;
				float len;

				VectorSubtract( r_entorigin, r_origin, delta );
				len = DotProduct( delta, vright );
				VectorMA( r_entorigin, -2*len, vright, r_entorigin );
			}
			tri.flags |= TRI_WEAPONMODEL;
		}

		if (currententity->flags & RF_LENSFLARE)
		{
			// Don't support lensflares
			return;
		}
		else if (s_psprite->flags & SPRITE_WORLDLIT)
		{
			R_LightPoint(r_entorigin, light, true);
			if ( VectorLength( light ) < 1 )
			{
				light[0]=light[1]=light[2] = 0.33f;
			}
		}
		else
		{
			light[0]=light[1]=light[2] = 1.0f;
		}

		for ( i = 0; i < 3; i++ )
		{
			// upper left
			tri.verts[0][i] = up[i] + left[i];
			tri.verts[0][i+5] = light[i];
			// lower left
			tri.verts[1][i] = down[i] + left[i];
			tri.verts[1][i+5] = light[i];
			// upper right
			tri.verts[2][i] = up[i] + right[i];
			tri.verts[2][i+5] = light[i];
			// upper right
			tri.verts[3][i] = up[i] + right[i];
			tri.verts[3][i+5] = light[i];
			// lower left
			tri.verts[4][i] = down[i] + left[i];
			tri.verts[4][i+5] = light[i];
			// lower right
			tri.verts[5][i] = down[i] + right[i];
			tri.verts[5][i+5] = light[i];
		}

		//
		// assign texture coordinates
		//
		// upper left
		tri.verts[0][3] = 0.004;
		tri.verts[0][4] = 0.004;
		// lower left
		tri.verts[1][3] = 0.004;
		tri.verts[1][4] = 0.995f;
		// upper right
		tri.verts[2][3] = 0.995f;
		tri.verts[2][4] = 0.004;
		// upper right
		tri.verts[3][3] = 0.995f;
		tri.verts[3][4] = 0.004;
		// lower left
		tri.verts[4][3] = 0.004;
		tri.verts[4][4] = 0.995f;
		// lower right
		tri.verts[5][3] = 0.995f;
		tri.verts[5][4] = 0.995f;

		tri.num_tris = 2;
		if ( use_base )
			tri.texture = currentmodel->skins[s_psprite->numframes];
		else
			tri.texture = currentmodel->skins[currententity->frame];

		if ( currententity->flags & RF_TRANSLUCENT )
			tri.alpha = currententity->alpha;
		else
			tri.alpha = s_psprframe->alpha;

		if (s_psprite->twosided)
			tri.flags |= TRI_TWOSIDED;

		tri.flags |= TRI_MASKED;

		VectorCopy( r_entorigin, tri.origin );
		VectorClear( tri.angles );
		DrawTriangle ( &tri );
	}
}
