
/*
#include "global.h"
#include "debris.h"
#include "map_draw.h"
#include "puzzles.h"
#include "debris.h"
#include "maths.h"
#include "overlays.h"
#include "main.h"
*/

#include "global.h"
#include "debris.h"
#include "main.h" 
#include "map_view.h"
#include "collide.h"
#include "maths.h"
#include "platform.h"
#include "main.h"
#include "inventory.h"
#include "enemies.h"
#include "charactr.h"
#include "map_play.h"
#include "puzzles.h"
#include "camera.h"
#include "deth.h"
#include "card.h"



extern void textureRemoveCLUT16(USHORT clut);
void debrisNewGravySplash(VECTOR *pos);

int debriszscale = 1;

TextureType	*dustTex[7];
TextureType	*ripple;
TextureType	*buble;
TextureType	*bubleSmall;

TextureType	*gravy;
TextureType	*gravySmall;


DEBRISSTR *debris;
DEBRISSTR *active_debris = NULL;
DEBRISSTR *free_debris = NULL;

USHORT debrisAlphaClut = 0;

void debrisKillAll()
{
	int i;

	active_debris = NULL;
	free_debris = &debris[0];
	for(i = 0; i < MAX_DEBRIS-1; i++)
	{
		debris[i].next = &debris[i+1];
	}
	debris[i].next = NULL;
}



void debrisInit()
{
	static USHORT ref_palette[16] =
	{0x8000,0x4210,0x4210,0x4210,	// rgb = 127
	 0x4210,0x4210,0x4210,0x4210,
	 0x4210,0x4210,0x4210,0x4210,
	 0x4210,0x4210,0x4210,0x4210
	};

	debris = MALLOC(MAX_DEBRIS * sizeof(DEBRISSTR));
	debrisKillAll();

	if(!debrisAlphaClut)
	{
		debrisAlphaClut = textureAddCLUT16(&ref_palette[0]);
	}
	// setup pointers to vent/dust textures
	dustTex[0]=textureFindInAllBanks("SMK01");
	dustTex[1]=textureFindInAllBanks("SMK02");
	dustTex[2]=textureFindInAllBanks("SMK03");
	dustTex[3]=textureFindInAllBanks("SMK04");
	dustTex[4]=textureFindInAllBanks("SMK05");
	dustTex[5]=textureFindInAllBanks("SMK06");
	dustTex[6]=textureFindInAllBanks("SMK07");
	ripple=textureFindInAllBanks("WATRIP");

	buble=textureFindInAllBanks("PSXBUB2");	// psxbub02 isn't there !?
	
	//buble=textureFindInAllBanks("GRAVY02");	// psxbub02 isn't there !?
	
	//ASSERT(buble);
	bubleSmall=textureFindInAllBanks("PSXBUB1");	// psxbub01 isn't there !?
	//ASSERT(buble);

	//gravy=textureFindInAllBanks("GRDRIP01");
	gravy=textureFindInAllBanks("GRAVTEST");
	gravySmall=textureFindInAllBanks("GRDRIP02");

	DEBRISDISTANCE = 5000;

}
void debrisFree()
{
	FREE(debris);
	debris = NULL;
	textureRemoveCLUT16(debrisAlphaClut);

	debrisAlphaClut = 0;
}


void debrisKill(DEBRISSTR *debris, DEBRISSTR **prev)
{
	*prev = debris->next;
	debris->next = free_debris;
	debris->type = 0;
	free_debris = debris;
}

//DJH... keep this as a variable as it needs to be longer in the subgames
//DJH... debrisInit() sets it back to 5000 so if you change it you don't need to change it back
//DJH... I'm presuming that	debrisInit gets called everytime a new level is loaded
int	DEBRISDISTANCE = 5000;


//int	testColour=0x60001C40;

#ifdef DREAMCAST
VECTOR gravypos[3] = {
				{4300,-2816,64792,-1700},
				{5325,-4131,59899,-3250},
				{-280,-6047,61009,-4900},
				};
#else
VECTOR gravypos[3] = {
				{4343,-2816,64792,-1600},
				{5325,-4131,59899,-3200},
				{-280,-6047,61009,-4800},
				};
#endif
void	cogChaseGravy(void)
{
DEBRISSTR *deb;
	//DB("gravy squirt\n");

int		i;

//	DB(":");

	if ( (loop_ticker2%2) ) return;

//	DB(";");

	for (i=0;i<3;i++)
	{	
		//deb = debrisNew( pos, buble, 300);
		// Ok the problem here is that we run out of slots very quickly
		if (camVars.targetEnemy->pos.vy > (gravypos[i].pad-1000) && camVars.targetEnemy->pos.vy < (gravypos[i].pad+1000) )
		{
			deb = debrisNew( &gravypos[i], gravy, 300);
			if(deb)
			{
				deb->size = 512 + utilRandomInt(256); // lets go for a realy big bugger
				deb->dy=60;
				deb->dx=-3 + utilRandomInt(6);
				deb->dz=-3 + utilRandomInt(6);

				deb->colour=0xff001C40;

				deb->gravity=3;
				deb->flags.whole=DEB_MOVING;
				deb->type = DEBRIS_GRAVY;
				deb->fade_start = 0; // gravy does not fade
				//deb->special.gravy.height = -1624;	// y for splash
				deb->special.gravy.height = gravypos[i].pad;
			}
			else return;
		}
	}

}

DEBRISSTR *debrisNew(VECTOR *pos, TextureType *spr, int lifetime)
{
	DEBRISSTR *deb;
	//VECTOR	temp;
	short	x,z,x1,z1;

	if(!free_debris)
	{
// scan through active debris & find the oldest
		return NULL;
	}

/*
  	gte_SetRotMatrix(&GsWSMATRIX);
  	gte_SetTransMatrix(&GsWSMATRIX);
// note - prehist boss's smoke needs to be seen from the far end of the level
// 2000 ain't enough, so let's try 2500
	if(level == SPACEBOSS2 || level == PREHISTORICBOSS)
	{
		if(!RadiusCheck4096(pos, (20<<12), 5000))
			return NULL;
	}
	else
	{
		if(!RadiusCheck4096(pos, (20<<12), 2000))
			return NULL;
	}
*/
	//temp.vx=pos->vx-mycamera.vpx;
	//temp.vz=pos->vz-mycamera.vpz;
	//temp.vy=0;

	//DB("vent dist %d\n",Magnitude2D( (pos->vx-mycamera.vpx) , (pos->vz-mycamera.vpz) ) );
	x=mycamera.vpx;
	z=mycamera.vpz;

	x1=pos->vx;
	z1=pos->vz;

	//if (Magnitude2D( (pos->vx-mycamera.vpx) , (pos->vz-mycamera.vpz) )>DEBRISDISTANCE ) return NULL;
	if (Magnitude2D( (x1-x) , (z1-z) )>DEBRISDISTANCE ) return NULL;

	deb = free_debris;
	free_debris = deb->next;

	deb->next = active_debris;
	active_debris = deb;

	//DB("x %d z %d x1 %d z1 %d\n",x,z,x1,z1);

// data to copy over
	deb->x = pos->vx;
	deb->y = pos->vy;
	deb->z = pos->vz;
	deb->spr = spr;
	deb->lifetime = lifetime;
	deb->age_countdown = lifetime;


// rqd default values
	deb->flags.whole = 0;	// which disables most of 'em
	deb->colour = 0x00808080;	// solid, & normal brightness
	deb->size = 256;
	deb->dsize = 0;
//	deb->depthoffset = 0;
	return deb;
}
////////////////////////////////////////////////////////////////////



