// Triangle rendering, if any

//
// Modified by MoOg to be more mod coder friendly
//
#include "hud.h"
#include "cl_util.h"

// Triangle rendering apis are in gEngfuncs.pTriAPI

#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "triangleapi.h"
#include "vrml.h"

//added by harSens
#include "com_model.h"
#include "event_api.h"
#include "pmtrace.h"
#include "pm_defs.h"
#include "com_model.h"
#include "studio.h"
#include "dlight.h"

#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <math.h>

#include "studio_util.h"
#include "r_studioint.h"
#include "StudioModelRenderer.h"
#include "GameStudioModelRenderer.h"

// Added by Pcjoe
#include "transformfx.h"
#include "demo_api.h"
#include "camera.h"
// added by Pcjoe
#include "vgui_TeamFortressViewport.h"
#include "vgui_fxtoolpanel.h"
#include "tf_defs.h"

#define TRAIL_HEAD_RATIO 2.5
#define TRAIL_BEAM_RATIO 5.0
#define BEAM_OVERLAP	 0.125
#define SBC_ORBIT_BEAM_RATIO 2.0
#define PI 3.1415926535897932384626433832795
//end harSens add

extern int	g_IsSpectator[MAX_PLAYERS+1];

#define DLLEXPORT __declspec( dllexport )

extern "C"
{
	void DLLEXPORT HUD_DrawNormalTriangles( void );
	void DLLEXPORT HUD_DrawTransparentTriangles( void );
};
/*extern bool gOnlyClientDraw;
#include <gl\gl.h>							
#include <gl\glu.h>							
#include <gl\glaux.h>*/

//Variables added by MoOg
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//Set in view.cpp to the correct view angles (which player->angles doesn't hold)
extern vec3_t v_origin; 

vec3_t v_up, v_right, v_forward; //Defined out here so other areas of code can grab them
void VectorAngles( const float *forward, float *angles );
//added by harSens + Pcjoe
extern HSPRITE g_hsprPowerupFX;		// powerup aura texture
extern HSPRITE g_hsprPowerupDust1;	// Dust for powerup
extern HSPRITE g_hsprPowerupDust2;	// Dust for powerup
extern HSPRITE g_hsprPowerupWater1;	// Water splashes for powerup
extern HSPRITE g_hsprPowerupWater2;
extern HSPRITE g_hsprPowerupRipple1;// Ripples
extern HSPRITE g_hsprPowerupRipple2;
extern HSPRITE g_hsprPowerupRock1;	// Floating Rocks
extern HSPRITE g_hsprPowerupRock2;
extern HSPRITE g_hsprPowerupRock3;
extern HSPRITE g_hsprPowerupRock4;
extern HSPRITE g_hsprPowerupRock5;
extern HSPRITE g_hsprPowerupAura;	// aura particle
extern HSPRITE g_hsprWhite;			// Used for Triangle over head
extern HSPRITE g_hsprLighting;		// Lighting...
extern HSPRITE g_hsprMeleeFlash1;	// Cliding sprite for melee battles
extern HSPRITE g_hsprMeleeFlash2;
extern HSPRITE g_hsprAuraVRML;
extern HSPRITE g_hsprLighting;
extern HSPRITE g_hsprRockVRML;
extern HSPRITE g_hsprAuraWhiteVRML;
extern HSPRITE g_hsprBlack;
extern CGameStudioModelRenderer g_StudioRenderer;
extern CMouseCapture g_MouseCap;

VRMLData *gVRMLSphere;
extern VRMLData gVRMLExplosion;
extern VRMLData gVRMLSphereLow;
extern VRMLData gVRMLSphereHigh;
extern VRMLData gVRMLAura;
extern VRMLData gVRMLAura2;
extern VRMLData gVRMLPowerupAura;
extern VRMLData gVRMLLowAura;
extern VRMLData gVRMLRock;

//beamhead by david
//extern VRMLData gVRMLBeamhead;
/* removed by harSens
extern VRMLData gVRMLDiamond;
*/
extern cvar_t *cl_beamquality;

extern int g_BoundingboxEnts[255];
extern int g_iNumberOfBoundingBoxEnts;

// added by Pcjoe
extern int g_MaxParticles;		// Max Dust particles per ring
extern int g_MaxParticleGroup;	// Max Ring Particles
extern int g_MaxRipples;		// Max ripple Particles
extern int g_MaxRocks;			// Max Rock Particles
extern int g_MaxAura;			// Max Aura Particles
extern float g_flRotationDiamond;// used to rotate diamond
// Added by Pcjoe, acouple CVARS/varibles for rendering
extern cvar_t *cl_3drocks;
extern cvar_t *cl_fxquality;
extern cvar_t *cam_idealdist;
extern cvar_t *cl_drawdiamonds;
extern vec3_t g_CamAngles;
extern vec3_t g_CamOrigin;
extern vec3_t v_origin;
extern int cam_thirdperson;
extern int cam_idealview;

// Big FX structs
extern powerupfx *g_PoweringupList;
extern part_manager_s *pPartJobs;				// Transform FX

// Added by Pcjoe
#include "r_studioint.h"
extern engine_studio_api_t IEngineStudio;

// added by Pcjoe
//extern shockwave *tri_shock;
extern explosion *pBlobExp;
using namespace std;
extern explosion *tri_exp;
extern list <sbc_trail> g_SBCTrails;
extern list <ent_ent_trail> g_EntEntTrails;
extern list <flare> g_Flares;
//extern int charge_sb;

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=


/*
=================
Draw_Triangles

Example routine.  Draws a sprite 100 units in front of the player
=================
*/

