void RenderShadow(LPDIRECT3DDEVICE7 lpDevice,D3DVERTEX* vertices,int numvertices,WORD* indices,DWORD numindices)
{
    // Turn depth buffer off, and stencil buffer on
    lpDevice->SetRenderState( D3DRENDERSTATE_ZWRITEENABLE,  FALSE );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILENABLE, TRUE );

    // Set up stencil compare fuction, reference value, and masks
    // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILFUNC,     D3DCMP_ALWAYS );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILREF,      0x1 );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILMASK,     0xffffffff );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILWRITEMASK,0xffffffff );

    // If ztest passes, write 1 into stencil buffer
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILZFAIL, D3DSTENCILOP_KEEP );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILFAIL,  D3DSTENCILOP_KEEP );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILPASS,  D3DSTENCILOP_REPLACE );

    // Make sure that no pixels get drawn to the frame buffer
    lpDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
    lpDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND,  D3DBLEND_ZERO );
    lpDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE );

	lpDevice->SetTexture(0,NULL);
    // Draw front-side of shadow volume in stencil/z only
	if (indices==NULL)
	{
		lpDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX,
                                        vertices, numvertices,
                                        NULL );
	}
	else
		lpDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX,
                                        vertices, numvertices,
                                        indices, numindices, NULL );

    // Now reverse cull order so back sides of shadow volume are written,
    // writing 0's into stencil. Result will be any pixel which still has a bit
    // set in the stencil buffer, is inside the shadow.
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILREF, 0x0 );

    // Draw back-side of shadow volume in stencil/z only
    lpDevice->SetRenderState( D3DRENDERSTATE_CULLMODE, D3DCULL_CW );
	if (indices==NULL)
	{
		lpDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX,
                                        vertices, numvertices,
                                        NULL );
	}
	else
		lpDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX,
                                        vertices, numvertices,
                                        indices, numindices, NULL );

    // Restore render states
    lpDevice->SetRenderState( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW );
    lpDevice->SetRenderState( D3DRENDERSTATE_ZWRITEENABLE,     TRUE );
    lpDevice->SetRenderState( D3DRENDERSTATE_STENCILENABLE,    FALSE );
    lpDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE );
}
/// <summary>
/// <c>wDrawIndexedPrimitive</c> 
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="d3dDevice7"></param>
/// <param name="d3dptPrimitiveType"></param>
/// <param name="dwVertexTypeDesc"></param>
/// <param name="pvVertices"></param>
/// <param name="dwVertexCount"></param>
/// <param name="pwIndices"></param>
/// <param name="dwIndexCount"></param>
/// <param name="dwFlags"></param>
/// <returns></returns>
HRESULT __stdcall wDrawIndexedPrimitive(
	LPDIRECT3DDEVICE7 d3dDevice7, D3DPRIMITIVETYPE d3dptPrimitiveType, 
	ULONG dwVertexTypeDesc, PVOID pvVertices, ULONG dwVertexCount, PUSHORT pwIndices, 
	ULONG dwIndexCount, ULONG dwFlags)
{
	PSTR		pszPrimitiveData;
	PSTR		pszErrorMessage;
	HRESULT		hResult;

	pszPrimitiveData = GetDrawIndexedPrimitiveData(
		d3dptPrimitiveType,
		dwVertexTypeDesc,
		pvVertices,
		dwVertexCount,
		pwIndices,
		dwIndexCount,
		dwFlags);
	InternalFunctionSpew("GameOS_Direct3D", "DrawIndexedPrimitive( %s)", pszPrimitiveData);

	hResult = d3dDevice7->DrawIndexedPrimitive(
		d3dptPrimitiveType,
		dwVertexTypeDesc,
		pvVertices,
		dwVertexCount,
		pwIndices,
		dwIndexCount,
		dwFlags);
	if (FAILED(hResult))
	{
		if ( hResult != DDERR_SURFACELOST)
		{
			pszPrimitiveData = GetDrawIndexedPrimitiveData(
				d3dptPrimitiveType,
				dwVertexTypeDesc,
				pvVertices,
				dwVertexCount,
				pwIndices,
				dwIndexCount,
				dwFlags);
			pszErrorMessage = ErrorNumberToMessage(hResult);
			if ( InternalFunctionPause("FAILED (0x%x - %s) - DrawIndexedPrimitive( %s)",
				hResult, pszErrorMessage, pszPrimitiveData) )
				ENTER_DEBUGGER;
		}
	}

	return hResult;
}
//-----------------------------------------------------------------------------
float CExplosion::Render(LPDIRECT3DDEVICE7 device)
{
	if (this->key > 1) return 0;

	SETALPHABLEND(device, TRUE);
	SETZWRITE(device, FALSE);

	device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
	device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);

	//calcul du disque
	D3DTLVERTEX d3dvs, *d3dv;
	EERIE_3D	* vertex;
	int			nb, col, col2;
	float		rin;

	switch (key)
	{
		case 0:
			rin = 255.f * scale;
			vertex = disquevertex;
			d3dv = disqued3d;
			nb = disquenbvertex >> 1;

			while (nb)
			{
				d3dvs.sx = pos.x + (vertex + 1)->x + ((vertex->x - (vertex + 1)->x) * scale);
				d3dvs.sy = pos.y;
				d3dvs.sz = pos.z + (vertex + 1)->z + ((vertex->z - (vertex + 1)->z) * scale);
				EE_RTP(&d3dvs, d3dv);
				d3dv->color = RGBA_MAKE(255, 200, 0, 255);
				vertex++;
				d3dv++;

				d3dvs.sx = pos.x + vertex->x;
				d3dvs.sy = pos.y;
				d3dvs.sz = pos.z + vertex->z;
				EE_RTP(&d3dvs, d3dv);

				if (!ARXPausedTimer) d3dv->color = RGBA_MAKE((int)(rin * rnd()), 0, 0, 255);

				vertex++;
				d3dv++;
				nb--;
			}

			if (rnd() > .25f)
			{
				int j = ARX_PARTICLES_GetFree();

				if ((j != -1) && (!ARXPausedTimer))
				{
					ParticleCount++;
					particle[j].exist = 1;
					particle[j].zdec = 0;

					float a = DEG2RAD(360.f * scale);
					float b = rin; 

					particle[j].ov.x		=	pos.x + b * EEcos(a);
					particle[j].ov.y		=	pos.y;
					particle[j].ov.z		=	pos.z + b * EEsin(a);
					particle[j].move.x		=	0.f;
					particle[j].move.y		=	rnd();
					particle[j].move.z		=	0.f;
					particle[j].siz			=	10.f + 10.f * rnd();
					particle[j].tolive		=	500 + (unsigned long)(float)(rnd() * 500.f);
					particle[j].scale.x		=	1.f;
					particle[j].scale.y		=	1.f;
					particle[j].scale.z		=	1.f;
					particle[j].timcreation	=	lARXTime;
					particle[j].tc			=	tp;
					particle[j].special		=	FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
					particle[j].fparam		=	0.0000001f;
					particle[j].r			=	1.f;
					particle[j].g			=	1.f;
					particle[j].b			=	1.f;
				}

				j = ARX_PARTICLES_GetFree();

				if ((j != -1) && (!ARXPausedTimer))
				{
					ParticleCount++;
					particle[j].exist = 1;
					particle[j].zdec = 0;

					float a = DEG2RAD(-360.f * scale);
					float b = this->rin;

					particle[j].ov.x	=	pos.x + b * EEcos(a);
					particle[j].ov.y	=	pos.y;
					particle[j].ov.z	=	pos.z + b * EEsin(a);
					particle[j].move.x	=	0.f;
					particle[j].move.y	=	rnd();
					particle[j].move.z	=	0.f;
					particle[j].siz		=	10.f + 10.f * rnd();
					particle[j].tolive	=	500 + (unsigned long)(float)(rnd() * 500.f);
					particle[j].scale.x	=	1.f;
					particle[j].scale.y	=	1.f;
					particle[j].scale.z	=	1.f;
					particle[j].timcreation	=	lARXTime;
					particle[j].tc		=	tp;
					particle[j].special	=	FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
					particle[j].fparam	=	0.0000001f;
					particle[j].r		=	1.f;
					particle[j].g		=	1.f;
					particle[j].b		=	1.f;
				}
			}

			if (rnd() > .1f)
			{
				int j = ARX_PARTICLES_GetFree();

				if ((j != -1) && (!ARXPausedTimer))
				{
					ParticleCount++;
					particle[j].exist = 1;
					particle[j].zdec = 0;

					float a = rnd() * 360.f; 
					float b = rin * rnd();

					particle[j].ov.x	=	pos.x + b * EEcos(a);
					particle[j].ov.y	=	pos.y + 70.f;
					particle[j].ov.z	=	pos.z + b * EEsin(a);
					particle[j].move.x	=	0.f;
					particle[j].move.y	=	-(5.f + 10.f * rnd());
					particle[j].move.z	=	0.f;
					particle[j].siz		=	10.f + 20.f * rnd();
					particle[j].tolive	=	1000 + (unsigned long)(float)(rnd() * 1000.f);
					particle[j].scale.x	=	1.f;
					particle[j].scale.y	=	1.f;
					particle[j].scale.z	=	1.f;
					particle[j].timcreation	=	lARXTime;
					particle[j].tc		=	tp2;
					particle[j].special	=	FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
					particle[j].fparam	=	0.0000001f;
					particle[j].r		=	1.f;
					particle[j].g		=	1.f;
					particle[j].b		=	1.f;
				}
			}

			break;
		case 1:
			D3DTLVERTEX d3dvs2;
			rin = 1.f + (puissance * scale);
			vertex = disquevertex;
			d3dv = disqued3d;
			nb = disquenbvertex >> 1;
			float a = 1.f - scale;
			col = RGBA_MAKE((int)(255.f * a), (int)(200.f * a), 0, 255);
			col2 = RGBA_MAKE((int)(255.f * a * rnd()), 0, 0, 0);

			while (nb--)
			{
				d3dvs.sx = pos.x + vertex->x * rin;
				d3dvs.sy = pos.y;
				d3dvs.sz = pos.z + vertex->z * rin;
				vertex++;
				d3dvs2.sx = pos.x + vertex->x * rin;
				d3dvs2.sy = pos.y;
				d3dvs2.sz = pos.z + vertex->z * rin;
				vertex++;

				if (tactif[nb] >= 0)
				{
					EERIE_3D pos, dir;
					pos.x = d3dvs2.sx;
					pos.y = d3dvs2.sy;
					pos.z = d3dvs2.sz;
					dir.x = d3dvs.sx;
					dir.y = d3dvs.sy;
					dir.z = d3dvs.sz;

					DynLight[tactif[nb]].pos.x = dir.x;
					DynLight[tactif[nb]].pos.y = dir.y;
					DynLight[tactif[nb]].pos.z = dir.z;
					DynLight[tactif[nb]].intensity = .7f + 2.f * rnd();

					Collision(nb, &pos, &dir);
					ExplosionAddParticule(nb, &d3dvs, tp);
				}

				EE_RTP(&d3dvs, d3dv);

				if (!ARXPausedTimer) d3dv->color = col;

				d3dv++;

				EE_RTP(&d3dvs2, d3dv);

				if (!ARXPausedTimer) d3dv->color = col2;

				d3dv++;
			}

			break;
	}

	//tracé du disque
	SETCULL(device, D3DCULL_NONE);
	device->SetTexture(0, NULL);
	device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX, disqued3d, disquenbvertex, (unsigned short *)disqueind, disquenbvertex + 2, 0);

	device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
	device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
	SETALPHABLEND(device, FALSE);
	SETZWRITE(device, TRUE);

	return 0;
}
/*--------------------------------------------------------------------------*/
float CPortal::Render(LPDIRECT3DDEVICE7 device)
{
	SETALPHABLEND(device, TRUE);
	SETZWRITE(device, FALSE);

	device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
	device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);

	//calcul sphere
	int			nb = this->spherenbpt;
	D3DTLVERTEX * v = this->sphered3d, d3dvs;
	EERIE_3D	* pt = this->spherevertex;
	int col = RGBA_MAKE(0, (int)(200.f * this->spherealpha), (int)(255.f * this->spherealpha), 255);

	while (nb)
	{
		d3dvs.sx = pt->x + this->pos.x;	//pt du bas
		d3dvs.sy = pt->y + this->pos.y;
		d3dvs.sz = pt->z + this->pos.z;
		EE_RTP(&d3dvs, v);

		if (!ARXPausedTimer) v->color = col;

		v++;
		pt++;
		nb--;
	}

	//update les couleurs aux impacts
	nb = 256;

	while (nb--)
	{
		if (this->tabeclair[nb].actif)
		{
			float a;

			a = 1.f - ((float)this->tabeclair[nb].currduration / (float)this->tabeclair[nb].duration);

			if (a < 0.f) a = 0.f;

			if (this->tabeclair[nb].numpt >= 0)
			{
				int r = (int)((0.f + (255.f - 0.f) * a) * this->spherealpha * 3.f);

				if (r > 255) r = 255;

				int g = (int)((200.f + (255.f - 200.f) * a) * this->spherealpha * 3.f);

				if (g > 255) g = 255;

				int b = (int)(255.f * this->spherealpha * 3.f);

				if (b > 255) b = 255;

				if (!ARXPausedTimer) this->sphered3d[this->tabeclair[nb].numpt].color = RGBA_MAKE(r, g, b, 255);
			}

		}
	}


	//affichage de la sphere back
	SETCULL(device, D3DCULL_CW);
	device->SetTexture(0, NULL);
	device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, this->sphered3d, this->spherenbpt, (unsigned short *)this->sphereind, this->spherenbfaces * 3, 0);

	//affichage eclair
	this->DrawAllEclair(device);

	//affichage des particules à l'interieur
	if (rnd() > .25f)
	{
		int j = ARX_PARTICLES_GetFree();

		if ((j != -1) && (!ARXPausedTimer))
		{
			ParticleCount++;
			particle[j].exist = 1;
			particle[j].zdec = 0;

			float a = rnd() * 360.f;
			float b = rnd() * 360.f;
			float rr = this->r * (rnd() + .25f) * 0.05f;

			particle[j].ov.x	=	this->pos.x;
			particle[j].ov.y	=	this->pos.y;
			particle[j].ov.z	=	this->pos.z;
			particle[j].move.x	=	rr * EEsin(DEG2RAD(a)) * EEcos(DEG2RAD(b));
			particle[j].move.y	=	rr * EEcos(DEG2RAD(a));
			particle[j].move.z	=	rr * EEsin(DEG2RAD(a)) * EEsin(DEG2RAD(b));
			particle[j].siz		=	10.f;
			particle[j].tolive	=	1000 + (unsigned long)(float)(rnd() * 1000.f);
			particle[j].scale.x	=	1.f;
			particle[j].scale.y	=	1.f;
			particle[j].scale.z	=	1.f;
			particle[j].timcreation	=	lARXTime;
			particle[j].tc		=	tp;
			particle[j].special	=	FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
			particle[j].fparam	=	0.0000001f;
			particle[j].r		=	1.f;
			particle[j].g		=	1.f;
			particle[j].b		=	1.f;
		}
	}

	//affichage de la sphere front
	SETCULL(device, D3DCULL_CCW);
	device->SetTexture(0, NULL);
	device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, this->sphered3d, this->spherenbpt, (unsigned short *)this->sphereind, this->spherenbfaces * 3, 0);

	device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
	device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
	SETALPHABLEND(device, FALSE);
	SETCULL(device, D3DCULL_NONE);
	SETZWRITE(device, TRUE);

	return 0;
}