//	int	x,y,z;
//	int	type;
//	int	decay;
//	int	emit;
//	int	height;

VENT *ventFind(int tag)
{
	int	loop;
	VENT	*current_vent;

	if (!vents) return NULL;	// tbd move this to call place when finished

	current_vent=vents;
	for (loop=0;loop<n_vents;loop++)
	{
		if (tag==current_vent->tag)
			return current_vent;
		current_vent++;
	}
	return NULL;	
}



void	ventProccessAll(void)
{
	int	loop;
	VENT	*current_vent;

	if (!vents) return;	// tbd move this to call place when finished

	current_vent=vents;

	for (loop=0;loop<n_vents;loop++)
	{
		//DB("current_vent->type %d\n",current_vent->type);
		switch(current_vent->type)
		{
			case VENT_STEAM:
				//DB("mod %d\n", loop_ticker%current_vent->emit );
				if ( (loop_ticker%current_vent->emit)==0 && current_vent->flags )
					//debrisNewSteam( (VECTOR*)&current_vent->x,current_vent->decay,current_vent->decay);
					debrisNewSteam(current_vent);
				break;

			case VENT_CANDLE:
				if ( (loop_ticker%current_vent->emit)==0 && current_vent->flags )
					//debrisNewCandle( (VECTOR*)&current_vent->x,current_vent->decay,current_vent->decay);
					debrisNewCandle(current_vent);
				break;

			case VENT_WATER:
				if ( (loop_ticker%current_vent->emit)==0 && current_vent->flags )
					//debrisNewWater( (VECTOR*)&current_vent->x,(VECTOR*)&current_vent->vx,current_vent->decay,current_vent->height);
					debrisNewWater(current_vent);
				break;

			case VENT_GRAVY:
				if ( (loop_ticker%current_vent->emit)==0 && current_vent->flags )
					//debrisNewGravy( (VECTOR*)&current_vent->x,(VECTOR*)&current_vent->vx,current_vent->decay,current_vent->height);
					debrisNewGravy(current_vent);
				break;
		}
		current_vent++;
	}
}
////////////////////////////////////////////////////////////////////
void debrisCycle()
{
	DEBRISSTR *deb;
	DEBRISSTR **prev;
	int temp;

	if (levinfo->level_number==LEVNUMBER_A2_COGCHASE)
	{
		if (PuzzleVars.variables[3]) cogChaseGravy();
	}

	for(prev = (&active_debris); (deb = (*prev)) != 0; )
	{
		switch(deb->type)
		{
		case DEBRIS_DUST:
			temp=(7*deb->age_countdown)/deb->lifetime;
			switch (temp)
			{
				case 1:
					deb->spr = dustTex[6];
					break;
				case 2:
					deb->spr = dustTex[5];
					break;
				case 3:
					deb->spr = dustTex[4];
					break;
				case 4:
					deb->spr = dustTex[3];
					break;
				case 5:
					deb->spr = dustTex[2];
					break;
				case 6:
					deb->spr = dustTex[1];
					break;
			}
			break;

		case DEBRIS_SMOKE:
			deb->flags.whole = DEB_SELFALPHA;
			deb->y-=4;
			deb->special.smoke.rot1+=deb->special.smoke.rot1speed;
			deb->special.smoke.rot2+=deb->special.smoke.rot2speed;

			deb->size+=4;
			break;


		case DEBRIS_STEAM:
			//deb->flags.whole|= DEB_SELFALPHA;
			deb->x += deb->dx>>4; // This may go wrong with -ve numbers
			deb->y += deb->dy;
			deb->z += deb->dz>>4;

			deb->dx=(deb->dx*98)/100;
			deb->dz=(deb->dz*98)/100;

			deb->flags.whole|= DEB_TRUEALPHA;
			//deb->y-=4*3;
			deb->special.smoke.rot1+=deb->special.smoke.rot1speed;

			//deb->special.smoke.rot2+=deb->special.smoke.rot2speed;

			//if (deb->size<256) deb->size+=16;
			deb->size+=2;

			temp=(4*deb->age_countdown)/deb->lifetime;

			switch (temp)
			{
				case 3:
					//deb->spr = textureFindInAllBanks("SMK02");
					deb->spr = dustTex[1];
					break;
				case 2:
					//deb->spr = textureFindInAllBanks("SMK03");
					deb->spr = dustTex[2];
					break;
				case 1:
					//deb->spr = textureFindInAllBanks("SMK04");
					deb->spr = dustTex[3];
					break;
			}
			break;

		case DEBRIS_CANDLE:
			deb->x += deb->dx>>4; // This may go wrong with -ve numbers
			deb->y += deb->dy;
			deb->z += deb->dz>>4;

			deb->dx=(deb->dx*98)/100;
			deb->dz=(deb->dz*98)/100;

			deb->flags.whole|= DEB_TRUEALPHA;
			//deb->y-=4;
			deb->special.smoke.rot1+=deb->special.smoke.rot1speed;
			//deb->size-=2;

			temp=(4*deb->age_countdown)/deb->lifetime;

			switch (temp)
			{
				case 1:
					//deb->spr = textureFindInAllBanks("SMK02");
					deb->spr = dustTex[1];
					break;
				case 2:
					//deb->spr = textureFindInAllBanks("SMK03");
					deb->spr = dustTex[2];
					break;
				case 3:
					//deb->spr = textureFindInAllBanks("SMK04");
					deb->spr = dustTex[3];
					break;
			}
			//textureFindInAllBanks("SMK01");
			break;


		case DEBRIS_GRAVY:

			//if (characterVars.pMainChar->pEnemy->readData.pActor->position.vx==99) DB("test\n");
		case DEBRIS_WATER:
			deb->flags.whole|= DEB_SELFALPHA;
			{
				VECTOR	temp1;
				temp1.vx=deb->dx;
				temp1.vz=deb->dz;
				RotateVector2D(&temp1,&temp1,((2048-camVars.camAngle)+2048)&4095);
				deb->special.gravy.rot=calc_angle( (temp1.vx),-deb->dy)&4095;
			}
			//deb->special.gravy.rot=calc_angle( (deb->dx+deb->dz),-deb->dy)&4095;
			break;
		
		case DEBRIS_GRAVYCHILD:
		case DEBRIS_WATERCHILD:
			deb->flags.whole|= DEB_SELFALPHA;
			{
				VECTOR	temp1;
				temp1.vx=deb->dx;
				temp1.vz=deb->dz;
				RotateVector2D(&temp1,&temp1,((2048-camVars.camAngle)+2048)&4095);
				deb->special.gravy.rot=calc_angle( (temp1.vx),-deb->dy)&4095;
			}

				//deb->special.gravy.rot=calc_angle( (deb->dx+deb->dz),-deb->dy)&4095;


			if (deb->y>deb->special.gravy.height) 
			{
				deb->age_countdown=1;
			}
			break;

		case DEBRIS_GENERIC_WATER:
		//	deb->x += deb->dx;
		//	deb->y += deb->dy;
		//	deb->z += deb->dz;

		case DEBRIS_SPLASH:
			deb->flags.whole|= DEB_SELFALPHA;
			break;


		default:
			DB("Bad debris type\n");
			ASSERT(0);
		}

		if(deb->flags.whole)
		{

			if(deb->flags.part.change_pos)
			{
				deb->x += deb->dx;
				deb->y += deb->dy;
				deb->z += deb->dz;
				deb->dy += deb->gravity;
				if (deb->type==DEBRIS_GRAVY || deb->type==DEBRIS_WATER)
				{
					if (deb->y>deb->special.gravy.height) 
					{
						int loop;
						VECTOR	pos;
						pos.vx=deb->x;
						pos.vy=deb->y;
						pos.vz=deb->z;
						pos.pad=deb->size;
						if ( deb->type==DEBRIS_GRAVY )
						{
							debrisNewGravySplash(&pos);
						}
						else
						{
							debrisNewWaterSplash(&pos);
						}
						for (loop=0;loop<8;loop++)
						{
							VECTOR	vel;
							VECTOR	pos;

							//deb->y=deb->special.gravy.height;

							pos.vx=deb->x;
							pos.vy=deb->special.gravy.height;
							pos.vz=deb->z;
							pos.pad=deb->size;

							vel.vx= utilRandomInt(16)-8;
							vel.vz= utilRandomInt(16)-8;
							vel.vy=-40;
							if ( deb->type==DEBRIS_GRAVY )
							{
								DEBRISSTR *ch;
								ch = debrisNewGravyChild( &pos,&vel,100,deb->special.gravy.height);
								if(ch)
								{
									ch->colour = deb->colour;
								}
							}
							else
							{
								debrisNewWaterChild( &pos,&vel,100,deb->special.gravy.height);
							}
						}
						deb->age_countdown=1;
					}
				}
				/*else if (deb->type==DEBRIS_GRAVYCHILD)
				{
					if (deb->y>deb->special.gravy.height) 
					{
						int loop;
						VECTOR	pos;
						pos.vx=deb->x;
						pos.vy=deb->y;
						pos.vz=deb->z;
						debrisNewWaterSplash(&pos);
						deb->age_countdown=1;
					}
				}*/
			}
			if(deb->flags.part.change_col)
			{
				if(deb->age_countdown < deb->fade_start)
				{
					int r1;
					int r2;
					int t;
					unsigned int bgr;

// when age_count = fade_start, colour = colour1
// when age_count = 0, colour = colour2
					r1 = (deb->colour1 & 0xff);
					r2 = (deb->colour2 & 0xff);
					bgr = r2 + (r1 - r2) * deb->age_countdown / deb->fade_start;
					r1 = (deb->colour1 >> 8) & 0xff;
					r2 = (deb->colour2 >> 8) & 0xff;
					t = r2 + (r1 - r2) * deb->age_countdown / deb->fade_start;
					bgr |= (t<<8);
					r1 = (deb->colour1 >>16) & 0xff;
					r2 = (deb->colour2 >>16) & 0xff;
					t = r2 + (r1 - r2) * deb->age_countdown / deb->fade_start;
					bgr |= (t<<16);
					r1 = (deb->colour1 >>24) & 0xff;
					r2 = (deb->colour2 >>24) & 0xff;
					t = r2 + (r1 - r2) * deb->age_countdown / deb->fade_start;
					bgr |= (t<<24);
					deb->colour = bgr;
				}
			}
		}

		deb->size += deb->dsize;

		deb->age_countdown--;
		if(!deb->age_countdown)
		{
			debrisKill(deb,prev);	// in which case "prev" remains the same
		}
		else
		{
			prev = &deb->next;
		}
	}
}

