///////////////////////////////////////////////////////////
//
//  IMPLEMENTATION
//
//  CONTEXT: Genesis3D lightweight framework
//  MODULE:	 some light effects
//  PREREQ:	 genewrap.h 
//  FILE:	 effects.cpp
//	AUTHOR:  Klaus Zerbe <klaus@zerbe.com>
//  ORIGIN:  http://klaus.zerbe.com
//  VERSION: 1.0
//  DATE:    3.2.1999
//  PURPOSE: as said above: light effects :)
//  DISCLAIMER:
//  	This code in moost pars is "stolen" from the GTEST
//      example files: dynlight.*, corona.*, and electric.*
//      Not much comments here, since it is assimilated to the
//      framework in the same way as all my other entities
//
///////////////////////////////////////////////////////////

#include "stdafx.h"
#include "effects.h"
#include "ram.h"

geFloat	EffectScale= 1.0f;

CDynamicLight::CDynamicLight(CEngineWrapper *pEngine) : CEntityTemplate(pEngine)
{
	geEntity_EntitySet *pSet;
	geEntity *pEntity;
	if	(!m_pWorld) throw "no world";
	pSet= geWorld_GetEntitySet(m_pWorld, "DynamicLight");
	if	(!pSet) return;
	for (pEntity= geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity;
	  pEntity= geEntity_EntitySetGetNextEntity(pSet, pEntity)) {
		DynamicLight *pLight= (DynamicLight*)geEntity_GetUserData(pEntity);
		pLight->NumFunctionValues = strlen(pLight->RadiusFunction);
		assert(pLight->NumFunctionValues > 0);
		pLight->IntervalWidth = pLight->RadiusSpeed / (geFloat)pLight->NumFunctionValues;
		pLight->DynLight = geWorld_AddLight(m_pWorld);
	}
}

void CDynamicLight::Render(geXForm3d *pViewPoint, DWORD  dwTime)
{
	geEntity_EntitySet *pSet;
	geEntity *pEntity;
 	if	(!m_pWorld) throw "no world";
	pSet = geWorld_GetEntitySet(m_pWorld, "DynamicLight");
	if	(!pSet) return;
	for (pEntity= geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity;
	  pEntity= geEntity_EntitySetGetNextEntity(pSet, pEntity)) {
		geFloat			Radius;
		geFloat			Percentage;
		int				Index;
		geVec3d			Pos;
		DynamicLight *pLight= (DynamicLight*)geEntity_GetUserData(pEntity);
		assert(pLight->DynLight);
		if	(pLight->Model) {
			geXForm3d	XForm;
			geWorld_GetModelXForm(m_pWorld, pLight->Model, &XForm);
			Pos = pLight->origin;
			if	(pLight->AllowRotation) {
				geVec3d	Center;
				geWorld_GetModelRotationalCenter(m_pWorld, pLight->Model, &Center);
				geVec3d_Subtract(&Pos, &Center, &Pos);
				geXForm3d_Transform(&XForm, &Pos, &Pos);
				geVec3d_Add(&Pos, &Center, &Pos);
			} else geVec3d_Add(&Pos, &XForm.Translation, &Pos);
		} else Pos = pLight->origin;
		assert(pLight->RadiusSpeed > pLight->LastTime);
		Percentage = pLight->LastTime / pLight->RadiusSpeed;
		Index = (int)(Percentage * pLight->NumFunctionValues);
		assert(Index < pLight->NumFunctionValues);
		assert(pLight->RadiusFunction[Index] >= 'a' && pLight->RadiusFunction[Index] <= 'z');
		if	(pLight->InterpolateValues && Index < pLight->NumFunctionValues - 1) {
			geFloat	Remainder;
			geFloat	InterpolationPercentage;
			int		DeltaValue;
			geFloat	Value;

			Remainder = (geFloat)fmod(pLight->LastTime, pLight->IntervalWidth);
			InterpolationPercentage = Remainder / pLight->IntervalWidth;
			DeltaValue = pLight->RadiusFunction[Index + 1] - pLight->RadiusFunction[Index];
			Value = pLight->RadiusFunction[Index] + DeltaValue * InterpolationPercentage;
			Percentage = ((geFloat)(Value - 'a')) / ((geFloat)('z' - 'a'));
		} else Percentage = ((geFloat)(pLight->RadiusFunction[Index] - 'a')) / ((geFloat)('z' - 'a'));
		Radius = Percentage * (pLight->MaxRadius - pLight->MinRadius) + pLight->MinRadius;
		geWorld_SetLightAttributes(m_pWorld, pLight->DynLight, &Pos, &pLight->Color, Radius, GE_TRUE);
		pLight->LastTime = (geFloat)fmod(pLight->LastTime + dwTime, pLight->RadiusSpeed);
	}
}

