
/****************************************************************************
*
* RAIN.C
*
*    VERSION : 00.00
*    CREATED : 13/05/98
*   MODIFIED : 13/05/98
*	   TABS : 5
*
* DESCRIPTION
*
*****************************************************************************/

/*---------------------------------------------------------------------------
 * Import Headers
\*--------------------------------------------------------------------------*/

#ifdef PSX_VERSION
#include <sys\types.h>
#include <libgte.h>
#include <libgpu.h>
#include <gtemac.h>
#include <inline_c.h>
#include "..\spec_psx\typedefs.h"
#include "..\spec_psx\gpu.h"
#include "..\spec_psx\maths.h"
#else
#include "../specific/stypes.h"
#endif

#include "objects.h"
#include "items.h"
#include "room.h"
#include "anim.h"
#include "lara.h"
#include "control.h"

/*---------------------------------------------------------------------------
 * Constants
\*--------------------------------------------------------------------------*/

#define MAX_SNOWFLAKES 256

#define X 0
#define Y 1
#define Z	2
#define XYZ 3

/*---------------------------------------------------------------------------
 * Type Defintions
\*--------------------------------------------------------------------------*/

typedef struct {
	long		x;
	long		y;
	long		z;
	signed	char	xv;
	unsigned	char yv;	// Also determines size of flake.
	signed	char zv;
	unsigned	char life;
} SNOWFLAKE;

/*---------------------------------------------------------------------------
 * Externals
\*--------------------------------------------------------------------------*/

#ifdef PSX_VERSION
extern VECTOR3D CamPos, CamTgt;
#endif

extern signed short rcossin_tbl[];
extern long SmokeWindX, SmokeWindZ;

/*---------------------------------------------------------------------------
 * Locals
\*--------------------------------------------------------------------------*/

static SNOWFLAKE raindrops[MAX_SNOWFLAKES];

/*---------------------------------------------------------------------------
 * Public Functions
\*--------------------------------------------------------------------------*/

/****************************************************************************
* DoRain
*
* SYNOPSIS
*	void DoRain()
*
* PURPOSE
*	Displays a load of lovely raindrops
*
* INPUTS
*	None
*
* RETURNS
*	Nothing
*/

#ifdef PSX_VERSION