int	testswitch=0;

void debrisDraw()
{
	DEBRISSTR *deb;
	VERT vect;
	unsigned int colour;
	int r,g,b;
	TextureType	*spr;

  	gte_SetRotMatrix(&GsWSMATRIX);
  	gte_SetTransMatrix(&GsWSMATRIX);

// this time, we can whistle through the list, coz none of 'em are going to vanish
	for(deb = active_debris; deb; deb = deb->next)
	{
		vect.vx = deb->x-mapCamData.gameCam.vpx;
		vect.vy = deb->y-mapCamData.gameCam.vpy;
		vect.vz = deb->z-mapCamData.gameCam.vpz;

		spr = deb->spr;
		if(deb->flags.part.animating)
		{
			if(deb->age_countdown < deb->fade_start)
			{
				spr = (spr + deb->anim_frames -1)
					- deb->anim_frames * deb->age_countdown / deb->fade_start;
			}
		}

		if(deb->type == DEBRIS_SMOKE || deb->type==DEBRIS_STEAM || deb->type==DEBRIS_CANDLE)
		{
			int colour;

			if (deb->age_countdown < deb->fade_start)
			{
				int r,g,b,d;
				d = ((256*deb->age_countdown)/deb->fade_start);
				if ( (deb->lifetime-deb->age_countdown)<10)
				{
					int	t;
					t=((deb->lifetime-deb->age_countdown))*25;
					if (t<d) d=t;
				}
				r = deb->colour & 0xff;
				g = (deb->colour >> 8) & 0xff;
				b = (deb->colour >> 16) & 0xff;

				r = (r*d)>>8;
				g = (g*d)>>8;
				b = (b*d)>>8;

				colour = r|(g<<8)|(b<<16);
			}
			else if ( (deb->lifetime-deb->age_countdown)<10)
			{
				int r,g,b,d = 0,t;

				t=((deb->lifetime-deb->age_countdown))*25;
				if (t<d) d=t;
				r = deb->colour & 0xff;
				g = (deb->colour >> 8) & 0xff;
				b = (deb->colour >> 16) & 0xff;

				//r = (r*d)/255;
				//g = (g*d)/255;
				//b = (b*d)/255;
				r = (r*d)>>8;
				g = (g*d)>>8;
				b = (b*d)>>8;

				colour = r|(g<<8)|(b<<16);
			}
			else
			{
				colour = deb->colour;
			}

			if(colour)
			{	
				//if (testswitch==0)
					Print3DPaletteAlphaSpriteRot(spr,&vect, deb->size, colour, deb->special.smoke.rot1&4095);	// go with this one
				//else if (testswitch==1)
				//	Print3DSelfAlphaSpriteRot(spr,	&vect, deb->size, colour, deb->special.smoke.rot1&4095);
				//else if (testswitch==2)
				//	Print3DPaletteAlphaSprite(spr,&vect, deb->size, colour);


				//Print3DPaletteAlphaSprite(spr,&vect, deb->size, colour);	// go with this one



				//Print3DSelfAlphaSpriteRot(spr,	&vect, deb->size, colour, deb->special.smoke.rot1&4095);
				//Print3DSelfAlphaSpriteRot(spr,	&vect, deb->size, colour, deb->special.smoke.rot2&4095);
			}
		}
		else if (deb->type==DEBRIS_GRAVY || deb->type==DEBRIS_GRAVYCHILD)
		{
			int colour;

			colour = deb->colour;

			if(colour)
			{
				Print3DSelfAlphaSpriteRot(spr,	&vect, deb->size, colour, deb->special.gravy.rot&4095);
			}
		}
		else if (deb->type==DEBRIS_SPLASH)
		{
			int colour;//,colour1;
			VECTOR	vecs[4];
			int dist,alp;
			int r,g,b,d;

			dist=150-(deb->age_countdown*2);
			colour = deb->colour;

			//alp=140-(deb->age_countdown*4);
			//colour=(colour&0xffffff)+(alp<<24);
			d=(deb->age_countdown*4);

			r = deb->colour & 0xff;
			g = (deb->colour >> 8) & 0xff;
			b = (deb->colour >> 16) & 0xff;

			r = (r*d)>>8;
			g = (g*d)>>8;
			b = (b*d)>>8;

			colour = r|(g<<8)|(b<<16);

			//d=(r+g+b)/3;
			//colour1= d|(d<<8)|(d<<16);

			vecs[0].vx=deb->x+dist;
			vecs[0].vy=deb->y;
			vecs[0].vz=deb->z+dist;

			vecs[1].vx=deb->x-dist;
			vecs[1].vy=deb->y;
			vecs[1].vz=deb->z+dist;

			vecs[3].vx=deb->x-dist;
			vecs[3].vy=deb->y;
			vecs[3].vz=deb->z-dist;

			vecs[2].vx=deb->x+dist;
			vecs[2].vy=deb->y;
			vecs[2].vz=deb->z-dist;

			//overlayAlphaPoly(deb->spr, &vecs[0], 4, colour, 1);
			overlayAlphaPoly(deb->spr, &vecs[0], 4, colour, 0);
		}
		else if (deb->type==DEBRIS_GENERIC_WATER)
		{
			int colour;
			VECTOR	vecs[4];
			int dist,alp;
			int r,g,b,d;

			//dist=deb->100-(deb->age_countdown*2);
			colour = deb->colour;

			//alp=140-(deb->age_countdown*4);
			//colour=(colour&0xffffff)+(alp<<24);
			d=(deb->age_countdown*4);

			r = deb->colour & 0xff;
			g = (deb->colour >> 8) & 0xff;
			b = (deb->colour >> 16) & 0xff;

			r = (r*d)>>8;
			g = (g*d)>>8;
			b = (b*d)>>8;

			colour = r|(g<<8)|(b<<16);

			vecs[0].vx=deb->x+deb->size;
			vecs[0].vy=deb->y;
			vecs[0].vz=deb->z+deb->size;

			vecs[1].vx=deb->x-deb->size;
			vecs[1].vy=deb->y;
			vecs[1].vz=deb->z+deb->size;

			vecs[3].vx=deb->x-deb->size;
			vecs[3].vy=deb->y;
			vecs[3].vz=deb->z-deb->size;

			vecs[2].vx=deb->x+deb->size;
			vecs[2].vy=deb->y;
			vecs[2].vz=deb->z-deb->size;

			overlayAlphaPoly(deb->spr, &vecs[0], 4, colour, 0);
		}
		else
		{
			switch(deb->flags.part.transp_type)
			{
// Normal - plot spr +ve/-ve/semi/solid from the high byte of colour
			case 0:
				Print3DSprite(spr,	&vect, deb->size, deb->colour);
				break;
// Grey-sprite alpha. Double-plot the sprite grey-subtractive, colour-additive
			case 1:
				Print3DSelfAlphaSprite(spr,	&vect, deb->size, deb->colour);
				break;
// Colour alpha. Double-plot the sprite white-palette subtractive, colour additive
			case 2:
				Print3DPaletteAlphaSprite(spr,	&vect, deb->size, deb->colour);
				break;
// Two-Sprite. Plot a subtractive alpha sprite & an additive coloured one.
			case 3:
				Print3DAlphaChannelSprite(spr,	deb->spr+deb->anim_frames,&vect, deb->size, deb->colour);
				break;
			}
		}
	}
}