CCorona::CCorona(CEngineWrapper *pEngine) : CEntityTemplate(pEngine)
{
	m_pCoronaBitmap= NULL;
	if (!geWorld_GetEntitySet(m_pWorld, "Corona")) return;
	m_pCoronaBitmap = CreateAlphaBitmap(m_pContext, "corona.bmp", "corona_a.bmp");
	if (!m_pCoronaBitmap) throw "Bitmap für Corona nicht gefunden";
	if (!geWorld_AddBitmap(m_pWorld, m_pCoronaBitmap)) {
		geBitmap_Destroy(&m_pCoronaBitmap);
		throw "kann Corona-Bitmap nicht anlegen";
	}
}

CCorona::~CCorona()
{
	if (m_pCoronaBitmap && m_pWorld) {
		geWorld_RemoveBitmap(m_pWorld, m_pCoronaBitmap);
		geBitmap_Destroy(&m_pCoronaBitmap);
		m_pCoronaBitmap= NULL;
	}
}

void CCorona::Render(geXForm3d *pViewPoint, DWORD  dwTime)
{
	geEntity_EntitySet *pSet;
	geEntity *pEntity;
	GE_Collision collision;
	if	(!m_pWorld)	return;
	pSet = geWorld_GetEntitySet(m_pWorld, "Corona");
	if	(!pSet)	return;
	for (pEntity= geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity;
	  pEntity = geEntity_EntitySetGetNextEntity(pSet, pEntity))	{
		Corona *	C;
		geVec3d		Pos;
		geFloat		DistanceToCorona;
		geVec3d		Delta;
		geFloat		Radius;
		geBoolean	Visible;
		geBoolean	Fading;
		int32		Leaf;
		C = (Corona*)geEntity_GetUserData(pEntity);
		geWorld_GetLeaf(m_pWorld, &C->origin, &Leaf);

		if (geWorld_MightSeeLeaf(m_pWorld, Leaf)) {
			if	(C->Model) {
				geXForm3d	XForm;
				geWorld_GetModelXForm(m_pWorld, C->Model, &XForm);
				Pos = C->origin;
				if	(C->AllowRotation) {
					geVec3d	Center;
					geWorld_GetModelRotationalCenter(m_pWorld, C->Model, &Center);
					geVec3d_Subtract(&Pos, &Center, &Pos);
					geXForm3d_Transform(&XForm, &Pos, &Pos);
					geVec3d_Add(&Pos, &Center, &Pos);
				} else geVec3d_Add(&Pos, &XForm.Translation, &Pos);
			} else Pos = C->origin;
		}
		geVec3d_Subtract(&Pos, &pViewPoint->Translation, &Delta);
		DistanceToCorona = geVec3d_Length(&Delta);
		if	(!geWorld_Collision(m_pWorld, NULL, NULL, &Pos, &pViewPoint->Translation,
			GE_CONTENTS_SOLID_CLIP,	GE_COLLIDE_MODELS, 0xffffffff, NULL, NULL, &collision) &&
		 	(DistanceToCorona < C->MaxVisibleDistance))	{
			Visible = GE_TRUE;
			C->LastVisibleTime = C->LastTime;
		} else Visible = GE_FALSE;
		Fading = (C->FadeOut && (C->LastTime <= C->LastVisibleTime + C->FadeTime)) ? GE_TRUE : GE_FALSE;
		if	(Visible || Fading)	{
			GE_LVertex	Vert;
			Vert.X = Pos.X;
			Vert.Y = Pos.Y;
			Vert.Z = Pos.Z;
			Vert.r = C->Color.r;
			Vert.g = C->Color.g;
			Vert.b = C->Color.b;
			Vert.a = 255.0f;
			Vert.u = Vert.v = 0.0f;
			if	(Visible) {
				if	(DistanceToCorona >= C->MaxRadiusDistance) {
					Radius = (geFloat)C->MaxRadius;
				} else if (DistanceToCorona <= C->MinRadiusDistance) {
					Radius = (geFloat)C->MinRadius;
				} else {
					geFloat	Slope;
					Slope = (geFloat)(C->MaxRadius - C->MinRadius) / (geFloat)(C->MaxRadiusDistance - C->MinRadiusDistance);
					Radius = (geFloat)C->MinRadius + Slope * (geFloat)(DistanceToCorona - C->MinRadiusDistance);
				}
				C->LastVisibleRadius = Radius;
			} else {
				assert(Fading == GE_TRUE);
				assert(C->LastTime <= C->LastVisibleTime + C->FadeTime);
				Radius = (1.0f - (C->LastTime - C->LastVisibleTime) / C->FadeTime) * C->LastVisibleRadius;
			}
			geWorld_AddPolyOnce(m_pWorld, &Vert, 1, m_pCoronaBitmap, GE_TEXTURED_POINT,
				GE_RENDER_DO_NOT_OCCLUDE_OTHERS | GE_RENDER_DO_NOT_OCCLUDE_SELF, Radius * EffectScale);
		}
		C->LastTime += dwTime;
	}
}