/**
* Draw Box
*/
void Draw_Box( HSPRITE sprite, int iRenderMode, vec3_t vecMax, vec3_t vecMin )
{	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), 0 ))
	{	return;
	}
	
	Vector temporg;
	
	/*
	gEngfuncs.pTriAPI->RenderMode( kRenderTransAlpha );
	*/
	gEngfuncs.pTriAPI->RenderMode( iRenderMode );
	gEngfuncs.pTriAPI->Color4ub(255,255,255,255);
	gEngfuncs.pTriAPI->CullFace( TRI_NONE );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	
	//front face
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = Vector(vecMin.x, vecMin.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = Vector(vecMin.x, vecMax.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = Vector(vecMin.x, vecMax.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = Vector(vecMin.x, vecMin.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	//back face
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = Vector(vecMax.x, vecMin.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = Vector(vecMax.x, vecMax.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = Vector(vecMax.x, vecMax.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = Vector(vecMax.x, vecMin.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	//left face
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = Vector(vecMin.x, vecMin.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = Vector(vecMax.x, vecMin.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = Vector(vecMax.x, vecMin.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = Vector(vecMin.x, vecMin.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	//right face
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = Vector(vecMin.x, vecMax.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = Vector(vecMax.x, vecMax.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = Vector(vecMax.x, vecMax.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = Vector(vecMin.x, vecMax.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	//up face
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = Vector(vecMin.x, vecMin.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = Vector(vecMax.x, vecMin.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = Vector(vecMax.x, vecMax.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = Vector(vecMin.x, vecMax.y, vecMin.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	//down face
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = Vector(vecMin.x, vecMin.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = Vector(vecMax.x, vecMin.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = Vector(vecMax.x, vecMax.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = Vector(vecMin.x, vecMax.y, vecMax.z);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );	

	gEngfuncs.pTriAPI->End();	
}

/**
* Draws the bounding box around something (used for debugging)
* cl_entity_t *pClient: the entity to draw the boundinbox around
*/
void Draw_BBox( cl_entity_t *pClient)
{	// Edited by Pcjoe, moved generic code to draw box function so we can draw more than bounding boxes
	Vector vecOrigin = pClient->origin;
	Draw_Box( LoadSprite("sprites/bbox_add.spr"), kRenderTransAdd, pClient->curstate.maxs+vecOrigin, pClient->curstate.mins+vecOrigin );
}

void Draw_Fog(int r,int g, int b,float start, float end)
{
	gEngfuncs.pTriAPI->Fog(Vector(r,g,b), start, end, TRUE ); //Works just like GL_FOG, flFogColor is r/g/b.
}

/* Joe's code, disabled by harSens
int iCurVertexVRML = 0;
*/
void DrawVRMLiSprite (const VRMLData &info,vec3_t pos, int sprite, int rendermode, TRICULLSTYLE tricullstyle, int frame, int r, int g, int b, int a)
{	
	if ( !gEngfuncs.pTriAPI->SpriteTexture( IEngineStudio.GetModelByIndex(sprite), frame))
	{	ConsolePrint("Can't find texture sprite\n");
		return;
	}
	DrawVRML(info,pos,rendermode,tricullstyle,r,g,b,a);
}

// Return High quality sphere or low quality sphere
void setSphere()
{
	if(cl_fxquality->value == LOW_QUALITY_FX)
	{
		gVRMLSphere = &gVRMLSphereLow;
	}
	else
	{
		gVRMLSphere = &gVRMLSphereHigh;
	}
}

vec3_t GetCamPos()
{	return v_origin;
}

/*
void Draw_WorldSprite( HSPRITE sprite, vec3_t pos, float size, int RenderMode, float r, float g, float b )
void Draw_WorldSprite( HSPRITE sprite, vec3_t pos, float size, int RenderMode,int r,int g, int b, int a, int frame)
*/
void Draw_WorldSprite( HSPRITE sprite, vec3_t pos, float size, int RenderMode, TRICULLSTYLE tricullstyle,int r,int g, int b, int a, int frame)
{
	vec3_t temporg;

	size *=0.5;
	/* modified by harSens
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), 0 ))
	*/
	
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), frame ))
	{
		return;
	}
	// Create a triangle, sigh
	
	gEngfuncs.pTriAPI->RenderMode( RenderMode );
	gEngfuncs.pTriAPI->CullFace( tricullstyle );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	// Overload p->color with index into tracer palette, p->packedColor with brightness
	/* modified by harSens
	gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 );
	*/
	gEngfuncs.pTriAPI->Color4ub(r,g,b,a);
	
	// UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2)
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = pos + (v_right * size) + (v_up * size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );	
	temporg = pos + (v_right * size) + (v_up * -size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );	
	temporg = pos + (v_right * -size) + (v_up * -size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = pos + (v_right * -size) + (v_up * size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );
		
	gEngfuncs.pTriAPI->End();	
	gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
}

void Draw_WorldSpriteEnt(int sprite, vec3_t pos, float size, int RenderMode, TRICULLSTYLE tricullstyle,int r,int g, int b, int a, int frame)
{
	vec3_t temporg;

	size *=0.5;
	/* modified by harSens
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), 0 ))
	*/
	
	if ( !gEngfuncs.pTriAPI->SpriteTexture( IEngineStudio.GetModelByIndex(sprite), frame))
	{	ConsolePrint("Can't find texture sprite\n");
		return;
	}
	// Create a triangle, sigh
	
	gEngfuncs.pTriAPI->RenderMode( RenderMode );
	gEngfuncs.pTriAPI->CullFace( tricullstyle );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	// Overload p->color with index into tracer palette, p->packedColor with brightness
	/* modified by harSens
	gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 );
	*/
	gEngfuncs.pTriAPI->Color4ub(r,g,b,a);
	
	// UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2)
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = pos + (v_right * size) + (v_up * size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );	
	temporg = pos + (v_right * size) + (v_up * -size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );	
	temporg = pos + (v_right * -size) + (v_up * -size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = pos + (v_right * -size) + (v_up * size);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );
		
	gEngfuncs.pTriAPI->End();	
	gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
}

// Added by Pcjoe, used to draw lighting strikes
void Draw_LightingSprite( HSPRITE sprite, vec3_t vecPos, vec3_t vecPosEnd, int size, int r, int b, int g, int a, int frame )
{
	vec3_t temporg;

	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), frame ))
	{
		return;
	}
	
	// Used so Rain sprites wont bend on the Z axis
	vec3_t v_LightUp = v_up;
	vec3_t v_LightRight = v_right;
	v_LightUp.z = 1;
	v_LightRight.z = 0; 
	
	// Create lighting strike
	gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
	gEngfuncs.pTriAPI->CullFace( TRI_FRONT );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	gEngfuncs.pTriAPI->Color4ub(r,g,b,a);
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = vecPosEnd + (v_LightRight * (size/2)) + (v_LightUp);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = vecPos + (v_LightRight * (size/2)) + (v_LightUp);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = vecPos + (v_LightRight * (-size/2)) + (v_LightUp);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = vecPosEnd + (v_LightRight * (-size/2)) + (v_LightUp);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->End();
	gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
}

// Added by Pcjoe, who should have a triangle over their head?
/* removed by harSens
void Calc_Triangle( void )
{
	// Your pointer
	cl_entity_t *pPlayer = gEngfuncs.GetLocalPlayer();

	VRMLData vrmlDiamondScaled;

	// Team check
	int iUserTeam = g_PlayerExtraInfo[pPlayer->index].teamnumber;
	if ( iUserTeam < 0 )
	{	iUserTeam = 0;
	}

	// Loop Through all players
	for(int entindex = 0; entindex < MAX_PLAYERS; entindex++)
	{	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(entindex);
		
		// If player isn't valid
		if(!pClient)
		{	continue;
		}

		// If its not a player, dont draw a triangle
		if ( !pClient->player )
		{	continue;
		}

		// Is the player connected or disconnected? Use the powerlevel to figure out
		int iPowerLevel = g_PlayerExtraInfo[entindex].powerlevel;
		if ( iPowerLevel <= 0 )
		{	continue;
		}

		// If the player isnt solid ( Disconnected/gibs ), dont show him
		if(pClient->curstate.solid == SOLID_NOT)
		{	continue;
		}

		//added by harSens: skip spectators/observers
		if (g_IsSpectator[entindex])
		{	continue;
		}

		// Team check
		int iTeam = g_PlayerExtraInfo[entindex].teamnumber;
		if ( iTeam < 0 )
		{	iTeam = 0;
		}

		// Set tris over head
		vec3_t vecOrigin = pClient->origin;
		vecOrigin.z += 25;

		// How far is the player from us?
		Vector2D vecPlayerOrigin = Vector2D(pPlayer->origin.x,pPlayer->origin.y);
		Vector2D vecClientOrigin = Vector2D(pClient->origin.x, pClient->origin.y);

		float flDistance = (vecPlayerOrigin - vecClientOrigin).Length();
		vec3_t vecRotation = vec3_t(0,(int)g_flRotationDiamond,0);

		// If User is on your team, Draw a triangle over his head, unless its you:)
		if(iTeam == iUserTeam && pClient->index != pPlayer->index)
		{	// If its accually Team play, draw the green triangles
			if(gHUD.m_Teamplay)
			{	RotateVRML(vrmlDiamondScaled, gVRMLDiamond, vecRotation);
				ScaleVRML(vrmlDiamondScaled, vrmlDiamondScaled, 1.25);
				DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 0, 255, 0, 255);
			}
			// If its deathmatch, draw the red triangles
			else
			{	// Make sure players are in Dist. Since its DM, we will multiply it by 1.5
				if(flDistance < 1500)
				{
					RotateVRML(vrmlDiamondScaled, gVRMLDiamond, vecRotation);
					ScaleVRML(vrmlDiamondScaled, vrmlDiamondScaled, 1.25);
					DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 255, 0, 0, 255);
				}
			}
		}
		// Draw a tri over a bad guy's head if he is in radar dist
		else if(flDistance < 2000 && pClient->index != pPlayer->index)
		{	RotateVRML(vrmlDiamondScaled, gVRMLDiamond, vecRotation);
			ScaleVRML(vrmlDiamondScaled, vrmlDiamondScaled, 1.25);
			DrawVRML(vrmlDiamondScaled, vecOrigin, g_hsprWhite,kRenderNormal, TRI_NONE, 0, 255, 0, 0, 255);
		}
	}
}
*/
// Added by Pcjoe, used for Ripples
void Draw_RippleSprite( HSPRITE sprite, vec3_t pos, float size, int RenderMode,int r,int g, int b, int a, int frame)
{
	vec3_t temporg;

	/* modified by harSens
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), 0 ))
	*/
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), frame ))
	{
		return;
	}
	
	// Create a triangle, sigh
	gEngfuncs.pTriAPI->RenderMode( RenderMode );
	gEngfuncs.pTriAPI->CullFace( TRI_NONE );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );

	// Ghetto way to draw a flat sprite for the waves:)
	// Overload p->color with index into tracer palette, p->packedColor with brightness
	gEngfuncs.pTriAPI->Color4ub(r,g,b,a);
	// UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2)
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	temporg = pos;
	temporg.x += (size/2);
	temporg.y -= (size/2);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	temporg = pos;
	temporg.x += (size/2);
	temporg.y += (size/2);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	temporg = pos;
	temporg.x -= (size/2);
	temporg.y += (size/2);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	temporg = pos;
	temporg.x -= (size/2);
	temporg.y -= (size/2);
	gEngfuncs.pTriAPI->Vertex3f( temporg.x, temporg.y, temporg.z );

	gEngfuncs.pTriAPI->End();
	gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
}

// added by Pcjoe, used for various powerupfx affects
void DrawParticleAuraFX(aura_particle &pAura, HSPRITE sprite, float a)
{	
	Draw_WorldSprite( sprite, pAura.vecParticleOrigin, pAura.m_flSize, kRenderTransAdd , TRI_FRONT, pAura.r, pAura.g, pAura.b, a, 0 );
}

// added by Pcjoe, used for Aura powerupfx affects
void DrawParticleFX(group_particle &p, parGroup &pGroup, HSPRITE sprite, int size, int r, int g, int b, int a)
{
	// Note - Sprite animations are added in the think function in powerup.cpp
	// If ripple sprite, use a diff drawing functon
	if(sprite == g_hsprPowerupRipple1 || sprite == g_hsprPowerupRipple2)
	{	Draw_RippleSprite( sprite, p.origin, size, kRenderTransAdd , r, g, b, a, pGroup.m_iFrame );
	}
	// Rock particle
	else if( sprite == g_hsprPowerupRock1 || sprite == g_hsprPowerupRock2 || sprite == g_hsprPowerupRock3 || 
			sprite == g_hsprPowerupRock4 || sprite == g_hsprPowerupRock5 )
	{	Draw_WorldSprite( sprite, p.origin, size, kRenderTransTexture , TRI_FRONT, r, g, b, a, pGroup.m_iFrame );
	}
	// Anything else(dust, aura)
	else
	{	Draw_WorldSprite( sprite, p.origin, size, kRenderTransAdd , TRI_FRONT, r, g, b, a, pGroup.m_iFrame );
	}	
}

int iPowerupFrame;
void DrawPowerupFX(powerupfx *pFXEntry, int r, int g, int b)
{
	// Edited by Pcjoe
	// If particles are dying out(disabled by the user), don't still render the cone thing
	if (pFXEntry->enabled)
	{
		VRMLData vrmlScaledPowerupAura;
		cl_entity_t *pClient;
		pClient = gEngfuncs.GetEntityByIndex(pFXEntry->m_iEntIndex);
		Vector origin = pClient->origin;

		// Cycle through frames
		if(iPowerupFrame<SPR_Frames(g_hsprPowerupFX)-1)
		{	iPowerupFrame++;	
		}
		else
		{	iPowerupFrame = 0;
		}

		//draw aura
		ScaleVRML(vrmlScaledPowerupAura, gVRMLPowerupAura, 15);
		DrawVRML(vrmlScaledPowerupAura, origin,	g_hsprPowerupFX,kRenderTransAdd, TRI_FRONT, iPowerupFrame, r,g,b,255);
	}


	// Added by Pcjoe
	// --- Ripples
	int i;
	for(i=0; i < g_MaxRipples; i++)
	{
		// --- Dust/Water Particles
		float flAlpha = pFXEntry->ripplegroup[i].m_flLife;
		
		if(flAlpha > 1.0)
			flAlpha = 1.0;
	
		flAlpha *= 255;
		// If group is dead, don't draw it!
		
		if(flAlpha <= 0)
			continue;

		// Random Sprites, makes it look a little better
		if(pFXEntry->ripplegroup[i].m_iSprite)
		{	DrawParticleFX( pFXEntry->ripplegroup[i].dust[0], pFXEntry->ripplegroup[i], g_hsprPowerupRipple1, pFXEntry->ripplegroup[i].m_iSize, pFXEntry->ripplegroup[i].r, pFXEntry->ripplegroup[i].g, pFXEntry->ripplegroup[i].b, flAlpha);
		}
		else
		{	DrawParticleFX( pFXEntry->ripplegroup[i].dust[0], pFXEntry->ripplegroup[i], g_hsprPowerupRipple2, pFXEntry->ripplegroup[i].m_iSize, pFXEntry->ripplegroup[i].r, pFXEntry->ripplegroup[i].g, pFXEntry->ripplegroup[i].b, flAlpha);
		}
	}

	// --- Dust/Water
	// If there are no particles, don't go through the trouble of looping through all of this
	if(g_MaxParticles)
	{	for(i=0;i<g_MaxParticleGroup;i++)
		{
			float flAlpha = pFXEntry->dustgroup[i].m_flLife;
			if(flAlpha > 1.0)
				flAlpha = 1.0;
			flAlpha *= 255;
			// If group is dead, don't draw it!
			if(flAlpha <= 0)
				continue;

			// Draw each specific particle of the group
			for(int n=0;n<g_MaxParticles; n++)
			{	
				// If particle wasn't sentanced to death on birth(being spawned by the wall for example)
				// don't render!
				if(pFXEntry->dustgroup[i].dust[n].m_blLiving)
				{
					// Dust
					if(pFXEntry->dustgroup[i].m_iSprite == -1)
						DrawParticleFX( pFXEntry->dustgroup[i].dust[n], pFXEntry->dustgroup[i], g_hsprPowerupDust1, pFXEntry->dustgroup[i].m_iSize, pFXEntry->dustgroup[i].r, pFXEntry->dustgroup[i].g, pFXEntry->dustgroup[i].b, flAlpha);
					else if(!pFXEntry->dustgroup[i].m_iSprite)
						DrawParticleFX( pFXEntry->dustgroup[i].dust[n], pFXEntry->dustgroup[i], g_hsprPowerupDust2, pFXEntry->dustgroup[i].m_iSize, pFXEntry->dustgroup[i].r, pFXEntry->dustgroup[i].g, pFXEntry->dustgroup[i].b, flAlpha);
					// Water
					else if(pFXEntry->dustgroup[i].m_iSprite == 1)
					{	DrawParticleFX( pFXEntry->dustgroup[i].dust[n], pFXEntry->dustgroup[i], g_hsprPowerupWater1, pFXEntry->dustgroup[i].m_iSize, pFXEntry->dustgroup[i].r, pFXEntry->dustgroup[i].g, pFXEntry->dustgroup[i].b, flAlpha);
					}
					else if(pFXEntry->dustgroup[i].m_iSprite == 2)
					{	DrawParticleFX( pFXEntry->dustgroup[i].dust[n], pFXEntry->dustgroup[i], g_hsprPowerupWater2, pFXEntry->dustgroup[i].m_iSize, pFXEntry->dustgroup[i].r, pFXEntry->dustgroup[i].g, pFXEntry->dustgroup[i].b, flAlpha);
					}
				}
			}
		}
	}
	
	// --- Floating rocks
	// If there are no particles, don't go through the trouble of looping through all of this
	if(g_MaxRocks)
	{	for(i=0;i<g_MaxRocks;i++)
		{
			float flAlpha = pFXEntry->rockgroup[i].m_flLife;

			// If particle is dead, don't draw it!
			if(flAlpha > 0.1)
			{	flAlpha = 1.0;
			}
			else
			{	continue;
			}
			flAlpha *= 225;

			// Draw each specific particle of the group
			int n = 0;
			// If particle wasn't sentanced to death on birth(being spawned by the wall for example)
			// don't render!

			
			if(pFXEntry->rockgroup[i].rock[n].m_blLiving)
			{
				// 3d rocks or sprite rocks, that is the question...
				if(!cl_3drocks->value)
				{
					// Render with random rocks
					if(pFXEntry->rockgroup[i].m_iSprite == 1)
					{	DrawParticleFX( pFXEntry->rockgroup[i].rock[n], pFXEntry->rockgroup[i], g_hsprPowerupRock1, pFXEntry->rockgroup[i].m_iSize, pFXEntry->rockgroup[i].r, pFXEntry->rockgroup[i].g, pFXEntry->rockgroup[i].b, flAlpha);
					}
					else if(pFXEntry->rockgroup[i].m_iSprite == 2)
					{	DrawParticleFX( pFXEntry->rockgroup[i].rock[n], pFXEntry->rockgroup[i], g_hsprPowerupRock2, pFXEntry->rockgroup[i].m_iSize, pFXEntry->rockgroup[i].r, pFXEntry->rockgroup[i].g, pFXEntry->rockgroup[i].b, flAlpha);
					}
					else if(pFXEntry->rockgroup[i].m_iSprite == 3)
					{	DrawParticleFX( pFXEntry->rockgroup[i].rock[n], pFXEntry->rockgroup[i], g_hsprPowerupRock3, pFXEntry->rockgroup[i].m_iSize, pFXEntry->rockgroup[i].r, pFXEntry->rockgroup[i].g, pFXEntry->rockgroup[i].b, flAlpha);
					}
					else if(pFXEntry->rockgroup[i].m_iSprite == 4)
					{	DrawParticleFX( pFXEntry->rockgroup[i].rock[n], pFXEntry->rockgroup[i], g_hsprPowerupRock4, pFXEntry->rockgroup[i].m_iSize, pFXEntry->rockgroup[i].r, pFXEntry->rockgroup[i].g, pFXEntry->rockgroup[i].b, flAlpha);
					}
					else
					{	DrawParticleFX( pFXEntry->rockgroup[i].rock[n], pFXEntry->rockgroup[i], g_hsprPowerupRock5, pFXEntry->rockgroup[i].m_iSize, pFXEntry->rockgroup[i].r, pFXEntry->rockgroup[i].g, pFXEntry->rockgroup[i].b, flAlpha);
					}
				}
				// 3d rocks
				else
				{
					// Only render 3d rocks if you are decently close
					cl_entity_t *pPlayer = gEngfuncs.GetLocalPlayer();
					int iDist = (GetCamPos() - pFXEntry->rockgroup[i].rock[n].origin).Length();
					if(iDist <= 700)
					{
						VRMLData vrmlScaledRocks;
						RotateVRML(vrmlScaledRocks, gVRMLRock, pFXEntry->rockgroup[i].rock[n].vecRotation);
						ScaleVRML(vrmlScaledRocks, vrmlScaledRocks, pFXEntry->rockgroup[i].m_iSize*15);
						DrawVRML(vrmlScaledRocks, pFXEntry->rockgroup[i].rock[n].origin
							, g_hsprRockVRML,kRenderTransTexture, TRI_FRONT, 0, 190, 190, 190, 190);
					}
				}
			}
		}
	}

	// --- Aura Particles
	// If there are no particles, don't go through the trouble of looping through all of this
	if(g_MaxAura)
	{	for(i=0;i<g_MaxAura;i++)
		{	float flAlpha = pFXEntry->aura[i].m_flLife;
			if(flAlpha > 0.1)
				flAlpha = 1.0;

			flAlpha *= 255;
			// If particle is dead, don't draw it!
			if(flAlpha <= 0)
				continue;

			// If particle wasn't sentanced to death on birth(being spawned by the wall for example)
			// don't render!
			if(pFXEntry->aura[i].m_flLife)
			{	DrawParticleAuraFX( pFXEntry->aura[i], g_hsprPowerupAura, flAlpha);
		
			}
	}
}
}

void TransformationFX( void )
{
	// Dont allow software mode to run this
	if(!IEngineStudio.IsHardware())
		return;

	// Quality of tranny FX
	int iQuality = cl_fxquality->value;
	// If there is no quality, dont render
	if(!iQuality)
		return;

	if(iQuality > 3)
		iQuality = 3;
	if(iQuality < 1)
		iQuality = 1;

	VRMLData vrmlScaledExplosionTranny;
	VRMLData vrmlScaledShockwave;
	VRMLData vrmlScaledAura;
	VRMLData vrmlScaledAura2;
	VRMLData vrmlScaledLowAura;
//	VRMLData vrmlScaledRocks;
	part_manager_s *pManager = pPartJobs;

	while (pManager)
	{
		if(pManager->blDisplay)
		{

			switch (pManager->m_iFlag)
			{
			case FLASHY_AURA:
			case FLASHY_WHITE_AURA:
				{
					if(!pManager->pParticle)
					{
						pManager = pManager->pNext;
						continue;
					}
					else
					{
						cl_entity_t *pClient = gEngfuncs.GetLocalPlayer();
						cl_entity_t *pEntity = gEngfuncs.GetEntityByIndex( pManager->m_iIndex );

						if(iQuality == LOW_QUALITY_FX)
						{
							RotateVRML(vrmlScaledLowAura, gVRMLLowAura, pManager->pParticle->vecRotation);
							ScaleVRML(vrmlScaledLowAura, vrmlScaledLowAura, pManager->pParticle->flSize);

							if(pManager->m_iFlag == FLASHY_AURA)
								DrawVRML(vrmlScaledLowAura, pEntity->origin,
								g_hsprAuraVRML,kRenderTransAdd, TRI_FRONT, pManager->pParticle->iFrame,
								pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
								pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
							else
								DrawVRML(vrmlScaledLowAura, pEntity->origin,
								g_hsprAuraWhiteVRML,kRenderTransAdd, TRI_FRONT, pManager->pParticle->iFrame,
								pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
								pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
						}
						else
						{
							if(iQuality == MEDIUM_QUALITY_FX || iQuality == HIGH_QUALITY_FX)
							{
								RotateVRML(vrmlScaledAura, gVRMLAura, pManager->pParticle->vecRotation);
								ScaleVRML(vrmlScaledAura, vrmlScaledAura, pManager->pParticle->flSize);

								if(pManager->m_iFlag == FLASHY_AURA)
									DrawVRML(vrmlScaledAura, pEntity->origin,
									g_hsprAuraVRML,kRenderTransAdd, TRI_FRONT, pManager->pParticle->iFrame,
									pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
									pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
								else
									DrawVRML(vrmlScaledAura, pEntity->origin,
									g_hsprAuraWhiteVRML,kRenderTransAdd, TRI_FRONT, pManager->pParticle->iFrame,
									pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
									pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
							}

							if(iQuality == HIGH_QUALITY_FX)
							{
								RotateVRML(vrmlScaledAura2, gVRMLAura2, pManager->pParticle->vecRotation2);
								ScaleVRML(vrmlScaledAura2, vrmlScaledAura2, pManager->pParticle->flSize);

								if(pManager->m_iFlag == FLASHY_AURA)
									DrawVRML(vrmlScaledAura2, pEntity->origin,
									g_hsprAuraVRML,kRenderTransAdd, TRI_FRONT, pManager->pParticle->iFrame,
									pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
									pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
								else
									DrawVRML(vrmlScaledAura2, pEntity->origin,
									g_hsprAuraWhiteVRML,kRenderTransAdd, TRI_FRONT, pManager->pParticle->iFrame,
									pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
									pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);

							}
					}
					break;
				}
			case ROTATE_LGHTING_SPHERE:
			case PURPLE_LGHTING_SPHERE:
			case WHITE_SPHERE:
			case HARD_INNDER_SPHERE:
			case SHOCKWAVE_CORE:
				{
					// Just make sure the particle struct exist before we go rendering it
					if(!pManager->pParticle)
					{
						pManager = pManager->pNext;
						continue;
					}
					else
					{
						cl_entity_t *pClient = gEngfuncs.GetLocalPlayer();
						cl_entity_t *pEntity = gEngfuncs.GetEntityByIndex( pManager->m_iIndex );
						RotateVRML(vrmlScaledExplosionTranny, *gVRMLSphere, pManager->pParticle->vecRotation);
						ScaleVRML(vrmlScaledExplosionTranny, vrmlScaledExplosionTranny, pManager->pParticle->flSize);
						DrawVRML(vrmlScaledExplosionTranny, pEntity->origin,
							g_hsprWhite,kRenderTransAdd, TRI_NONE, pManager->pParticle->iFrame,
							pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
							pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
					}
					break;
				}
			case PINK_SOLID_SPHERE:
				{
					// Just make sure the particle struct exist before we go rendering it
					if(!pManager->pParticle)
					{
						pManager = pManager->pNext;
						continue;
					}
					else
					{
						cl_entity_t *pClient = gEngfuncs.GetLocalPlayer();
						cl_entity_t *pEntity = gEngfuncs.GetEntityByIndex( pManager->m_iIndex );
						//RotateVRML(vrmlScaledExplosionTranny, Sphere(), pManager->pParticle->vecRotation);
						RotateVRML(vrmlScaledExplosionTranny, *gVRMLSphere, pManager->pParticle->vecRotation);
						ScaleVRML(vrmlScaledExplosionTranny, vrmlScaledExplosionTranny, pManager->pParticle->flSize);
						DrawVRML(vrmlScaledExplosionTranny, pEntity->origin,
							g_hsprWhite,kRenderTransAdd, TRI_NONE, pManager->pParticle->iFrame,
							pManager->pParticle->iColor[0], pManager->pParticle->iColor[1],
							pManager->pParticle->iColor[2], pManager->pParticle->iColor[3]);
					}
					break;
				}
			// Draw Slightly differently then the above
			case SHOCKWAVE_FROM_CORE:
			case SHOCKWAVE_FROM_CORE_INVERSE:
			case EXPLOSION_SPHERE:
				{
					// Just make sure the particle struct exist before we go rendering it
					if(!pManager->pParticle)
					{
						pManager = pManager->pNext;
						continue;
					}
					else
					{
						cl_entity_t *pClient = gEngfuncs.GetLocalPlayer();
						cl_entity_t *pEntity = gEngfuncs.GetEntityByIndex( pManager->m_iIndex );
						if(pManager->pParticle->flEnergy != 0)
						{
							float flAlpha = 1.0;
							if(pManager->pParticle->flEnergy < 1.0)
							{
								flAlpha = pManager->pParticle->flEnergy;
							}

							// If its yourself, set the quality to low
						/*	if(pClient->index == pManager->m_iIndex && (pManager->m_iFlag == SHOCKWAVE_FROM_CORE || pManager->m_iFlag == SHOCKWAVE_FROM_CORE_INVERSE))
							{
								if(iQuality == HIGH_QUALITY_FX)
								{
									// Already accounts for low/high qaulity
									//RotateVRML(vrmlScaledShockwave, Sphere(), pManager->pParticle->vecRotation);
									RotateVRML(vrmlScaledShockwave, *gVRMLSphere, pManager->pParticle->vecRotation);
									ScaleVRML(vrmlScaledShockwave, vrmlScaledShockwave, pManager->pParticle->flSize);
									DrawVRML(vrmlScaledShockwave, pEntity->origin,
										g_hsprWhite,kRenderTransAdd, TRI_NONE, pManager->pParticle->iFrame,
										pManager->pParticle->iColor[0]*flAlpha, pManager->pParticle->iColor[1]*flAlpha,
										pManager->pParticle->iColor[2]*flAlpha, pManager->pParticle->iColor[3]*flAlpha);
								}
								else
								{
									// Already accounts for low/high qaulity
									RotateVRML(vrmlScaledShockwave, gVRMLSphereLow, pManager->pParticle->vecRotation);
									ScaleVRML(vrmlScaledShockwave, vrmlScaledShockwave, pManager->pParticle->flSize);
									DrawVRML(vrmlScaledShockwave, pEntity->origin,
										g_hsprWhite,kRenderTransAdd, TRI_NONE, pManager->pParticle->iFrame,
										pManager->pParticle->iColor[0]*flAlpha, pManager->pParticle->iColor[1]*flAlpha,
										pManager->pParticle->iColor[2]*flAlpha, pManager->pParticle->iColor[3]*flAlpha);
								}
							}
							else
							{*/
								// Already accounts for low/high qaulity
								//RotateVRML(vrmlScaledShockwave, Sphere(), pManager->pParticle->vecRotation);
								RotateVRML(vrmlScaledShockwave, *gVRMLSphere, pManager->pParticle->vecRotation);
								ScaleVRML(vrmlScaledShockwave, vrmlScaledShockwave, pManager->pParticle->flSize);
								DrawVRML(vrmlScaledShockwave, pEntity->origin,
									g_hsprWhite,kRenderTransAdd, TRI_NONE, pManager->pParticle->iFrame,
									pManager->pParticle->iColor[0]*flAlpha, pManager->pParticle->iColor[1]*flAlpha,
									pManager->pParticle->iColor[2]*flAlpha, pManager->pParticle->iColor[3]*flAlpha);
						/*	}*/

						}
					}
					break;

				}

			case FLOATING_ROCKS:
				{	
					if(pManager->pPartSys)
					{
						for(int i = 0; i < pManager->pPartSys->iMaxParticles; i++)
						{
							// Only render those with life
							if(pManager->pPartSys->pParticle[i].flEnergy > 0)
							{
								particle_fx pParticle = pManager->pPartSys->pParticle[i];
									// Make sure there arnt too many rocks in 3d, if so, switch back to sprite
								/*	if(cl_3drocks->value)
									{
										// Disable 3d rocks if there are too many VRML polies
										if((int)iCurVertexVRML/3 > 5000)
										{
											cl_3drocks->value = 0;
										}
									}
									// Render with random rocks
									if(!cl_3drocks->value)
									{*/
										switch(pParticle.iSprite)
										{
										default:
										case 1:
											Draw_WorldSprite( g_hsprPowerupRock1, pParticle.vecOrigin, pParticle.flSize, kRenderTransTexture, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3], pParticle.iFrame);
											break;
										case 2:
											Draw_WorldSprite( g_hsprPowerupRock2, pParticle.vecOrigin, pParticle.flSize, kRenderTransTexture, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3], pParticle.iFrame);
											break;
										case 3:
											Draw_WorldSprite( g_hsprPowerupRock3, pParticle.vecOrigin, pParticle.flSize, kRenderTransTexture, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3], pParticle.iFrame);
											break;
										case 4:
											Draw_WorldSprite( g_hsprPowerupRock4, pParticle.vecOrigin, pParticle.flSize, kRenderTransTexture, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3], pParticle.iFrame);
											break;
										case 5:
											Draw_WorldSprite( g_hsprPowerupRock5, pParticle.vecOrigin, pParticle.flSize, kRenderTransTexture, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3], pParticle.iFrame);
											break;
										}
								/*	}
									// 3d rocks
									else
									{
										// Only render 3d rocks if you are decently close
										cl_entity_t *pPlayer = gEngfuncs.GetLocalPlayer();
										int iDist = (GetCamPos() - pParticle.vecOrigin).Length();
										if(iDist <= 700)
										{
											RotateVRML(vrmlScaledRocks, gVRMLRock, pParticle.vecRotation);
											ScaleVRML(vrmlScaledRocks, vrmlScaledRocks, pParticle.flSize*15);
											DrawVRML(vrmlScaledRocks, pParticle.vecOrigin
												, g_hsprRockVRML,kRenderTransTexture, 0, 190, 190, 190, 190);
										}
									}*/
								}
								
							}
						}
					}
					break;
				}
			case DUST:
			case COLUMN_DUST:
			case ROTATING_DUST:
			case EXPANDED_DUST:
			case STEAM_HEAD:
			case DUSTTRAIL:
			case STEAM:
				{	
					if(pManager->pPartSys)
					{
						for(int i = 0; i < pManager->pPartSys->iMaxParticles; i++)
						{
							// Only render those with life
							if(pManager->pPartSys->pParticle[i].flEnergy > 0)
							{
								particle_fx pParticle = pManager->pPartSys->pParticle[i];
								float flAlpha = pManager->pPartSys->pParticle[i].flEnergy;
								if(flAlpha > 1.0)
									flAlpha = 1.0;

								// Render Sprites

								// Dust
								if(pParticle.iSprite == -1)
									Draw_WorldSprite( g_hsprPowerupDust1, pParticle.vecOrigin, pParticle.flSize, kRenderTransAdd, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3] * flAlpha, pParticle.iFrame);
								else if(!pParticle.iSprite)
									Draw_WorldSprite( g_hsprPowerupDust2, pParticle.vecOrigin, pParticle.flSize, kRenderTransAdd, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3] * flAlpha, pParticle.iFrame);
								// Water
								else if(pParticle.iSprite == 1)
									Draw_WorldSprite( g_hsprPowerupWater1, pParticle.vecOrigin, pParticle.flSize, kRenderTransAdd, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3] * flAlpha, pParticle.iFrame);
								else
									Draw_WorldSprite( g_hsprPowerupWater2, pParticle.vecOrigin, pParticle.flSize, kRenderTransAdd, TRI_FRONT, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3] * flAlpha, pParticle.iFrame);
							}
						}
					}
					break;
				}
			case LIGHTING:
				{
					if(pManager->pPartSys)
					{
						for(int i = 0; i < pManager->pPartSys->iMaxParticles; i++)
						{
							// Only render those with life
							if(pManager->pPartSys->pParticle[i].flEnergy)
							{
								particle_fx pParticle = pManager->pPartSys->pParticle[i];
								Draw_LightingSprite( g_hsprLighting , pParticle.vecOrigin, pParticle.vecOrigin2, pParticle.flSize, pParticle.iColor[0], pParticle.iColor[1], pParticle.iColor[2], pParticle.iColor[3], pParticle.iFrame);
							}
						}
					}				
					break;
				}			
			}
		}
	pManager = pManager->pNext;
	}

}

/*
draws a beam part. Assumes: texture initialized, 
Triapi Begin started with squares, startwidth>=endwidth>0
*/
void DrawBeamPart(vec3_t start, vec3_t end, float startwidth,float endwidth)
{	
	float flMiddleWidth = startwidth - (startwidth-endwidth)*0.5;		
	if(endwidth/startwidth < 0.7 && (start-end).Length()>flMiddleWidth)
	{	//split, to avoid uglyness
		vec3_t vecMiddle = start + (end-start)*0.5;
		DrawBeamPart(start, vecMiddle, startwidth, flMiddleWidth);
		DrawBeamPart(vecMiddle,end,flMiddleWidth,endwidth);
	}
	else	
	{
		vec3_t vecPreviousPointLeft = -v_right * startwidth * 0.5 + start;
		vec3_t vecPreviousPointRight = v_right * startwidth * 0.5 + start;
		vec3_t vecPreviousPointDown = -v_up * startwidth * 0.5 + start;
		vec3_t vecPreviousPointUp = v_up * startwidth * 0.5 + start;
		
		
		vec3_t vecPointLeft = -v_right * endwidth * 0.5 + end;
		vec3_t vecPointRight = v_right * endwidth * 0.5 + end;
		vec3_t vecPointDown = -v_up * endwidth * 0.5 + end;
		vec3_t vecPointUp = v_up * endwidth * 0.5 + end;

		gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
		gEngfuncs.pTriAPI->Vertex3f( vecPointLeft.x, vecPointLeft.y, vecPointLeft.z );

		gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
		gEngfuncs.pTriAPI->Vertex3f( vecPreviousPointLeft.x, vecPreviousPointLeft.y, vecPreviousPointLeft.z );
		
		gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
		gEngfuncs.pTriAPI->Vertex3f( vecPreviousPointRight.x, vecPreviousPointRight.y, vecPreviousPointRight.z );

		gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
		gEngfuncs.pTriAPI->Vertex3f( vecPointRight.x, vecPointRight.y, vecPointRight.z );

		gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
		gEngfuncs.pTriAPI->Vertex3fv( vecPointDown);

		gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
		gEngfuncs.pTriAPI->Vertex3fv(vecPreviousPointDown);

		gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
		gEngfuncs.pTriAPI->Vertex3fv(vecPreviousPointUp);

		gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
		gEngfuncs.pTriAPI->Vertex3fv(vecPointUp);	
	}
}
/*
draws a beam part. Assumes: texture initialized, 
Triapi Begin started with squares, startwidth>=endwidth>0
*/
/*
vec3_t DrawBeamPart(vec3_t start, vec3_t end, float startwidth,float endwidth, vec3_t vecStartUp)
{	
	float flMiddleWidth = startwidth - (startwidth-endwidth)*0.5;		
	if(endwidth/startwidth < 0.7 && (start-end).Length()>flMiddleWidth)
	{	//split, to avoid uglyness
		vec3_t vecMiddle = start + (end-start)*0.5;
		vec3_t vecUp = DrawBeamPart(start, vecMiddle, startwidth, flMiddleWidth,vecStartUp);
		return DrawBeamPart(vecMiddle,end,flMiddleWidth,endwidth,vecUp);
	}
	else	
	{
		vec3_t W = start-g_CamOrigin;
		vec3_t U = end-g_CamOrigin;
		double wx=DotProduct(W,v_right);
		double wy=DotProduct(W,v_up);
		double ux=DotProduct(U,v_right);
		double uy=DotProduct(U,v_up);
		
		Vector2D onPlane = Vector2D(ux-wx,uy-wy);
		
		//if(onPlane.Length()<0.5)
		//{
		//	return vec3_t(0,0,0);
		//}
		
		Vector2D Q=Vector2D(uy-wy,wx-ux);
		Vector2D q=Q.Normalize();
		vec3_t vecUp = q.x*v_right+q.y*v_up;
		vecUp=vecUp.Normalize();
		if(vecStartUp.Length()==0)
		{
			vecStartUp=vecUp;
		}
		
		
		vec3_t vecTemp;
		float flStartSize = startwidth * 0.5;
		float flEndSize = endwidth * 0.5;

		gEngfuncs.pTriAPI->Brightness( 1 );
		gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
		vecTemp = start + (vecStartUp * flStartSize);
		gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
		
		gEngfuncs.pTriAPI->Brightness( 1 );
		gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );	
		vecTemp = end + (vecUp * flEndSize);
		gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );

		gEngfuncs.pTriAPI->Brightness( 1 );
		gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );	
		vecTemp = end - (vecUp * flEndSize);
		gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
		
		gEngfuncs.pTriAPI->Brightness( 1 );
		gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
		vecTemp = start - (vecStartUp * flStartSize);
		gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
		
		return vecUp;
	}
}
*/
void DrawHead(vec3_t origin, int sprite, int width, int frame)
{	if ( !gEngfuncs.pTriAPI->SpriteTexture( IEngineStudio.GetModelByIndex(sprite), frame))
	{	ConsolePrint("Can't find texture sprite\n");
		return;
	}
	
	vec3_t vecPointLeft = v_up * width * 0.5 + -v_right * width * 0.5 + origin;
	vec3_t vecPointRight = v_up * width * 0.5 + v_right * width * 0.5 + origin;
	vec3_t vecPointLeftDown = -v_up * width * 0.5 + -v_right * width * 0.5 + origin;
	vec3_t vecPointRightDown = -v_up * width * 0.5 + v_right * width * 0.5 + origin;
	
	gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
	gEngfuncs.pTriAPI->CullFace( TRI_NONE );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	gEngfuncs.pTriAPI->Color4ub(255,255,255,255);
	
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	gEngfuncs.pTriAPI->Vertex3f( vecPointLeft.x, vecPointLeft.y, vecPointLeft.z );

	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
	gEngfuncs.pTriAPI->Vertex3f( vecPointLeftDown.x, vecPointLeftDown.y, vecPointLeftDown.z );
		
	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
	gEngfuncs.pTriAPI->Vertex3f( vecPointRightDown.x, vecPointRightDown.y, vecPointRightDown.z );

	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	gEngfuncs.pTriAPI->Vertex3f( vecPointRight.x, vecPointRight.y, vecPointRight.z );
	
	gEngfuncs.pTriAPI->End();
}

vec3_t DrawBeamStart(vec3_t vecStart, const ent_ent_trail &trTrail)
{	
	//starting point of the trail
	list <vec3_t>::const_iterator first = trTrail.points.begin();	
	vec3_t vecDir = *first-vecStart;
	
	//startpoint != last point?
	if (Length(vecDir)==0)
	{	//at least 2 points in the trail?
		if(trTrail.points.size()>1)
		{	list <vec3_t>::const_iterator last=--trTrail.points.end();	
			Vector vecOld = *last;	
			vecDir = vecOld - vecStart;
		}
		else
		{	return vecStart;
		}
	}	
	
	vec3_t vecMiddle;
	float flBeamWidth = trTrail.width * TRAIL_HEAD_RATIO;
	if (trTrail.points.size()>1)
	{	list <vec3_t>::const_iterator next = ++first;
		vecDir = *next - *first;
		VectorNormalize(vecDir);
	}
	else 
	{	vecDir = v_forward;
	}
	
	DrawHead(vecStart, trTrail.startb, flBeamWidth, trTrail.startframe[0]);
	vecMiddle = vecStart + vecDir * flBeamWidth * BEAM_OVERLAP * 0.5;
	vecStart = vecStart + vecDir * flBeamWidth * 0.5 * BEAM_OVERLAP;

	DrawHead(vecStart, trTrail.startb, flBeamWidth, trTrail.startframe[1]);
	vecStart = vecStart + vecDir * flBeamWidth * 0.5 * BEAM_OVERLAP;
	
	DrawHead(vecStart, trTrail.startb, flBeamWidth * 0.5, trTrail.startframe[2]);
	vecStart = vecStart + vecDir * flBeamWidth * 0.25 * BEAM_OVERLAP;
	
	DrawHead(vecStart, trTrail.starta, flBeamWidth/TRAIL_HEAD_RATIO, trTrail.startframe[3]);
	return vecMiddle;
}

void DrawBeamHead(const beam &head, vec3_t vecStart, vec3_t vecDir)
{
	/*VRML beamhead experiment
	VRMLData vrmlScaledHead;
	VRMLData vrmlRotatedHead;	
	ScaleVRML(vrmlScaledHead, gVRMLBeamhead, head.width);

	vec3_t vecAngles;	
	VectorAngles(vecDir,vecAngles);
	RotateVRML(vrmlRotatedHead,vrmlScaledHead,vecAngles);
	DrawVRMLSVSprite(vrmlRotatedHead, vecStart, head.flarea,kRenderTransAdd,TRI_NONE,0, 255, 255, 255, 255);
	*/

	//vec3_t vecMiddle;
	vec3_t vecCurrent;

	vecCurrent = vecStart - vecDir * head.width * BEAM_OVERLAP * 0.9;
	DrawHead(vecCurrent, head.flareb, head.width * 0.9, head.flareframe[1]);
	
	vecCurrent = vecCurrent - vecDir * head.width * BEAM_OVERLAP * 0.8;	
	DrawHead(vecCurrent, head.flarea, head.width * 0.8, head.flareframe[0]);	
	
	DrawHead(vecStart, head.flareb, head.width, head.flareframe[2]);
	//vecMiddle = vecStart + vecDir * head.width * BEAM_OVERLAP * 0.5;
	
	vecCurrent = vecStart + vecDir * head.width * BEAM_OVERLAP;
	DrawHead(vecCurrent, head.flareb, head.width * 0.9, head.flareframe[3]);
	
	vecCurrent = vecCurrent + vecDir * head.width * BEAM_OVERLAP * 0.9;
	DrawHead(vecCurrent, head.flareb, head.width * 0.8, head.flareframe[4]);
	
	vecCurrent = vecCurrent + vecDir * head.width * BEAM_OVERLAP * 0.8;
	DrawHead(vecCurrent, head.flareb, head.width * 0.6, head.flareframe[5]);

	vecCurrent = vecCurrent + vecDir * head.width * BEAM_OVERLAP * 0.6;
	DrawHead(vecCurrent, head.flareb, head.width * 0.4, head.flareframe[6]);
	
	vecCurrent = vecCurrent + vecDir * head.width * BEAM_OVERLAP * 0.4;
	DrawHead(vecCurrent, head.flarea, head.width * 0.3, head.flareframe[7]);

	vecCurrent = vecCurrent + vecDir * head.width * BEAM_OVERLAP * 0.3;
	DrawHead(vecCurrent, head.flarea, head.width * 0.2, head.flareframe[8]);
	//return vecMiddle;	
	
}

void DrawBeamFlare(const ent_ent_trail &trTrail, vec3_t vecEnd, const beam &head)
{	
	list <vec3_t>::const_iterator first=trTrail.points.begin();
	list <vec3_t>::const_iterator last=trTrail.points.end();
	vec3_t vecDir = *first - vecEnd;
	//last point != end point?
	if (Length(vecDir)==0)
	{	list <vec3_t>::const_iterator next = first;
		++next;
		if (next!=last)
		{	vecDir = *next - vecEnd;
		}
		else
		{	//trail too short to find out the flare dir
			return;
		}
	}
	VectorNormalize(vecDir);		
	DrawBeamHead(head, vecEnd, vecDir);	
}

void DrawBeamFlare(const sbc_trail &trTrail, vec3_t vecEnd, beam head)
{	vec3_t vecDir = trTrail.startpos - vecEnd;
	VectorNormalize(vecDir);
	DrawBeamHead(head, vecEnd, vecDir);	
}

void DrawBeamFlare(const flare &flr, vec3_t vecEnd, const beam &head)
{	
	vec3_t vecDir;
	list <vec3_t>::const_iterator first = flr.points.begin();
	list <vec3_t>::const_iterator last = flr.points.end();

	vecDir = *first - vecEnd;
	//last point != end point?
	if (Length(vecDir)==0)
	{	list <vec3_t>::const_iterator next = first;
		++next;
		if (next!=last)
		{	vecDir = *next - vecEnd;
		}
		else
		{	cl_entity_t *pClient;
			pClient = gEngfuncs.GetEntityByIndex( flr.head.ent );
			AngleVectors(pClient->angles,vecDir,NULL,NULL);
		}
	}
	

	VectorNormalize(vecDir);		
	DrawBeamHead(head, vecEnd, vecDir);	
}

void DrawFlareTrail(const list <vec3_t> &points, vec3_t end, float width, int sprite, int frame, float beamlength)
{	
	if (width <= 0)
	{
		ConsolePrint("Invalid beam width\n");
		return;
	}

	float flEndWidth = width; 
	float flStartWidth = width;
	float flWidthIncrease = width;
	
	float flMinimumWidth = 4;
	if (flStartWidth<flMinimumWidth)
	{	flMinimumWidth = flStartWidth;
	}
		
	list <vec3_t>::const_iterator first = points.begin();
	vec3_t vecPreviousPoint = *first;

	if ( !gEngfuncs.pTriAPI->SpriteTexture( IEngineStudio.GetModelByIndex(sprite), frame))
	{	ConsolePrint("Can't find texture sprite\n");
		return;
	}	

	gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
	gEngfuncs.pTriAPI->CullFace( TRI_NONE );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	gEngfuncs.pTriAPI->Color4ub(255,255,255,255);
	//vec3_t vecEndUp = vec3_t(0,0,0);
	if (Length(vecPreviousPoint-end)>0)
	{	if (beamlength)
		{	flEndWidth -= flWidthIncrease * Length(vecPreviousPoint - end)/beamlength;
			if(flEndWidth<flMinimumWidth)
				flEndWidth=flMinimumWidth;
		}
		flStartWidth = flEndWidth;
		DrawBeamPart(end,vecPreviousPoint,flStartWidth,flEndWidth);
		//vecEndUp = DrawBeamPart(end,vecPreviousPoint,flStartWidth,flEndWidth, vecEndUp);
	}
	list <vec3_t>::const_iterator iter = first;
	iter++;
	while (iter!=points.end())
	{	if (beamlength)
		{	flEndWidth -= flWidthIncrease * Length(vecPreviousPoint - *iter)/beamlength;
			if(flEndWidth<flMinimumWidth)
				flEndWidth=flMinimumWidth;
		}		
		DrawBeamPart(vecPreviousPoint, *iter, flStartWidth, flEndWidth);
		//vecEndUp = DrawBeamPart(vecPreviousPoint, *iter, flStartWidth, flEndWidth,vecEndUp);
		vecPreviousPoint = *iter;
		flStartWidth = flEndWidth;		
		iter++;
	}

	gEngfuncs.pTriAPI->End();
}

/**
 * Draws a viewplane aligned rectangle with middle line start-end
 */
void DrawWorldRect(vec3_t start, vec3_t end, float width, int sprite, int frame, int r, int g, int b, int a)
{
	vec3_t W = start-g_CamOrigin;
	vec3_t U = end-g_CamOrigin;
	double wx=DotProduct(W,v_right);
	double wy=DotProduct(W,v_up);
	double ux=DotProduct(U,v_right);
	double uy=DotProduct(U,v_up);

	Vector2D onPlane=Vector2D(ux-wx,uy-wy);
	char buffer[255];
	sprintf(buffer,"onPlane.Length():%f\n",onPlane.Length());
	ConsolePrint(buffer);
	if(onPlane.Length()<0.5)
	{
		return;
	}

	Vector2D Q=Vector2D(uy-wy,wx-ux);
	Vector2D q=Q.Normalize();
	vec3_t vecUp = q.x*v_right+q.y*v_up;
	vecUp=vecUp.Normalize();

	vec3_t vecTemp;

	float flSize = width * 0.5;
	if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( sprite ), frame ))
	{
		return;
	}
	
	gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
	gEngfuncs.pTriAPI->CullFace( TRI_NONE );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	gEngfuncs.pTriAPI->Color4ub(r,g,b,a);
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
	vecTemp = start + (vecUp * flSize);
	gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );	
	vecTemp = end + (vecUp * flSize);
	gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );

	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );	
	vecTemp = end - (vecUp * flSize);
	gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
	
	gEngfuncs.pTriAPI->Brightness( 1 );
	gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
	vecTemp = start - (vecUp * flSize);
	gEngfuncs.pTriAPI->Vertex3f( vecTemp.x, vecTemp.y, vecTemp.z );
		
	gEngfuncs.pTriAPI->End();	
	gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
}

void DrawTrail(const list <vec3_t> &points, vec3_t start,vec3_t end, float width, int sprite, int frame, int increasewidth,float beamlength)
{	
	float flEndWidth = width; 
	float flStartWidth = width; 
	float flWidthIncrease = 1;
		
	if(increasewidth)
	{	flWidthIncrease = 0.5 * TRAIL_BEAM_RATIO * width;
		flStartWidth += flWidthIncrease;
		flEndWidth += flWidthIncrease;
	}
	list <vec3_t>::const_iterator first=points.begin();
	vec3_t vecPreviousPoint = *first;

	if ( !gEngfuncs.pTriAPI->SpriteTexture( IEngineStudio.GetModelByIndex(sprite), frame))
	{	ConsolePrint("Can't find texture sprite\n");
		return;
	}	
	gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
	gEngfuncs.pTriAPI->CullFace( TRI_NONE );
	gEngfuncs.pTriAPI->Begin( TRI_QUADS );
	gEngfuncs.pTriAPI->Color4ub(255,255,255,255);
	
	
	//vec3_t vecUp=vec3_t(0,0,0);
	if (Length(vecPreviousPoint-end)>0)
	{	DrawBeamPart(end,vecPreviousPoint,flStartWidth,flEndWidth);
		//vecUp=DrawBeamPart(end,vecPreviousPoint,flStartWidth,flEndWidth,vecUp);
	}

	list <vec3_t>::const_iterator iter=first;
	list <vec3_t>::const_iterator next;
	while (iter!=points.end())
	{			
		iter++;
		if (iter!=points.end())
		{	if (increasewidth)
			{	if (beamlength)
				{	flEndWidth -= flWidthIncrease * Length(vecPreviousPoint - *iter)/beamlength;
				}			
			}
			DrawBeamPart(vecPreviousPoint, *iter, flStartWidth, flEndWidth);			
			//vecUp=DrawBeamPart(vecPreviousPoint, *iter, flStartWidth, flEndWidth,vecUp);
			flStartWidth = flEndWidth;
			vecPreviousPoint = *iter;
		}
		else
		{	DrawBeamPart(vecPreviousPoint, start, width, width);
			//vecUp=DrawBeamPart(vecPreviousPoint, start, width, width,vecUp);
		}						
	}
	gEngfuncs.pTriAPI->End();
}

vec3_t GetFlareStart(const beam &b,int &succes)
{
	cl_entity_t *pClient;	
	succes = true;
	if(b.bs)
	{	pClient = gEngfuncs.GetEntityByIndex( b.bsent );
		if(!pClient)
		{	succes = false;
			return vec3_t(0,0,0);
		}
		else 
		{	if (b.bones->blCanUsePlayerPos) 
			{	vec3_t vecLeftShoulder = g_StudioRenderer.GetBoneOrigin(pClient,b.bones->playerpos,"Bip01 L Arm");
				vec3_t vecLeftHand = g_StudioRenderer.GetBoneOrigin(pClient,b.bones->playerpos,"Bip01 L Hand");
				
				vec3_t vecRightShoulder = g_StudioRenderer.GetBoneOrigin(pClient,b.bones->playerpos,"Bip01 R Arm");
				vec3_t vecRightHand = g_StudioRenderer.GetBoneOrigin(pClient,b.bones->playerpos,"Bip01 R Hand");
				
				vec3_t vecForward = (vecLeftHand-vecLeftShoulder+vecRightHand-vecRightShoulder);
				VectorNormalize(vecForward);

				return (vecLeftHand + vecRightHand)*0.5+vecForward * b.width * 0.25;
			}
			else
			{	return pClient->curstate.origin;
			}
		}
	}
	else
	{	pClient = gEngfuncs.GetEntityByIndex( b.ent );
		if(!pClient)
		{	succes = false;
			return vec3_t(0,0,0);			
		}
		else 
		{	if (!InPVS(pClient))
			{	succes = false;
			}
			return pClient->curstate.origin;
		}
	}	
}

void DrawSBCTrail(const sbc_trail &trTrail)
{	
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex( trTrail.head.ent );
	
	//draw main trail
	//trail_points points;
	//points.point = trTrail.startpos;
	//points.next = NULL;
	int succes = 0;
	vec3_t vecEnd = GetFlareStart(trTrail.head,succes);
	if (vecEnd == vec3_t(0,0,0))
	{	vecEnd = trTrail.pos;;
	}
	DrawTrail(trTrail.mainpoints, trTrail.startpos,vecEnd, trTrail.width * SBC_ORBIT_BEAM_RATIO, trTrail.trail, trTrail.trailframe, false, 0);
		
	//draw beam main flare
	DrawBeamFlare(trTrail,vecEnd,trTrail.head);

	if (cl_beamquality->value<4)
	{	//draw orbiting trail
		DrawTrail(trTrail.points,trTrail.startpos,trTrail.orbitpos, trTrail.orbitwidth, trTrail.orbittrail, trTrail.orbittrailframe, false, 0);
		//draw orbitting flare
		DrawBeamFlare(trTrail,trTrail.orbitpos,trTrail.orbithead);
	}
}

void DrawFlare(const flare &flr)
{	list <vec3_t>::const_iterator first= flr.points.begin();	
	if (first==flr.points.end())
		return;	
		
	vec3_t vecEnd;
	int succes;
	vecEnd = GetFlareStart(flr.head,succes);
	if(vecEnd != vec3_t(0,0,0))
	{ vecEnd = *first;
	}

	/*
	cl_entity_t *pClient;
	pClient = gEngfuncs.GetEntityByIndex(flr.head.ent);

	vec3_t vecEnd;
	if (pClient)
	{	vecEnd = pClient->curstate.origin;		
	}
	*/

	//draw beam trail
	DrawBeamFlare(flr,vecEnd,flr.head);
	DrawFlareTrail(flr.points, vecEnd, flr.width, flr.trail, flr.trailframe, flr.traillength);	
}	

void DrawEntEntTrail(const ent_ent_trail &trTrail)
{	list <vec3_t>::const_iterator first=trTrail.points.begin();
	if (first == trTrail.points.end())
		return;
	
	vec3_t vecEnd;
	int succes;
	vecEnd = GetFlareStart(trTrail.head,succes);
	if(vecEnd==vec3_t(0,0,0))
	{ vecEnd = *first;
	}	

	//calculate first point
	vec3_t vecFirst;
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex( trTrail.startent );
	if (pClient)
	{	if (trTrail.attachment)
		{	vecFirst = pClient->attachment[trTrail.attachment-1];
		}
		else
		{	vecFirst = pClient->origin;
		}		
	}
	else
	{	ConsolePrint("Beam owner not found\n");
		return;
	}
	
	//draw beam trail
	vec3_t vecTrailStart = DrawBeamStart(vecFirst,trTrail);
	DrawBeamFlare(trTrail,vecEnd,trTrail.head);
	DrawTrail(trTrail.points, vecTrailStart, vecEnd, trTrail.width, trTrail.trail, trTrail.trailframe, true, trTrail.traillength);	
}


void ManageInterpolGait( void )
{	
	for (int i=0;i<MAX_PLAYERS;i++)
	{	if(!g_StudioRenderer.m_InterpolGait[i].blRendered)
		{	g_StudioRenderer.m_InterpolGait[i].blActive = false;
		}
		else
		{	g_StudioRenderer.m_InterpolGait[i].blRendered = false;		
		}
	}
	/*
	list <interpol_gait_s>::iterator first = g_StudioRenderer.m_pInterpolGait.begin();
	list <interpol_gait_s>::iterator last = g_StudioRenderer.m_pInterpolGait.end();	
	while (first!=last)
	{	if(first->blRendered)
		{	first->blRendered = false;
			first++;
		}
		// Erase and restart loop
		else
		{	ConsolePrint("Erasing interpol_gate_s\n");						
			first = g_StudioRenderer.m_pInterpolGait.erase(first);
		}
	}*/	
}

void MeleeSphere( void )
{	// set local index
	int iIndex = 0;
	cl_entity_t *pEntity = gEngfuncs.GetLocalPlayer();
	VRMLData vrmlScaledExplosion;

	if(pEntity)
	{	iIndex = pEntity->index;
	}

	// Loop through all players
	for(int i=1;i<=32;i++)
	{	/*modified by harSens
		list<model_manip_s>::iterator pModelManip = gHUD.m_ManipModel.FindByPlayerIndex(i);
		*/
		model_manip_s *pModelManip = gHUD.m_ManipModel.FindByPlayerIndex(i);
		// Draw sphere around meleeing players
		if(pModelManip!=NULL && ((pModelManip->iFlags & MANIP_FLAG_CONNECT) || (pModelManip->iFlags & MANIP_FLAG_MSTRUGGLE)))
		{	int rgba = 30;

			// Don't render sphere if you're the player in melee
			if(pModelManip->iPlayerIndex == iIndex || pModelManip->iOtherIndex == iIndex)
			{	continue;
			}

			vec3_t vecPlayer = g_StudioRenderer.GetBoneOrigin( gEngfuncs.GetEntityByIndex( pModelManip->iPlayerIndex ), pModelManip->playerpos, "Bip01 Spine");
			vec3_t vecOther = g_StudioRenderer.GetBoneOrigin( gEngfuncs.GetEntityByIndex( pModelManip->iOtherIndex ), pModelManip->otherpos, "Bip01 Spine");
			vec3_t vecAvg;
			for(int i=0;i<3;i++)
				vecAvg[i] = (vecPlayer[i] + vecOther[i])/2;


			ScaleVRML(vrmlScaledExplosion, *gVRMLSphere, 17.5);
			DrawVRML(vrmlScaledExplosion, vecAvg, g_hsprWhite,kRenderTransAdd,TRI_NONE,0, rgba, rgba, rgba, rgba);
		}
	}
}

// Pcjoe: TEST
#include "fxscript/fxsys.h"
#include "fxscript/fxparticlesystemmanager.h"
extern CFXDataPoint *gPathSelect;
#include "mdlcontrol.h"
#include "modelvgui.h"
CCharacterVgui *g_pCharacter = NULL;

void delete_particles()
{	g_FXPsysManager.Reset();
}

void reset_particles()
{//	cl_entity_t *pLocal = gEngfuncs.GetLocalPlayer();
	
	// Create two particle systems
	g_FXPsysManager.Reset();
//	g_FXPsysManager.createManagedParticleSystem("test_sys", pLocal);
//	g_FXPsysManager.createManagedParticleSystem("test_sys1", pLocal);
//	g_FXPsysManager.createManagedParticleSystem("test_sys3", pLocal);
//	g_FXPsysManager.createManagedParticleSystem("test_sys4", pLocal);
//	g_FXPsysManager.createManagedParticleSystem("test_sys_rise",pLocal);
//	g_FXPsysManager.createManagedParticleSystem("test_sys_scatter",pLocal);
//	g_FXPsysManager.createManagedParticleSystem("aura", pLocal);
}


void reload_particles()
{	g_ParseMain.Initialize();
	reset_particles();
}


void Draw_Triangles( void )
{	cl_entity_t *pLocal = gEngfuncs.GetLocalPlayer();
	// Edited by Pcjoe, if third person, use Camera Angles( So the sprites will look good, regardless of the angle )
	// If first person, use v_forward
	
	//finds out what sphere to use
	setSphere();
	
	// Third Person
	if(cam_thirdperson || gEngfuncs.pDemoAPI->IsPlayingback() || (pLocal && g_IsSpectator[pLocal->index]))
	{	/* Original code by Joe, modified by harSens, g_CamAngles[2] holds the zoom
		AngleVectors( g_CamAngles, v_forward, v_right, v_up);
		*/
		vec3_t vecViewAngles = g_CamAngles;
		vecViewAngles[2]=0;
		AngleVectors( vecViewAngles, v_forward, v_right, v_up);	
	}
	// First Person
	else
	{	vec3_t vecViewAngles;
		gEngfuncs.GetViewAngles( (float *)vecViewAngles);
		AngleVectors( vecViewAngles, v_forward, v_right, v_up);	
	}

	if((gViewPort->m_pESFClassMenu->getDrawCycle() == 1) && gViewPort->m_pESFClassMenu->isVisible())
	{	// Reset draw cycle
		gViewPort->m_pESFClassMenu->setDrawCycle(0);

		// Draw black background
		int iMaxSize = 9999;
		Draw_Box(g_hsprBlack, kRenderNormal, vec3_t(iMaxSize,iMaxSize,iMaxSize), vec3_t(-iMaxSize,-iMaxSize,-iMaxSize));

		// Reset rendering to normal
		gEngfuncs.pTriAPI->RenderMode( kRenderNormal );
	
		// stand
/*		CMDLControl mdlctrl;
		mdlctrl.setIndex(0);
		mdlctrl.setFrame(0);
		mdlctrl.setSequence("idle");
		mdlctrl.setModel(IEngineStudio.Mod_ForName("models/mountain.mdl",0));

		// Draw stand
		g_StudioRenderer.StudioDrawModel( &mdlctrl );*/

		if(gViewPort->m_pESFClassMenu->isVisible())
		{	// Player
			CCharacterVgui *pCurrentCharacter = gViewPort->m_pESFClassMenu->getCharacterPortrait(gViewPort->m_pESFClassMenu->getCurrentInfo());
			if(pCurrentCharacter)
			{	CCharacterFormVgui *pForm = pCurrentCharacter->getForm(gViewPort->m_pESFClassMenu->getCurrentForm());
				if(pForm)
				{	// Update rotate
					if(gViewPort->m_pESFClassMenu->getCurrentlyRotating())
					{	// Use global mouse button press to make sure we're still holding on, even outside of the window
						if(g_MouseCap.getStatus(0))
						{	int x,y;
							App::getInstance()->getCursorPos(x,y);
							if(gViewPort->m_pESFClassMenu->getMouseXPrev() == -1)
							{	gViewPort->m_pESFClassMenu->setMouseXPrev(x);
							}
							// Use the delta between mouse positions and a set scale to increase rotation
							else
							{	float flIncRot = float(x-gViewPort->m_pESFClassMenu->getMouseXPrev())*0.75;
								gViewPort->m_pESFClassMenu->setMouseXPrev(x);
								gViewPort->m_pESFClassMenu->setRotate(gViewPort->m_pESFClassMenu->getRotate()+flIncRot);
							}
						}
						else
						{	gViewPort->m_pESFClassMenu->setCurrentlyRotating(false);
							gViewPort->m_pESFClassMenu->setMouseXPrev(-1);
						}
					}
					// set rotate
					vec3_t vecRotate(0,0,0);
					vecRotate[YAW] = 180 + gViewPort->m_pESFClassMenu->getRotate(); // Add 180 or the model will be facing backwards by default

					// Make sure we have a model to render
					if(pForm->getModel() && pForm->getModel()->getModelControl() && pForm->getModel()->getModelControl()->getModel())
					{	// backup model if we decide to replace it with a custom model
						model_s *pBkModel = pForm->getModel()->getModelControl()->getModel();
						// Update rotate
						pForm->getModel()->getModelControl()->setAngle(vecRotate);
						
						// Custom Model Support
						std::string strCustomModel = gViewPort->m_pESFClassMenu->getCustomModel();
						if(strCustomModel != "")
						{	CCustomModel *pCustomModel = gHUD.m_CustomModel.getCustomModel(gViewPort->m_pESFClassMenu->getCurrentInfo(), strCustomModel);
							if(pCustomModel)
							{	model_s *pReplacement = pCustomModel->getReplacement(pBkModel->name);
								if(pReplacement)
								{	pForm->getModel()->getModelControl()->setModel(pReplacement);
								}
							}
						}
						pForm->Render();
						pForm->getModel()->getModelControl()->setModel(pBkModel);
					}
				}
			}

			return;
		}
	}

	gHUD.m_Crosshair.DrawFollowRectangle();
	g_FXPsysManager.Think();
	g_FXPsysManager.Render();
	
	//added by harSens to draw explosions
	explosion *current = tri_exp;
	VRMLData vrmlScaledExplosion;
	VRMLData vrmlRotatedExplosion;
	while (current)
	{	if(current->m_iFrame<0||current->m_iFrame>SPR_Frames(current->sprite)-1)
		{	current->m_iFrame = 0;
		}

		ScaleVRML(vrmlScaledExplosion, gVRMLExplosion, current->radius);
		RotateVRML(vrmlRotatedExplosion,vrmlScaledExplosion,current->rotation);
		DrawVRML(vrmlRotatedExplosion, current->pos, current->sprite,kRenderTransAdd,TRI_NONE,current->m_iFrame, 120, 120, 120, 120);

		current->m_iFrame++;
		current = current->next;
	}

	// Added by Pcjoe, Blob Explosions
	current = pBlobExp;
	while (current)
	{	// Only render if your in view...
		ScaleVRML(vrmlScaledExplosion, *gVRMLSphere, current->radius);
		DrawVRML(vrmlScaledExplosion, current->pos, current->sprite,kRenderTransAdd,TRI_NONE,current->m_iFrame, current->iAlpha, current->iAlpha, current->iAlpha, current->iAlpha);
		current = current->next;
	}

	// Redone + edited by Pcjoe to draw an updated power up dust
	// Originally by harsens to draw triapi powerup dome
	// And edited by Rick :) : Changed g_Poweringup array to a linked list(g_PoweringupList)
	// Reason : buddy's need a powerup fx aswell
	powerupfx *pFXEntry = g_PoweringupList;
	while(pFXEntry)
	{
		if(pFXEntry->enabled || pFXEntry->m_flDyingTime != 0)
		{	DrawPowerupFX(pFXEntry,pFXEntry->r,pFXEntry->g,pFXEntry->b);
		}
		pFXEntry = pFXEntry->next;
	}

	// Pcjoe: Render shockwaves
	gHUD.m_MeleeFX.RenderShockwaves();
	

	list <sbc_trail>::iterator sfirst = g_SBCTrails.begin();
	list <sbc_trail>::iterator slast = g_SBCTrails.end();
	while (sfirst!=slast)
	{	--slast;
		DrawSBCTrail(*slast);
	}

	list <ent_ent_trail>::iterator efirst = g_EntEntTrails.begin();
	list <ent_ent_trail>::iterator elast = g_EntEntTrails.end();	
	while (efirst!=elast)
	{	--elast;
		DrawEntEntTrail(*elast);
	}

	list <flare>::iterator ffirst = g_Flares.begin();
	list <flare>::iterator flast = g_Flares.end();	
	while (ffirst!=flast)
	{	--flast;	
		DrawFlare(*flast);		
	}

	//TODO: should draw all trails
	gHUD.m_Trail.DrawTrails();

	//harSens: draw particle stuff
	gHUD.m_FXManager.Draw();

	// Added by Pcjoe, Transform FX
	TransformationFX();

	//draw bboxes
	for (int i=0;i<g_iNumberOfBoundingBoxEnts;i++)
	{
		cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(g_BoundingboxEnts[i]);
		Draw_BBox(pClient);		
	}

	// Pcjoe: TEST for hud models
/*	cl_entity_t *pPlayer = gEngfuncs.GetLocalPlayer();
	if(pPlayer && pPlayer->model)
	{	if(!blTest && gHUD.m_flTime > 10)
		{	blTest = true;
			C3DHud *pHud = new C3DHud(pPlayer->model, vec3_t(0, 0, 0), vec3_t(ScreenWidth/2,ScreenHeight,0));
			pHud->SetAnimation("walk");
			pHud->Resize2D(vec3_t(ScreenWidth/2, 0, 0), vec3_t(ScreenWidth,ScreenHeight/2,0), 6);
			pHud = new C3DHud(pPlayer->model, vec3_t(ScreenWidth/2, 0, 0), vec3_t(ScreenWidth,ScreenHeight,0));
			pHud->SetAnimation("idle");
			pHud->Resize2D(vec3_t(0, 0, 0), vec3_t(ScreenWidth/2,ScreenHeight/2,0), 6);
		}
	}*/

	// Pcjoe: Check hud models after they render
	C3DHud *pCurrent = gHUD.m_3dhud.m_p3DHud;
	while(pCurrent)
	{	pCurrent->AfterRenderCheck();
		// TEST
	/*	if(pCurrent->GetModel() != pPlayer->model)
		{	pCurrent->SetModel(pPlayer->model);
		}*/
		pCurrent = pCurrent->GetNext();
	}

	// added by Pcjoe, Draw triangles over team mates heads
	if(cl_drawdiamonds->value)
	{	g_StudioRenderer.DrawDiamonds();
	}

	g_StudioRenderer.DrawHalos();

	// Pcjoe: Manage gait interpolation
	ManageInterpolGait( );
	
	// Pcjoe: Draw spheres around meleeing fighters
	MeleeSphere();



/*	if(g_pEvent)
	{	// Object think
		g_pEvent->Think(g_pEvent->getStartTime()+gEventTimeTest);

		// Render all events
		g_pEvent->Render();

		// Update sound
		if(g_FMODWrapper.isLoaded())
		{	g_FMODWrapper.FWRAPPER_3D_Listener_SetAttributes(GetCamPos(), NULL, v_forward.x,v_forward.y,v_forward.z,v_up.x,v_up.y,v_up.z);
			g_FMODWrapper.FWRAPPER_Update();
		}

		// Render paths
		if(cl_fxscript_debug->value)
			g_pEvent->getPathSystem()->RenderPaths(g_pEvent);
	}*/
	
	g_FXSystem.Think();
	g_FXSystem.Render();
	// Update sound
	if(g_FMODWrapper.isLoaded())
	{	g_FMODWrapper.FWRAPPER_3D_Listener_SetAttributes(GetCamPos(), NULL, v_forward.x,v_forward.y,v_forward.z,v_up.x,v_up.y,v_up.z);
		g_FMODWrapper.FWRAPPER_Update();
	}

	// Pcjoe: HACK HACK - Draw selected path point
	if(gPathSelect)
	{	vec3_t vecOrg = gPathSelect->getPosition();
		int iAxisSize = 35;
		float r=255,g=100,b=100,a=180;
		float flAlpha = float(255/a);
		VRMLData vrmlSphere;
		ScaleVRML(vrmlSphere, *gVRMLSphere, 10);
		DrawVRML(vrmlSphere, vecOrg, g_hsprWhite, kRenderTransAdd, TRI_NONE, 0, r*flAlpha,g*flAlpha,b*flAlpha,a*flAlpha);
	}

	//DrawWorldRect(vec3_t(100,0,1000), vec3_t(0,0,1000), 50, g_hsprWhite, 0, 255, 255, 255, 255);

/*	if(gOnlyClientDraw)
	{	
		model_t* world = gEngfuncs.GetEntityByIndex(0)->model;
		msurface_t** s=world->marksurfaces;
		glpoly_t* p;
		texture_t* tex;
		glColor4f(1,1,1,1);
		for(int i=0;i<world->nummarksurfaces;i++)
		{
		//	if(s[i]->visframe!=-1)
			{
				tex=s[i]->texinfo->texture;
				glBindTexture(GL_TEXTURE_2D,tex->gl_texturenum);
				p=s[i]->polys;
				glBegin (GL_POLYGON);
				float* v = p->verts[0];
				for (int t=0 ; t<p->numverts ; t++, v+= VERTEXSIZE)
				{
					glTexCoord2f (v[3], v[4]);
					glVertex3fv (v);
				}
				glEnd ();
		//		s[i]->visframe=-1;
			}
		}
	}*/
}



/*
=================
HUD_DrawNormalTriangles

Non-transparent triangles-- add them here
=================
*/
void DLLEXPORT HUD_DrawNormalTriangles( void )
{

	gHUD.m_Spectator.DrawOverview();
#if defined( TEST_IT )
//	Draw_Triangles();
#endif
}

/*
=================
HUD_DrawTransparentTriangles

Render any triangles with transparent rendermode needs here
=================
*/
void DLLEXPORT HUD_DrawTransparentTriangles( void )
{

  /*removed by harSens
  #if defined( TEST_IT )
  */
	Draw_Triangles();
  /*removed by harSens
  #endif
  */
}