/**********************************************************************************/
void debrisNewWaterSplash(VECTOR *pos)
{
	DEBRISSTR *deb;
	//TextureType *tex;

	//tex = textureFindInAllBanks("SPLAB01");	
	//tex = textureFindInAllBanks("WATRIP");

	deb = debrisNew(pos, ripple, 35);
	if(!deb)
		return;

	deb->size=pos->pad;	// null pointer fix - rfw 15 aug 00
	deb->dx = deb->dy = deb->dz = 0;

	deb->type = DEBRIS_SPLASH;
	deb->colour=0x59725A;
//	pD->fade_start = fadeStart;

}


/**********************************************************************************/
void debrisNewGenericWaterSplash(TextureType *tex, VECTOR *pos, int sizeStart, int sizeSpeed, int lifetime)
{
	DEBRISSTR *deb;
	//TextureType *tex;

	//tex = textureFindInAllBanks("SPLAB01");	
	//tex = textureFindInAllBanks("WATRIP");

//	deb = debrisNew(pos, ripple, 45);
	deb = debrisNew(pos, tex, lifetime);
	if(!deb)
		return;

	deb->type = DEBRIS_GENERIC_WATER;
	deb->colour=0x808080;
	deb->size = sizeStart;
	deb->dsize = sizeSpeed;

//	pD->fade_start = fadeStart;

}



/**********************************************************************************/
void debrisNewGravySplash(VECTOR *pos)
{
	DEBRISSTR *deb;
	//TextureType *tex;

	//tex = textureFindInAllBanks("SPLAB01");	
	//tex = textureFindInAllBanks("WATRIP");

	deb = debrisNew(pos, ripple, 35);
	if(!deb)
		return;

	deb->size=pos->pad;	// null pointer fix - rfw 15 aug 00
	deb->type = DEBRIS_SPLASH;

//	deb->colour=0x0064c8;
	deb->colour=0x003264;

//	deb->colour=0x60001C40;

//	pD->fade_start = fadeStart;

}

/**********************************************************************************/
DEBRISSTR *debrisDust(VECTOR *pos, short lifeTime ,short size)
{
	DEBRISSTR *deb;
	TextureType *tex;

	//tex = textureFindInAllBanks("SMK04");	
	//ASSERT(tex);

	deb = debrisNew(pos,dustTex[0] , lifeTime);

	if(!deb)
		return NULL;

	deb->type = DEBRIS_DUST;
	if (size) deb->size=size;
	//pD->fade_start = fadeStart;
	deb->flags.whole = DEB_SELFALPHA;
	return deb;
}

/**********************************************************************************/
void debrisNewSmoke(VECTOR *pPos, TextureType *pT, short fadeStart, short lifeTime)
{
	DEBRISSTR *pD;
	pD = debrisNew(pPos, pT, lifeTime);

	if(!pD)
		return;

	pD->type = DEBRIS_SMOKE;
	pD->fade_start = fadeStart;
	pD->special.smoke.rot1speed = 16+utilRandomInt(32);
	pD->special.smoke.rot2speed = -(16+utilRandomInt(32));
}
/**********************************************************************************/