CElectricBolt::CElectricBolt(CEngineWrapper *pEngine) : CEntityTemplate(pEngine)
{
	geEntity_EntitySet *pSet;
	geEntity *pEntity;
	m_pBitmap= NULL;
	pSet = geWorld_GetEntitySet(m_pWorld, "ElectricBolt");
	if	(!pSet) return;
	m_pBitmap = CreateAlphaBitmap(m_pContext, "Bolt.Bmp", "Bolt.Bmp");
	if (!m_pBitmap) throw "Bitmap für ElectricBolt nicht gefunden";
	if (!geWorld_AddBitmap(m_pWorld, m_pBitmap)) {
		geBitmap_Destroy(&m_pBitmap);
		throw "kann Bitmap für ElectricBolt nicht anlegen";
	}
	geSound_System *pSndSys= m_pWrapper->GetSoundSystem();
	if	(pSndSys) {
		geVFile *	File;
		File = geVFile_Open(m_pContext, "loopbzzt.wav", GE_VFILE_OPEN_READONLY);
		if	(!File)	return;
		m_pLoopingDef = geSound_LoadSoundDef(pSndSys, File);
		geVFile_Close(File);
		File = geVFile_Open(m_pContext, "onebzzt.wav", GE_VFILE_OPEN_READONLY);
		if	(!File)	return;
		m_pSingleDef = geSound_LoadSoundDef(pSndSys, File);
		geVFile_Close(File);
	}
	for (pEntity= geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity;
	  pEntity = geEntity_EntitySetGetNextEntity(pSet, pEntity)) {
		ElectricBolt *pBolt= (ElectricBolt*)geEntity_GetUserData(pEntity);
		pBolt->Bolt = Electric_BoltEffectCreate(m_pBitmap, NULL, pBolt->NumPoints, pBolt->Width, pBolt->Wildness);
		Electric_BoltEffectSetColorInfo(pBolt->Bolt, &pBolt->Color, pBolt->DominantColor);
		if	(!pBolt->Bolt) {
			geBitmap_Destroy(&m_pBitmap);
			throw "kann ElectricBolt nicht aufbauen";
		}
		if (!pBolt->Intermittent && pSndSys) {
			pBolt->LoopingSound = geSound_PlaySoundDef(pSndSys, m_pLoopingDef, 0.0f, 0.0f, 0.0f, GE_TRUE);
		}
	}
}

CElectricBolt::~CElectricBolt()
{
	geSound_System *pSndSys= m_pWrapper->GetSoundSystem();
	if (m_pBitmap) {
		geBitmap_Destroy(&m_pBitmap);
		m_pBitmap = NULL;
	}
	if (m_pLoopingDef) {
		geSound_FreeSoundDef(pSndSys, m_pLoopingDef);
		m_pLoopingDef = NULL;
	}
	if (m_pSingleDef) {
		geSound_FreeSoundDef(pSndSys, m_pSingleDef);
		m_pSingleDef = NULL;
	}
}

static	geFloat	frand(geFloat Low, geFloat High);

#define	LIGHTNINGSTROKEDURATION	0.05f

