//-----------------------------------------------------------------------------
//
//  $Logfile:: /Source/cl_surface.c                                           $
// $Revision:: 2                                                              $
//   $Author:: Burgermac                                                      $
//     $Date:: 12/27/00 7:46 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:
// Keeps track of all the surfaces in the game.  They all get updated here
// for translation, animation, and the states get set here from the server
// messages.

#include <ctype.h>
#include "client.h"

#define MAXSURFACES 1024

csurface_t        *surfaceList[MAXSURFACES];
int cl_numsurfaces;

/*
==================
CL_BuildSurfaceList
==================
*/
void CL_BuildSurfaceList( void )
{
	int i;
	csurface_t *csurf;

	cl_numsurfaces = 0;

	for ( i=0; i<numtexinfo; i++ )
	{
		if (cl_numsurfaces > MAXSURFACES)
		{
			Com_Error ( ERR_DROP, "CL_BuildSurfaceList: Exceeded max number of surfaces\n" );
		}

		csurf = &map_surfaces[ i ];
		if (csurf->flags & (SURF_ANIMATE|SURF_TRANSLATE))
		{
			surfaceList[cl_numsurfaces++] = csurf;
		}
	}
}


/*
==================
CL_ProcessSurfaces
==================
*/
void CL_ProcessSurfaces( void )
{
	int i;
	float time = cls.realtime / 1000.0f;
	static qboolean paused = false;
	csurface_t  *csurf;

	if (cls.state != ca_active)
		return;

	if (cl.map_sequence_number != map_sequence_number)
	{
		return;
	}

	// If the system is paused, then we don't need to update.
	if ( cl_paused->value )
	{
		if ( !paused ) paused = true;
		return;
	}
	else if ( paused )
	{
		paused = false;
		// When we come un-paused, we need to update the time only
		// and then skip a frame
		for ( i=0; i<numtexinfo; i++ )
		{
			csurf = &map_surfaces[ i ];
			csurf->last_update_time = time;
		}
		return;
	}

	// Loop through all the surfaces and update surfaces
	for ( i=0; i<cl_numsurfaces; i++ )
	{
		csurf = surfaceList[ i ];

		//-----------------------------------
		// Update animation for this surface
		//-----------------------------------
		if ( csurf->flags & SURF_ANIMATE )
		{
			if ( time > csurf->nextanimtime )
			{
				// increment the animation frame by setting the texinfo in
				// the surface to the next one ( if it's there, otherwise wrap
				// around )

				if ( csurf->flags & SURF_RANDOMANIMATE )
				{
					// Random start frame
					csurf->animation_frame = ( csurf->frameoffset + 1 ) % csurf->numframes;
				}
				else
				{
					csurf->animation_frame = ( csurf->animation_frame + 1 ) % csurf->numframes;
				}

				if (csurf->flags & SURF_RNDTIME)
				{
					csurf->nextanimtime = time + max( csurf->animtime, frand() );
				}
				else
				{
					csurf->nextanimtime = time + csurf->animtime;
				}
			}
		}

		// ---------------------------
		// Update translating surfaces
		// ---------------------------
		if (csurf->flags & SURF_TRANSLATE)
		{
			float xpart;
			float ypart;

			if (csurf->trans_angle == 0)
			{xpart = 1; ypart = 0;}
			else if (csurf->trans_angle == 90)
			{xpart = 0; ypart = 1;}
			else if (csurf->trans_angle == 180)
			{xpart = -1; ypart = 0;}
			else if (csurf->trans_angle == 270)
			{xpart = 0; ypart = -1;}
			else
			{
				ypart = sin( ( csurf->trans_angle * M_PI ) / 180.0 );
				xpart = cos( ( csurf->trans_angle * M_PI ) / 180.0 );
			}

			if ( csurf->flags & ( SURF_WARP | SURF_WAVY ) )
			{
				csurf->delta_s += ( xpart *( csurf->trans_mag ) * ( time - csurf->last_update_time ) );
				csurf->delta_t += ( ypart *( csurf->trans_mag ) * ( time - csurf->last_update_time ) );
			}
			else
			{
				csurf->delta_s += ( xpart *( csurf->trans_mag / csurf->upload_width ) * ( time - csurf->last_update_time ) );
				csurf->delta_t += ( ypart *( csurf->trans_mag / csurf->upload_height ) * ( time - csurf->last_update_time ) );
			}

			if ( fabs( csurf->delta_s ) > 256 )
				csurf->delta_s = 0;
			if ( fabs( csurf->delta_t ) > 256 )
				csurf->delta_t = 0;
		}

		// ---------------------------
		// Set last update time
		// ---------------------------
		csurf->last_update_time = time;
	}   // end process surface loop
}

/*
=====================
CL_UpdateSurfaceState
=====================
*/
static void CL_UpdateSurfaceState( surface_state_t *state, int flags, csurface_t *csurf )
{
	if ( flags & S_TRANS_STATE )
	{
		if ( state->trans_state )
			csurf->flags |= SURF_TRANSLATE;
		else
			csurf->flags &= ~SURF_TRANSLATE;
	}

	if ( flags & S_TRANS_ANGLE )
	{
		csurf->trans_angle = state->trans_angle;
	}

	if ( flags & S_TRANS_MAG )
	{
		csurf->trans_mag = state->trans_mag;
	}

	if ( flags & S_TRANSLUCENCE )
	{
		csurf->translucence = state->translucence;
	}

	if ( flags & S_MAGNITUDE )
	{
		csurf->magnitude = state->magnitude;
	}

	if ( flags & S_FREQUENCY )
	{
		csurf->frequency = state->frequency;
	}

	if ( flags & S_DAMAGE_FRAME )
	{
		int frame;
		csurface_t     *surface;

		surface = &map_surfaces[ csurf->groupnumber ];
		surface->animation_frame = 0;

		// Update the animation frame based off the damage frame that
		// was sent over.
		for (frame = 0; frame < state->damage_frame; frame++)
		{
			if (surface->next)
			{
				surface->animation_frame++;
			}
			else
				break;
		}
	}
}

/*
========================
CL_ProcessTexinfoCommand
========================
*/
void CL_ProcessTexinfoCommand( int surface_number, surface_state_t *state, int flags )
{
	csurface_t  *csurf;
	const char  *surfname;
	int i;

	if (!map_surfaces)
		return;

	csurf = &map_surfaces[surface_number];

	if (!isdigit(csurf->groupname[0]))
		surfname  = csurf->groupname;
	else	surfname  = NULL;

	CL_UpdateSurfaceState( state, flags, csurf );

	if (surfname) /* search all */
	{
		for (i = 0; i < numtexinfo; i++)
		{
			csurf = &map_surfaces[i];
			if (!strcmp( surfname, csurf->groupname))
			{
				CL_UpdateSurfaceState(state, flags, csurf);
			}
		}
	}
}