//void debrisNewCandle(VECTOR *pPos, short fadeStart, short lifeTime)
void debrisNewCandle(VENTHANDLE	vent)
{
	DEBRISSTR *deb;
//	TextureType *tex;
	//tex = textureFindInAllBanks("SMK04");	
	//ASSERT(tex);

	deb = debrisNew( (VECTOR*)&vent->x, dustTex[3], vent->decay);

	if(!deb)
		return;

	deb->type = DEBRIS_CANDLE;
	deb->fade_start = vent->decay;

	deb->size=(deb->size*vent->scale)>>4;
	deb->dy=-((3*vent->scale)>>4);
	deb->dy+=vent->vy;
	deb->dx=vent->vx;
	deb->dz=vent->vz;

	deb->special.smoke.rot1speed = 16+utilRandomInt(32);
	deb->special.smoke.rot2speed = -(16+utilRandomInt(32));

}

/**********************************************************************************/
void debrisNewSmoke2(VECTOR *pPos, short fadeStart, short lifeTime)
{

}

/**********************************************************************************/
//void debrisNewSteam(VECTOR *pPos, short fadeStart, short lifeTime)
void debrisNewSteam(VENT	*vent)
{
	DEBRISSTR *deb;
	//TextureType *tex;

	//tex = textureFindInAllBanks("SMK04");	
	//ASSERT(tex);

	//deb = debrisNew(pPos, dustTex[3], lifeTime);
	deb = debrisNew( (VECTOR*)&vent->x, dustTex[3], vent->decay);

	if(!deb)
		return;

	deb->type = DEBRIS_STEAM;
	deb->fade_start = vent->decay;
	//deb->size*=4;
	deb->size=(deb->size*vent->scale)>>4;

	deb->dy=-((3*vent->scale)>>4);
	deb->dy+=vent->vy;
	deb->dx=vent->vx;
	deb->dz=vent->vz;

	deb->special.smoke.rot1speed = 32-utilRandomInt(64);
	deb->special.smoke.rot1=utilRandomInt(4096);
	deb->colour=0xffffffff;
}


/**********************************************************************************/
//void debrisNewGravy(VECTOR *pPos, VECTOR *vel, short lifeTime ,short height)
void debrisNewGravy(VENT	*vent)
{
	DEBRISSTR *deb;
//	TextureType *tex;
//	tex = textureFindInAllBanks("PSXBUB02");	
//	ASSERT(tex);

	//deb = debrisNew(pPos, tex, lifeTime);

	//deb = debrisNew( (VECTOR*)&vent->x, buble, vent->decay);
	deb = debrisNew( (VECTOR*)&vent->x, gravy, vent->decay);

	if(!deb)
		return;

	deb->size=(deb->size*vent->scale)>>4;
	//deb->dy=-((4*vent->scale)>>4);
	deb->dy=vent->vy;
	deb->dx=vent->vx;
	deb->dz=vent->vz;

	deb->gravity=5;

	deb->flags.whole=DEB_MOVING;

	deb->type = DEBRIS_GRAVY;
	deb->fade_start = vent->decay; // gravy does not fade
	deb->special.gravy.height=-(vent->height*8);
}

/**********************************************************************************/
//void debrisNewWater(VECTOR *pPos, VECTOR *vel, short lifeTime ,short height)
void debrisNewWater(VENT	*vent)
{
	DEBRISSTR *deb;
//	TextureType *tex;
//	tex = textureFindInAllBanks("PSXBUB02");
//	ASSERT(tex);

//	deb = debrisNew(pPos, tex, lifeTime);
	deb = debrisNew( (VECTOR*)&vent->x, buble, vent->decay);

	if(!deb)
		return;

	deb->size=(deb->size*vent->scale)>>4;
	//deb->dy=-((4*vent->scale)>>4);
	deb->dy=vent->vy;
	deb->dx=vent->vx;
	deb->dz=vent->vz;

	deb->gravity=5;

	deb->flags.whole=DEB_MOVING;

	deb->type = DEBRIS_WATER;
	deb->fade_start = vent->decay; // gravy does not fade
	deb->special.gravy.height=-(vent->height*8);
}


/**********************************************************************************/
//void debrisNewGravy(VECTOR *pPos, TextureType *pT, short fadeStart, short lifeTime ,short height)
//int	tempScale=1;

DEBRISSTR * debrisNewGravyChild(VECTOR *pPos, VECTOR *vel, short lifeTime ,short height)
{
	DEBRISSTR *deb;
	TextureType *tex;

//	DB("gravy child called\n");

	//tex = bubleSmall;	// (don't repeatedly re-find) textureFindInAllBanks("PSXBUB1");		// 01 doesn't exist

	if (levinfo->level_number==LEVNUMBER_A2_COGCHASE )
	{
		pPos->pad=pPos->pad>>2;
		tex=gravy;
	}
	else tex=gravySmall;
	ASSERT(tex);


	pPos->vy=height-1;

	deb = debrisNew(pPos, tex, lifeTime);
	if(!deb)
		return NULL;

	deb->size=pPos->pad*2;	// null pointer fix - rfw 15 aug 00
	deb->dx=vel->vx;
	deb->dy=vel->vy;
	deb->dz=vel->vz;
	deb->gravity=5;
	deb->flags.whole=DEB_MOVING;

	//deb->size=deb->size/5;

	deb->type = DEBRIS_GRAVYCHILD;
	deb->fade_start = lifeTime; // gravy does not fade
	deb->special.gravy.height=height;
	return deb;
}

/**********************************************************************************/
void debrisNewWaterChild(VECTOR *pPos, VECTOR *vel, short lifeTime ,short height)
{
	DEBRISSTR *deb;
	TextureType *tex;

//	tex = textureFindInAllBanks("PSXBUB01");	
	tex = bubleSmall;	// (don't repeatedly re-find) textureFindInAllBanks("PSXBUB1");		// 01 doesn't exist
	ASSERT(tex);

	pPos->vy=height-1;

	deb = debrisNew(pPos, tex, lifeTime);
	if(!deb)
		return;

	deb->size=pPos->pad;	// null pointer fix - rfw 15 aug 00
	deb->dx=vel->vx;
	deb->dy=vel->vy;
	deb->dz=vel->vz;
	deb->gravity=5;
	deb->flags.whole=DEB_MOVING;

	//deb->size=deb->size/5;

	deb->type = DEBRIS_WATERCHILD;
	deb->fade_start = lifeTime; // gravy does not fade
	deb->special.gravy.height=height;
}

/**********************************************************************************/
// returns psx-style bgr
// hex = 0...5, dist = 0...255, pastel = 0...127
unsigned int effectsGetPrimary(int hex, int dist, int pastel)
{
	int r,g,b;
	int antipastel = 127-pastel;

	switch(hex)
	{
	case 0:	// fade green up
		r = 127;
		g = pastel + ((dist * antipastel) >> 8);
		b = pastel;
		break;

	case 1:	// fade red out
		r = pastel + (((256-dist) * antipastel)>>8);
		g = 127;
		b = pastel;
		break;

	case 2:	// fade blue up
		r = pastel;
		g = 127;
		b = pastel + ((dist * antipastel) >> 8);
		break;

	case 3:	// fade green out
		r = pastel;
		g = pastel + (((256-dist) * antipastel)>>8);
		b = 127;
		break;

	case 4:	// fade red up
		r = pastel + ((dist * antipastel) >> 8);
		g = pastel;
		b = 127;
		break;

//	case 5:	// fade blue out
	default:
		r = 127;
		g = pastel;
		b = pastel + (((256-dist) * antipastel)>>8);
		break;
	}
	return ((b<<16) | (g<<8) | (r));
}