void CElectricBolt::Render(geXForm3d *pViewPoint, DWORD  dwTime) 
{
	geEntity_EntitySet *pSet;
	geEntity *pEntity;
	geVec3d	MidPoint;
	int32 Leaf;
 	if	(!m_pWorld) throw "no world";
	pSet= geWorld_GetEntitySet(m_pWorld, "ElectricBolt");
	if	(!pSet) return;
	geSound_System *pSndSys= m_pWrapper->GetSoundSystem();
	for (pEntity = geEntity_EntitySetGetNextEntity(pSet, NULL); pEntity;
	   pEntity= geEntity_EntitySetGetNextEntity(pSet, pEntity)) {
		ElectricBolt* pBolt= (ElectricBolt*)geEntity_GetUserData(pEntity);
		geVec3d_Subtract(&pBolt->Terminus->origin, &pBolt->origin, &MidPoint);
		geVec3d_AddScaled(&pBolt->origin, &MidPoint, 0.5f, &MidPoint);
		geWorld_GetLeaf(m_pWorld, &MidPoint, &Leaf);
		if (geWorld_MightSeeLeaf(m_pWorld, Leaf)) {
			float vol, pan, pitch;
			geSound3D_GetConfig(m_pWorld, pViewPoint, &MidPoint, 300.0f, 2.0f, &vol, &pan, &pitch);
			pBolt->LastTime += dwTime;
			if	(!pBolt->Intermittent ||
			  (pBolt->LastTime - pBolt->LastBoltTime > frand(pBolt->MaxFrequency, pBolt->MinFrequency))) {
				Electric_BoltEffectAnimate(pBolt->Bolt, &pBolt->origin, &pBolt->Terminus->origin);
				if (pBolt->Intermittent && pSndSys)
					geSound_PlaySoundDef(pSndSys, m_pSingleDef, vol, pan, pitch, GE_FALSE);
				pBolt->LastBoltTime = pBolt->LastTime;
			}
			if	(pBolt->LastTime - pBolt->LastBoltTime <= LIGHTNINGSTROKEDURATION)
				Electric_BoltEffectRender(m_pWorld, pBolt->Bolt, pViewPoint);
			if	(!pBolt->Intermittent && pSndSys && pBolt->LoopingSound) {
				geSound_ModifySound(pSndSys, pBolt->LoopingSound, vol, pan, pitch);
			}
		}
	}
}


static	geFloat	frand(geFloat Low, geFloat High)
{
	geFloat	Range;
	Range = High - Low;

	return ((geFloat)((rand() % 1000) + 1)) / 1000.0f * Range + Low;
}

typedef struct	Electric_BoltEffect
{
	int			beInitialized;
	int			beNumPoints;
	geFloat		beWildness;

	/* For rendering */
	geVec3d		beStart;
	geVec3d		beEnd;

	/* For generating the geometry */
	geVec3d	*	beCenterPoints;
	geVec3d *	beCurrentPoint;

	geFloat		beBaseColors[3];
	geFloat		beCurrentColors[3];
	geFloat		beBaseBlue;
	int			beDecayRate;
	int			beDominantColor;

	int			beWidth;

	geBitmap	*beBitmap;

}	Electric_BoltEffect;

static	int		logBase2(int n)
{
	int	i = 0;

	assert(n != 0);

	while	(!(n & 1))
	{
		n = n >> 1;
		i++;
	}

	assert((n & ~1) == 0);

	return i;
}


Electric_BoltEffect * Electric_BoltEffectCreate(
	geBitmap		*Bitmap,
	geBitmap		*Bitmap2,
 	int NumPolys,
 	int Width,
	geFloat Wildness)
{
	Electric_BoltEffect *	be;
	GE_RGBA					color;

	assert(Wildness >= 0.0f && Wildness <= 1.0f);

	/* Asserts power of 2 */
	logBase2(NumPolys);

	be = (Electric_BoltEffect *)geRam_Allocate(sizeof(*be));
	if	(!be)
		return be;

	memset(be, 0, sizeof(*be));

	be->beCenterPoints = (geVec3d *)geRam_Allocate(sizeof(*be->beCenterPoints) * (NumPolys + 1));
	if	(!be->beCenterPoints)
		goto fail;

	be->beBitmap	= Bitmap;
	be->beNumPoints	= NumPolys;
	be->beWildness	= Wildness;
	be->beWidth		= Width;
	color.r = 160.0f;
	color.g = 160.0f;
	color.b = 255.0f;
	Electric_BoltEffectSetColorInfo(be, &color, ELECTRIC_BOLT_BLUEDOMINANT);

	return be;

fail:
	if	(be->beCenterPoints)
		free(be->beCenterPoints);

	return NULL;
}

void Electric_BoltEffectDestroy(Electric_BoltEffect *Effect)
{
	free(Effect->beCenterPoints);
	free(Effect);
}

static	geFloat	GaussRand(void)
{
	int	i;
	int	r;

	r = 0;

	for	(i = 0; i < 6; i++)
		r = r + rand() - rand();

	return (geFloat)r / ((geFloat)RAND_MAX * 6.0f);
}