void DoRain()
{
	long	x, y, z, radius, lp, angle, randval, out, triggered;
	SNOWFLAKE	*rainptr;
	LINE_G2 *lineg2;

	short		*scrxy;	// X,Y
	long			*scrz;	// Z
	short		*TempMesh;

/* -------- determine distance (this is wank - do it properly after E3) */

//	if (OutsideRoomOffsets[((CamPos.x>>12)*27)+(CamPos.z>>12)] != -1)
//		distance = 3072;
//	else
//		distance = 4096;

	scrxy = (short *) 0x1f800000;	// Set pointer to scratch pad.
	scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.
	TempMesh = (short *) 0x1f800200;	// Set pointer to scratch pad.

	triggered = 0;

// Update raindrops and trigger any if need be (i.e. Xpos = 0).

	rainptr = &raindrops[0];

	for ( lp=0 ; lp<MAX_SNOWFLAKES ; lp++ )
	{
		if (rainptr->x == 0 && triggered < 8)	// Trigger a new one.
		{
			triggered++;
			y = -1024 - (GetRandomDraw()&2047);

			radius = (GetRandomDraw()&4095);
			angle = GetRandomDraw()&8190;

			x = (((rcossin_tbl[angle])*radius)>>12);
			z = (((rcossin_tbl[angle+1])*radius)>>12);

			rainptr->x = lara_item->pos.x_pos+x;
			rainptr->y = lara_item->pos.y_pos+y;
			rainptr->z = lara_item->pos.z_pos+z;
			if (IsRoomOutside(rainptr->x, rainptr->y, rainptr->z) < 0)
			{
				rainptr->x = 0;
				rainptr++;
				continue;
			}

			rainptr->xv = (GetRandomDraw()&7) - 4;
			rainptr->yv = ((GetRandomDraw()&7) + 16);
			rainptr->zv = (GetRandomDraw()&7) - 4;
			rainptr->life = 32+(56-(rainptr->yv<<1));
		}

		if (rainptr->x != 0)
		{
			out = IsRoomOutside(rainptr->x, rainptr->y, rainptr->z);
			if (out == -2 || room[IsRoomOutsideNo].flags & UNDERWATER)	// Underwater room.
			{
				rainptr->x=0;
				rainptr++;
				continue;
			}

			if (rainptr->life > 240 ||
				abs(CamPos.x - rainptr->x) > 6000 ||
				abs(CamPos.z - rainptr->z) > 6000 )
			{
				rainptr->x = 0;	// Turn it off.
				rainptr++;
				continue;
			}

			rainptr->x += rainptr->xv + (SmokeWindX<<2);
			rainptr->y += rainptr->yv<<3;
			rainptr->z += rainptr->zv + (SmokeWindZ<<2);

			randval = GetRandomDraw();
			if ((randval&3) != 3)
			{
				rainptr->xv += (randval&3)-1;
				if (rainptr->xv < -4)
					rainptr->xv = -4;
				else if (rainptr->xv > 4)
					rainptr->xv = 4;
			}

			randval = (randval>>2)&3;
			if (randval != 3)
			{
				rainptr->zv += randval-1;
				if (rainptr->zv < -4)
					rainptr->zv = -4;
				else if (rainptr->zv > 4)
					rainptr->zv = 4;
			}

			rainptr->life-=2;
			if (rainptr->life>240)
				rainptr->x = 0;
		}
		rainptr++;
	}

	mPushMatrix();
	mTranslateAbsXYZ(lara_item->pos.x_pos,lara_item->pos.y_pos,lara_item->pos.z_pos);

	lineg2=(LINE_G2*) db.polyptr;

	rainptr = &raindrops[0];

	for ( lp=0 ; lp<MAX_SNOWFLAKES ; lp++ )
	{
		if (db.polyptr >= db.polybuf_limit)
		{
			mPopMatrix();
			return;
		}

		if (rainptr->x == 0)	// Not triggered?
		{
			rainptr++;
			continue;
		}

		TempMesh[X] = rainptr->x-(SmokeWindX<<2)-lara_item->pos.x_pos;
		TempMesh[Y] = rainptr->y-(rainptr->yv<<3)-lara_item->pos.y_pos;
		TempMesh[Z] = rainptr->z-(SmokeWindZ<<2)-lara_item->pos.z_pos;

	  	gte_ldv0(TempMesh);
		TempMesh[X] = rainptr->x-lara_item->pos.x_pos;
		gte_rtps();
		TempMesh[Y] = rainptr->y-lara_item->pos.y_pos;
		gte_stsxy(scrxy);
		gte_stsz(scrz);
		TempMesh[Z] = rainptr->z-lara_item->pos.z_pos;

	  	gte_ldv0(TempMesh);
		gte_rtps();
		scrxy+=2;
		scrz++;
		gte_stsxy(scrxy);
		gte_stsz(scrz);
		scrxy-=2;
		scrz--;

		if ((*scrz) > 16384 || (*scrz) < 32 ||
			scrxy[X] < -32 ||
			scrxy[X] > 512+32 ||
			scrxy[Y] < -64 ||
			scrxy[Y] > 256+64)
		{
			rainptr++;
			continue;
		}

		lineg2 = (LINE_G2 *)db.polyptr;
		setlen(lineg2, 4);
		setcode(lineg2, 0x52);
		setRGB0(lineg2,0,0,0);
		setRGB1(lineg2,48,64,64);
		setXY2(lineg2,scrxy[X],scrxy[Y],scrxy[X+2],scrxy[Y+2]);
		MyaddPrim(db.ot, (*scrz)>>3, lineg2);
		lineg2++;
		db.polyptr = (char *)lineg2;

		if (db.polyptr >= db.polybuf_limit)
		{
			mPopMatrix();
			return;
		}

		setDrawTPage((DR_TPAGE *)db.polyptr, 0, 1, getTPage(0, 1, 0, 0));
		MyaddPrim(db.ot, (*scrz)>>3, (DR_TPAGE *)db.polyptr);
		db.polyptr += sizeof(DR_TPAGE);

		rainptr++;
	}

	mPopMatrix();
}
#endif