/*************************************************************************/

unsigned int effectsColourNear(unsigned int bgr, int range)
{
	int r,g,b;
	r = (bgr & 0xff);
	g = (bgr>>8)& 0xff;
	b = (bgr>>16)& 0xff;
	r += random(range<<1) - range;
	g += random(range<<1) - range;
	b += random(range<<1) - range;
	if(r < 0) r = 0;
	if(g < 0) g = 0;
	if(b < 0) b = 0;
	if(r > 127) r = 127;
	if(g > 127) g = 127;
	if(b > 127) b = 127;
	return ( (b<<16)|(g<<8)|r);

}

// Normal playstation colouring modes sprite

int Print3DSprite(TextureType *spr,VERT *vect,SHORT scale, unsigned long colour)
{
	POLY_FT4 *si;
	LONG spritez;

	LONG		width;
	LONG		height;
	LONG distancescale;

#ifdef DREAMCAST 
	int			ow,oh;
	
	ow = spr->w;
	oh = spr->h;
	spr->w = spr->u1 - spr->u0;
	spr->h = spr->v2 - spr->v0;
#endif
	BEGINPRIM(si, POLY_FT4);

// scary scaling-and-transform-in-one-go code from the Action Man people...
	width = (spr->w);
	gte_SetLDDQB(0);			// clear offset control reg (C2_DQB)
	gte_ldv0(vect)	;//vert);
	gte_SetLDDQA(width);		// shove sprite width into control reg (C2_DQA)
	gte_rtps();				// do the rtps
	gte_stsxy(&si->x0);	//scrxy);		// get screen x and y
	gte_stszotz(&spritez);	//depth);		// get order table z
// end of scaling-and-transform




	if(spritez < 20)
	{
#ifdef DREAMCAST
		spr->w = ow;
		spr->h = oh;
#endif
		return 0;
	}
#ifndef DREAMCAST
	if(spritez >= (1024<<3))
		spritez = (1024<<3)-1;
#endif

	gte_stopz(&distancescale);		// get scaled width of sprite
	distancescale >>= 16;

	width = (distancescale * scale) >> 8;

	if(width < 3)
	{
#ifdef DREAMCAST
		spr->w = ow;
		spr->h = oh;
#endif
 		return 0;	// better max-distance check
	}
 	si->x1=si->x3=si->x0+width;
 	si->x0=si->x2=si->x0-width;
#ifdef DREAMCAST	
	if ((si->x1<0) || (si->x0>640)) 
	{
		spr->w = ow;
		spr->h = oh;
		return 0;
	}
#else
   	if (si->x1<-256) return 0;
   	if (si->x0>256) return 0;
#endif

	if(spr->w == spr->h)
		height = width;
	else
		height = width * spr->h / spr->w;

	si->y2=si->y3=si->y0+height;
	si->y1=si->y0=si->y0-height;
#ifdef DREAMCAST	
	spr->w = ow;
	spr->h = oh;
	
	if (si->y2< 0) return 0;
   	if (si->y0> 480) return 0;
#else
   	if (si->y2< -128) return 0;
   	if (si->y0> 128) return 0;
#endif
// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	if( ! (colour & 0xF0000000) )
	{
		*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
							  | (((unsigned long)(spr->tpage)) <<16);
		*(ULONG*)&si->r0 = colour | (GPU_COM_TF4<<24);
#ifdef DREAMCAST
			si->tag = SEMITRANS_NONE;
#endif
	}
	else
	{
		*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
							  | (((unsigned long)(spr->tpage)) <<16)
							  | ((colour >> 8) & 0x00600000);
		*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);
#ifdef DREAMCAST
			si->tag = SEMITRANS_ADD;
#endif
	}

#ifdef DREAMCAST
	si->tpage = spr->tpage;
	si->code = GPU_COM_TF4;
	ENDPRIM(si, (spritez*16), POLY_FT4);
#else
	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy
	ENDPRIM(si, (spritez >> 3), POLY_FT4);
#endif

	return 1;
}

// Normal playstation colouring modes sprite

int Print3DSpriteFlipped(TextureType *spr,VERT *vect,SHORT scale, unsigned long colour)
{
	POLY_FT4 *si;
	LONG spritez;

	LONG		width;
	LONG		height;
	LONG distancescale;

	
	BEGINPRIM(si, POLY_FT4);

// scary scaling-and-transform-in-one-go code from the Action Man people...
	width = (spr->w);
	gte_SetLDDQB(0);			// clear offset control reg (C2_DQB)
	gte_ldv0(vect)	;//vert);
	gte_SetLDDQA(width);		// shove sprite width into control reg (C2_DQA)
	gte_rtps();				// do the rtps
	gte_stsxy(&si->x0);	//scrxy);		// get screen x and y
	gte_stszotz(&spritez);	//depth);		// get order table z
// end of scaling-and-transform




	if(spritez < 20) return 0;

	if(spritez >= (1024<<3))
		spritez = (1024<<3)-1;


	gte_stopz(&distancescale);		// get scaled width of sprite
	distancescale >>= 16;

	width = (distancescale * scale) >> 8;

	if(width < 3)
		return 0;	// better max-distance check

 	si->x1=si->x3=si->x0+width;
 	si->x0=si->x2=si->x0-width;
#ifdef DREAMCAST
	if (si->x1<0) return 0;
   	if (si->x0>640) return 0;
#else
   	if (si->x1<-256) return 0;
   	if (si->x0>256) return 0;
#endif

	if(spr->w == spr->h)
		height = width;
	else
		height = width * spr->h / spr->w;

	si->y2=si->y3=si->y0+height;
	si->y1=si->y0=si->y0-height;
#ifdef DREAMCAST
	if (si->y2<0) return 0;
   	if (si->y0>480) return 0;
#else
   	if (si->y2< -128) return 0;
   	if (si->y0> 128) return 0;
#endif
// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u1)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u3);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u2);

	if( ! (colour & 0xF0000000) )
	{
		*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u0)
							  | (((unsigned long)(spr->tpage)) <<16);
		*(ULONG*)&si->r0 = colour | (GPU_COM_TF4<<24);
	}
	else
	{
		*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u0)
							  | (((unsigned long)(spr->tpage)) <<16)
							  | ((colour >> 8) & 0x00600000);
		*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);
	}

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy
#ifdef DREAMCAST
	ENDPRIM(si, (spritez *16), POLY_FT4);
#else
	ENDPRIM(si, (spritez >> 3), POLY_FT4);
#endif
	return 1;
}
// Self-mask transparancy sprite
// (Assumed to be a greyscale sprite which you want displayed in pretty colours, with
// a greyscale subtracted version of itself used as alpha)