static	void	subdivide(
	Electric_BoltEffect *	be,
	const geVec3d *			start,
	const geVec3d *			end,
	geFloat 				s,
	int 					n)
{
	geVec3d	tmp;

	if	(n == 0)
	{
		be->beCurrentPoint++;
		*be->beCurrentPoint = *end;
		return;
	}
	
	tmp.X = (end->X + start->X) / 2 + s * GaussRand();
	tmp.Y = (end->Y + start->Y) / 2 + s * GaussRand();
	tmp.Z = (end->Z + start->Z) / 2 + s * GaussRand();
	subdivide(be,  start, &tmp, s / 2, n - 1);
	subdivide(be, &tmp,    end, s / 2, n - 1);
}

#define	LIGHTNINGWIDTH 8.0f

static	void	genLightning(
	Electric_BoltEffect *	be,
	int 					RangeLow,
	int 					RangeHigh,
	const geVec3d *			start,
	const geVec3d *			end)
{
	geFloat	length;
	int		seed;

	assert(be);
	assert(start);
	assert(end);
	assert(RangeHigh > RangeLow);

	/* Manhattan length is good enough for this */
	length = (geFloat)(fabs(start->X - end->X) +
						fabs(start->Y - end->Y) +
						fabs(start->Z - end->Z));

	seed = rand();
	srand(seed);

	be->beCurrentPoint					= be->beCenterPoints + RangeLow;
	be->beCenterPoints[RangeLow]		= *start;
	be->beCenterPoints[RangeHigh] 		= *end;
	subdivide(be, start, end, length * be->beWildness, logBase2(RangeHigh - RangeLow));
}

void Electric_BoltEffectSetColorInfo(
	Electric_BoltEffect *	Effect,
	GE_RGBA *				BaseColor,
	int						DominantColor)
{
	Effect->beBaseColors[0]		= BaseColor->r;
	Effect->beBaseColors[1]		= BaseColor->g;
	Effect->beBaseColors[2]		= BaseColor->b;
	Effect->beCurrentColors[0]	= BaseColor->r;
	Effect->beCurrentColors[1]	= BaseColor->g;
	Effect->beCurrentColors[2]	= BaseColor->b;
	Effect->beDominantColor 	= DominantColor;
}

void Electric_BoltEffectAnimate(
	Electric_BoltEffect *	Effect,
	const geVec3d *			start,
	const geVec3d *			end)
{
	int		dominant;
	int		nonDominant1;
	int		nonDominant2;
	geVec3d	SubdivideStart;
	geVec3d	SubdivideEnd;
	int		LowIndex;
	int		HighIndex;

	Effect->beStart = *start;
	Effect->beEnd	= *end;

	dominant = Effect->beDominantColor;
	nonDominant1 = (dominant + 1) % 3;
	nonDominant2 = (dominant + 2) % 3;
	if	(Effect->beBaseColors[nonDominant1] == Effect->beCurrentColors[nonDominant1])
	{
		int	DecayRate;
		int	Spike;

		DecayRate = rand() % (int)(Effect->beBaseColors[dominant] - Effect->beBaseColors[nonDominant1]);
		DecayRate = max(DecayRate, 5);
		Effect->beDecayRate = DecayRate;
		if	(Effect->beBaseColors[nonDominant1] >= 1.0f)
			Spike = rand() % (int)(Effect->beBaseColors[nonDominant1]);
		else
			Spike = 0;
		Effect->beCurrentColors[nonDominant1] -= Spike;
		Effect->beCurrentColors[nonDominant2] -= Spike;
	}
	else
	{
		Effect->beCurrentColors[nonDominant1] += Effect->beDecayRate;
		Effect->beCurrentColors[nonDominant2] += Effect->beDecayRate;
		if	(Effect->beCurrentColors[nonDominant1] > Effect->beBaseColors[nonDominant1])
		{
			Effect->beCurrentColors[nonDominant1] = Effect->beBaseColors[nonDominant1];
			Effect->beCurrentColors[nonDominant2] = Effect->beBaseColors[nonDominant2];
		}
	}

	if	(Effect->beInitialized && Effect->beNumPoints > 16)
	{
		int		P1=0;
		int		P2=0;
		int		P3=0;
		int		P4=0;

		switch	(rand() % 7)
		{
			case	0:
				genLightning(Effect, 0, Effect->beNumPoints, start, end);
				return;

			case	1:
			case	2:
			case	3:
				P1 = 0;
				P2 = Effect->beNumPoints / 2;
				P3 = P2 + Effect->beNumPoints / 4;
				P4 = Effect->beNumPoints;
				break;

			case	4:
			case	5:
			case	6:
				P1 = 0;
				P3 = Effect->beNumPoints / 2;
				P2 = P3 - Effect->beNumPoints / 4;
				P4 = Effect->beNumPoints;
				break;
		}
		SubdivideStart = Effect->beCenterPoints[P1];
		SubdivideEnd = Effect->beCenterPoints[P2];
		genLightning(Effect, P1, P2, &SubdivideStart, &SubdivideEnd);
		SubdivideStart = Effect->beCenterPoints[P2];
		SubdivideEnd = Effect->beCenterPoints[P3];
		genLightning(Effect, P2, P3, &SubdivideStart, &SubdivideEnd);
		SubdivideStart = Effect->beCenterPoints[P3];
		SubdivideEnd = Effect->beCenterPoints[P4];
		genLightning(Effect, P3, P4, &SubdivideStart, &SubdivideEnd);
	}
	else
	{
		Effect->beInitialized = 1;
		LowIndex = 0;
		HighIndex = Effect->beNumPoints;
		SubdivideStart = *start;
		SubdivideEnd   = *end;

		genLightning(Effect, LowIndex, HighIndex, &SubdivideStart, &SubdivideEnd);
	}
}

#define	LIGHTNINGALPHA	160.0f

void Electric_BoltEffectRender(
	geWorld *				World,
	Electric_BoltEffect *	be,
	const geXForm3d *		XForm)
{
	geVec3d			perp;
	geVec3d			temp;
	geVec3d			in;
	GE_LVertex 		verts[4];
	int				i;

	geVec3d_Subtract(&be->beStart, &be->beEnd, &temp);
	geXForm3d_GetIn(XForm, &in);

	geVec3d_CrossProduct(&in, &temp, &perp);
	geVec3d_Normalize(&perp);

	geVec3d_Scale(&perp, be->beWidth / 2.0f, &perp);

	/*
		We've got the perpendicular to the camera in the
		rough direction of the electric bolt center.  Walk
		the left and right sides, constructing verts, then
		do the drawing.
	*/
	for	(i = 0; i < be->beNumPoints - 1; i++)
	{
		geVec3d	temp;

		geVec3d_Subtract(&be->beCenterPoints[i], &perp, &temp);
		verts[0].X = temp.X;
		verts[0].Y = temp.Y;
		verts[0].Z = temp.Z;
		verts[0].u = 0.0f;
		verts[0].v = 0.0f;
		verts[0].r = be->beCurrentColors[0];
		verts[0].g = be->beCurrentColors[1];
		verts[0].b = be->beCurrentColors[2];
		verts[0].a = LIGHTNINGALPHA;

		geVec3d_Subtract(&be->beCenterPoints[i + 1], &perp, &temp);
		verts[1].X = temp.X;
		verts[1].Y = temp.Y;
		verts[1].Z = temp.Z;
		verts[1].u = 0.0f;
		verts[1].v = 1.0f;
		verts[1].r = be->beCurrentColors[0];
		verts[1].g = be->beCurrentColors[1];
		verts[1].b = be->beCurrentColors[2];
		verts[1].a = LIGHTNINGALPHA;

		geVec3d_Add(&be->beCenterPoints[i + 1], &perp, &temp);
		verts[2].X = temp.X;
		verts[2].Y = temp.Y;
		verts[2].Z = temp.Z;
		verts[2].u = 1.0f;
		verts[2].v = 1.0f;
		verts[2].r = be->beCurrentColors[0];
		verts[2].g = be->beCurrentColors[1];
		verts[2].b = be->beCurrentColors[2];
		verts[2].a = LIGHTNINGALPHA;

		geVec3d_Add(&be->beCenterPoints[i], &perp, &temp);
		verts[3].X = temp.X;
		verts[3].Y = temp.Y;
		verts[3].Z = temp.Z;
		verts[3].u = 1.0f;
		verts[3].v = 0.0f;
		verts[3].r = be->beCurrentColors[0];
		verts[3].g = be->beCurrentColors[1];
		verts[3].b = be->beCurrentColors[2];
		verts[3].a = LIGHTNINGALPHA;

		geWorld_AddPolyOnce(World,
							verts,
							4,
							be->beBitmap,
							GE_TEXTURED_POLY,
							GE_RENDER_DO_NOT_OCCLUDE_OTHERS,
							1.0f);

	}
}