int Print3DSelfAlphaSprite(TextureType *spr,VERT *vect,SHORT scale, unsigned long colour)
{
	return Print3DSelfAlphaSpriteRot(spr, vect, scale, colour, 0);
}

int Print3DSelfAlphaSpriteRot(TextureType *spr,VERT *vect,SHORT scale, unsigned long colour, short rot)
{
	POLY_FT4 *si;
	LONG	spritez;

	LONG	width;
	LONG	height;
	LONG	distancescale;
	int		alp;

	int		x,y;

	BEGINPRIM(si, POLY_FT4);

// scary scaling-and-transform-in-one-go code from the Action Man people...
#ifdef DREAMCAST
	width = (spr->u1 - spr->u0)*1.25;
#else
	width = (spr->w);
#endif

/*
#ifdef _WINDOWS
	gte_ldv0(vect);			//vert);
	gte_rtps();				// do the rtps
	gte_stsxy(&si->x0);		//scrxy);		// get screen x and y
	gte_stszotz(&spritez);	//depth);		// get order table z
#else
*/
	gte_SetLDDQB(0);			// clear offset control reg (C2_DQB)
	gte_ldv0(vect);				//vert);
	gte_SetLDDQA(width);		// shove sprite width into control reg (C2_DQA)
	gte_rtps();					// do the rtps
	gte_stsxy(&si->x0);			//scrxy);		// get screen x and y
	gte_stszotz(&spritez);		//depth);		// get order table z
// end of scaling-and-transform
// CPW: #endif

	x = si->x0;
	y = si->y0;

	if(spritez < 20) return 0;

#ifndef DREAMCAST
	if(spritez >= (1024<<3))
		spritez = (1024<<3)-1;
#endif
	// Theres something very odd going on here on ocation sprites behind/off camera are appering mid screen
	// apperars to happen on big sprites

	gte_stopz(&distancescale);		// get scaled width of sprite
	distancescale >>= 16;

	width = (distancescale * scale) >> 8;

// ** JS : Cludge for scale bug thingy FIXIT
//	if(width < 3)
//		return 0;	// better max-distance check

#if defined(DREAMCAST)
	if((spr->u1 - spr->u0) == (spr->v1 - spr->v2))
		height = width;
	else
		height = width * (spr->v1 - spr->v2) / (spr->u1 - spr->u0);
#else
	if(spr->w == spr->h)
		height = width;
	else
		height = width * spr->h / spr->w;
#endif

	if(rot == 0)
	{
#ifdef DREAMCAST
 		si->x1=si->x3=si->x0-width;
		si->x0=si->x2=si->x0+width;
		if (si->x1<0) return 0;
		if (si->x0>640) return 0;
#else
 		si->x1=si->x3=si->x0+width;
		si->x0=si->x2=si->x0-width;
		if (si->x1<-256) return 0;
		if (si->x0>256) return 0;
#endif

		si->y2=si->y3=si->y0+height;
		si->y1=si->y0=si->y0-height;

#ifdef DREAMCAST
		if (si->y2< 0) return 0;
   		if (si->y0> 480) return 0;
#else
   		if (si->y2< -128) return 0;
   		if (si->y0> 128) return 0;
#endif
	}
	else
	{
		int		sin1,cos1,sin2,cos2;
#ifdef DREAMCAST
		rot-=512+1024;
#else
		rot-=512;
#endif

		height*=2;
		width*=2;

		sin1=(rsin(rot)*width)/4096;
		cos1=(rcos(rot)*height)/4096;
		sin2=cos1;
		cos2=-sin1;
		si->x0=x + sin1;
		si->y0=y - cos1;
		si->x1=x + sin2;
		si->y1=y - cos2;
		si->x2=x + (-sin2);
		si->y2=y - (-cos2);
		si->x3=x + (-sin1);
		si->y3=y - (-cos1);
	}

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy

#ifdef DREAMCAST
	si->tpage = spr->tpage;
	si->code = GPU_COM_TF4;
	si->tag = SEMITRANS_ADD;
#endif

	si[1] = si[0];
	
#ifdef DREAMCAST
	ENDPRIM(si, (spritez*debriszscale + depthBump), POLY_FT4);

	BEGINPRIM(si, POLY_FT4);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;
	si->tpage = spr->tpage;
	si->code = GPU_COM_TF4;
	si->tag = SEMITRANS_SUB;

	ENDPRIM(si, ((spritez+20) * debriszscale + depthBump), POLY_FT4);

	si++;
#else
	ENDPRIM(si, (spritez >> 3), POLY_FT4);
// Self-Alpha transparancy

	BEGINPRIM(si, POLY_FT4);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;
	si->tpage = spr->tpage |((SEMITRANS_SUB-1)<<5);

	ENDPRIM(si, (spritez >> 3), POLY_FT4);

	si++;
#endif

	return 1;
}



// White-mask transparancy sprite
// (Alpha is itself, with a white-paletted version used as subtractive alpha effect)

int Print3DPaletteAlphaSprite(TextureType *spr,VERT *vect,SHORT scale, unsigned long colour)
{
	POLY_FT4 *si;
	LONG spritez;

	LONG		width;
	LONG		height;
	LONG distancescale;
	int alp;

	
	BEGINPRIM(si, POLY_FT4);

// scary scaling-and-transform-in-one-go code from the Action Man people...
	width = (spr->w);
	gte_SetLDDQB(0);			// clear offset control reg (C2_DQB)
	gte_ldv0(vect)	;//vert);
	gte_SetLDDQA(width);		// shove sprite width into control reg (C2_DQA)
	gte_rtps();				// do the rtps
	gte_stsxy(&si->x0);	//scrxy);		// get screen x and y
	gte_stszotz(&spritez);	//depth);		// get order table z
// end of scaling-and-transform

	if(spritez < 20) return 0;

	if(spritez >= (1024<<3))
		spritez = (1024<<3)-1;

	gte_stopz(&distancescale);		// get scaled width of sprite
	distancescale >>= 16;

	width = (distancescale * scale) >> 8;

	if(width < 3)
		return 0;	// better max-distance check

 	si->x1=si->x3=si->x0+width;
 	si->x0=si->x2=si->x0-width;
#ifdef DREAMCAST
   	if (si->x1<0) return 0;
   	if (si->x0>640) return 0;
#else
   	if (si->x1<-256) return 0;
   	if (si->x0>256) return 0;
#endif

	if(spr->w == spr->h)
		height = width;
	else
		height = width * spr->h / spr->w;

	si->y2=si->y3=si->y0+height;
	si->y1=si->y0=si->y0-height;
#ifdef DREAMCAST
	if (si->y2< 0) return 0;
   	if (si->y0> 480) return 0;
#else
   	if (si->y2< -128) return 0;
   	if (si->y0> 128) return 0;
#endif
	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy

	si[1] = si[0];
	
	ENDPRIM(si, (spritez >> 3), POLY_FT4);

// Alpha-clut transparancy

	BEGINPRIM(si, POLY_FT4);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;
	si->tpage = spr->tpage |((SEMITRANS_SUB-1)<<5);

	si->clut = debrisAlphaClut;
	ENDPRIM(si, (spritez >> 3), POLY_FT4);

	si++;

	return 1;
}


// Separate alpha-channel transparancy sprite

int Print3DAlphaChannelSprite(TextureType *spr,TextureType *sprM,VERT *vect,SHORT scale, unsigned long colour)
{
	POLY_FT4 *si;
	LONG spritez;

	LONG		width;
	LONG		height;
	LONG distancescale;
	int alp;

	
	BEGINPRIM(si, POLY_FT4);

// scary scaling-and-transform-in-one-go code from the Action Man people...
	width = (spr->w);
	gte_SetLDDQB(0);			// clear offset control reg (C2_DQB)
	gte_ldv0(vect)	;//vert);
	gte_SetLDDQA(width);		// shove sprite width into control reg (C2_DQA)
	gte_rtps();				// do the rtps
	gte_stsxy(&si->x0);	//scrxy);		// get screen x and y
	gte_stszotz(&spritez);	//depth);		// get order table z
// end of scaling-and-transform


	if(spritez < 20) return 0;

	if(spritez >= (1024<<3))
		spritez = (1024<<3)-1;


	gte_stopz(&distancescale);		// get scaled width of sprite
	distancescale >>= 16;

	width = (distancescale * scale) >> 8;

	if(width < 3)
		return 0;	// better max-distance check

 	si->x1=si->x3=si->x0+width;
 	si->x0=si->x2=si->x0-width;
#ifdef DREAMCAST
   	if (si->x1<0) return 0;
   	if (si->x0>640) return 0;
#else
   	if (si->x1<-256) return 0;
   	if (si->x0>256) return 0;
#endif



	if(spr->w == spr->h)
		height = width;
	else
		height = width * spr->h / spr->w;

	si->y2=si->y3=si->y0+height;
	si->y1=si->y0=si->y0-height;
#ifdef DREAMCAST
	if (si->y2< 0) return 0;
   	if (si->y0> 480) return 0;
#else
   	if (si->y2< -128) return 0;
   	if (si->y0> 128) return 0;
#endif

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy

	si[1] = si[0];
	
	ENDPRIM(si, (spritez >> 3), POLY_FT4);

// Alpha-channel transparancy

	spr = sprM;
	BEGINPRIM(si, POLY_FT4);

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_SUB-1) << (16+5));

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;

	ENDPRIM(si, (spritez >> 3), POLY_FT4);

	si++;

	return 1;
}
int Print3DPaletteAlphaSpriteRot(TextureType *spr,VERT *vect,SHORT scale, unsigned long colour, short rot)
{
	POLY_FT4 *si;
	LONG spritez;

	LONG		width;
	LONG		height;
	LONG distancescale;
	int alp;
	int		x,y;
#ifdef DREAMCAST
	int		ow,oh;

	ow = spr->w;
	oh = spr->h;
	spr->w = spr->u1 - spr->u0;
	spr->h = spr->v2 - spr->v0;
#endif
	BEGINPRIM(si, POLY_FT4);

// scary scaling-and-transform-in-one-go code from the Action Man people...
	width = (spr->w);
	gte_SetLDDQB(0);			// clear offset control reg (C2_DQB)
	gte_ldv0(vect)	;//vert);
	gte_SetLDDQA(width);		// shove sprite width into control reg (C2_DQA)
	gte_rtps();				// do the rtps
	gte_stsxy(&si->x0);	//scrxy);		// get screen x and y
	gte_stszotz(&spritez);	//depth);		// get order table z
// end of scaling-and-transform

	if(spritez < 20) 
	{
#ifdef DREAMCAST
		spr->w = ow;
		spr->h = oh;
#endif
		return 0;
	}
  
#ifndef DREAMCAST
	if(spritez >= (1024<<3))
		spritez = (1024<<3)-1;
#endif
	gte_stopz(&distancescale);		// get scaled width of sprite
	distancescale >>= 16;

	width = (distancescale * scale) >> 8;

	if(width < 3)
	{
#ifdef DREAMCAST
		spr->w = ow;
		spr->h = oh;
#endif
		return 0;	// better max-distance check
	}
 	//si->x1=si->x3=si->x0+width;
 	//si->x0=si->x2=si->x0-width;
   	//if (si->x1<-256) return 0;
   	//if (si->x0>256) return 0;


	if(spr->w == spr->h)
		height = width;
	else
		height = width * spr->h / spr->w;

	//si->y2=si->y3=si->y0+height;
	//si->y1=si->y0=si->y0-height;
   	//if (si->y2< -128) return 0;
   	//if (si->y0> 128) return 0;


	if(rot == 0)
	{
 		si->x1=si->x3=si->x0+width;
		si->x0=si->x2=si->x0-width;
#ifdef DREAMCAST
	  	if ((si->x1<0) || (si->x0>640))
		{
		spr->w = ow;
		spr->h = oh;
		return 0;
		}
#else
	  	if (si->x1<-256) return 0;
	  	if (si->x0>256) return 0;
#endif


		si->y2=si->y3=si->y0+height;
		si->y1=si->y0=si->y0-height;
#ifdef DREAMCAST
		if ((si->y2< 0) || (si->y0> 480))
		{
			spr->w = ow;
			spr->h = oh;
			return 0;
		}
#else
	  	if (si->y2< -128) return 0;
	  	if (si->y0> 128) return 0;
#endif
	}
	else
	{
		int		sin1,cos1,sin2,cos2;
		rot-=512;
		x = si->x0;
		y = si->y0;
		//height*=2;
		//width*=2;

		sin1=(rsin(rot)*width)/4096;
		cos1=(rcos(rot)*height)/4096;
		sin2=cos1;
		cos2=-sin1;
		si->x0=x + sin1;
		si->y0=y - cos1;
		si->x1=x + sin2;
		si->y1=y - cos2;
		si->x2=x + (-sin2);
		si->y2=y - (-cos2);
		si->x3=x + (-sin1);
		si->y3=y - (-cos1);
	}




	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy

	si[1] = si[0];

#ifdef _WINDOWS
	si->clut = spr->clut;
#endif
	
#ifdef DREAMCAST
	si->tpage = spr->tpage;
	si->code = GPU_COM_TF4;
	si->tag = SEMITRANS_ADD;
	ENDPRIM(si, (spritez *16), POLY_FT4);

	BEGINPRIM(si, POLY_FT4);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;
	si->tpage = spr->tpage;
	si->tag = SEMITRANS_SUB;
	ENDPRIM(si, ((spritez+1) *16), POLY_FT4);

	si++;
#else


#ifndef _WINDOWS
	ENDPRIM(si, (spritez >> 3), POLY_FT4);

// Alpha-clut transparancy

	BEGINPRIM(si, POLY_FT4);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;
	si->tpage = spr->tpage |((SEMITRANS_SUB-1)<<5);

	si->clut = debrisAlphaClut;
	ENDPRIM(si, (spritez >> 3), POLY_FT4);
#else

	ENDPRIM(si, spritez, POLY_FT4);

// Alpha-clut transparancy

	BEGINPRIM(si, POLY_FT4);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;
	si->clut  = spr->clut;
	si->tpage = spr->tpage |((SEMITRANS_SUB-1)<<5);

//	si->clut = debrisAlphaClut;
	
	ENDPRIM(si, spritez, POLY_FT4);


#endif


	si++;
#endif
	return 1;
}
