#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include "PajaTypes.h"
#include "ColorC.h"
#include "FlareRendererC.h"
#include <math.h>
#include <string>

using namespace PajaTypes;



static	uint32	g_ui32Seed = 1;

inline
uint32
irand()
{
	return ((uint32)(g_ui32Seed = 0x015a4e35 * g_ui32Seed + 1) >> 16);
}


FlareRendererC::FlareRendererC()
{
}

FlareRendererC::~FlareRendererC()
{
}

void
FlareRendererC::render_flare( uint8* pBuffer, uint32 ui32Width, uint32 ui32Height,
							  const ColorC& rBGColor, const ColorC& rGlowColor, const PajaTypes::ColorC& rSpotColor, const PajaTypes::ColorC& rSpikesColor, bool bUseTransparency )
{
	int		r, g, b, a;
	float	dx, dy, mag, ymag;

	float	maxDist = (float)ui32Width / 2.0f;
	maxDist *= maxDist;

	uint8*	pDest = 0;
	uint32	i, j;

	// Draw glow
	pDest = (uint8*)pBuffer;
	for( i = 0; i < ui32Height; i++ ) {
		dy = (float)i - (float)ui32Height / 2.0f;
		ymag = (float)exp( -dy * dy / maxDist );
		for( j = 0; j < ui32Width; j++ ) {

			dx = (float)j - (float)ui32Width / 2.0f;
			mag = (float)exp( -dx * dx / maxDist ) * ymag;
			mag *= mag;
			mag *= 0.5f;
			r = (int)((rGlowColor[0] * mag + rBGColor[0] * (1.0f - mag)) * 255.0f);
			g = (int)((rGlowColor[1] * mag + rBGColor[1] * (1.0f - mag)) * 255.0f);
			b = (int)((rGlowColor[2] * mag + rBGColor[2] * (1.0f - mag)) * 255.0f);
			a = (int)((rGlowColor[3] * mag + rBGColor[3] * (1.0f - mag)) * 255.0f);

			*pDest++ = (uint8)b;
			*pDest++ = (uint8)g;
			*pDest++ = (uint8)r;
			*pDest++ = (uint8)a;
		}
	}

	// Draw spot
	pDest = (uint8*)pBuffer;
	for( i = 0; i < ui32Height; i++ ) {
		dy = (float)i - (float)ui32Height / 2.0f;
		ymag = (float)exp( -dy * dy / maxDist );
		for( j = 0; j < ui32Width; j++ ) {

			dx = (float)j - (float)ui32Width / 2.0f;
			mag = (float)exp( -dx * dx / maxDist ) * ymag;
			mag = pow( mag, 15 ) * 1.3f;
			r = (int)(rSpotColor[0] * mag * 255.0f);
			g = (int)(rSpotColor[1] * mag * 255.0f);
			b = (int)(rSpotColor[2] * mag * 255.0f);
			a = (int)(rSpotColor[3] * mag * 255.0f);

			*pDest = (uint8)__min( b + *pDest, 255 );
			pDest++;
			*pDest = (uint8)__min( g + *pDest, 255 );
			pDest++;
			*pDest = (uint8)__min( r + *pDest, 255 );
			pDest++;
			*pDest = (uint8)__min( a + *pDest, 255 );
			pDest++;
		}
	}

#define		SPIKE_COUNT		64
#define		SPIKE_MASK		(SPIKE_COUNT - 1)

	g_ui32Seed = 12345678;
	float32	f32Spikes[SPIKE_COUNT];
	ZeroMemory( f32Spikes, SPIKE_COUNT * sizeof( float32 ) );
	for( i = 0; i < 16; i++ )
		f32Spikes[irand() & SPIKE_MASK] = (float32)(32 + (irand() & 255)) / (32.0f + 255.0f);

	// Draw spikes
	pDest = (uint8*)pBuffer;
	for( i = 0; i < ui32Height; i++ ) {
		dy = (float)i - (float)ui32Height / 2.0f;
		ymag = (float)exp( -dy * dy / maxDist );
		for( j = 0; j < ui32Width; j++ ) {


			dx = (float)j - (float)ui32Width / 2.0f;

			float32	f32Angle = atan2( dx, dy );
			f32Angle = ((f32Angle / M_PI) * 0.5f + 0.5f) * (float32)SPIKE_COUNT;

			int32	i32Idx1 = (int32)f32Angle;
			int32	i32Idx2 = i32Idx1 + 1;
			float32	f32A = f32Angle - (float32)i32Idx1;

			i32Idx1 &= SPIKE_MASK;
			i32Idx2 &= SPIKE_MASK;

			mag = (float)exp( -dx * dx / maxDist ) * ymag;
			mag = pow( mag, 15 ) + mag * 0.55 * (f32Spikes[i32Idx1] * (1.0f - f32A) + f32Spikes[i32Idx2] * f32A);
			mag = __min( mag, 1.0f );
			mag *= mag; //pow( mag, 5 );

			r = (int)(rSpikesColor[0] * mag * 255.0f);
			g = (int)(rSpikesColor[1] * mag * 255.0f);
			b = (int)(rSpikesColor[2] * mag * 255.0f);
			a = (int)(rSpikesColor[3] * mag * 255.0f);

			*pDest = (uint8)__min( b + *pDest, 255 );
			pDest++;
			*pDest = (uint8)__min( g + *pDest, 255 );
			pDest++;
			*pDest = (uint8)__min( r + *pDest, 255 );
			pDest++;
			*pDest = (uint8)__min( a + *pDest, 255 );
			pDest++;
		}
	}

	if( bUseTransparency ) {

		// Make checker pattern for transparen areas

		pDest = (uint8*)pBuffer;

		for( i = 0; i < ui32Height; i++ ) {
			for( j = 0; j < ui32Width; j++ ) {

				int32	i32Grey = 255;

				if( (((i >> 3) ^ (j >> 3)) & 1) == 0 ) {
					i32Grey = 204;
				}

				int32	i32A = pDest[3];

				i32Grey *= (255 - i32A);

				pDest[0] = (uint8)(((int32)pDest[0] * i32A + i32Grey) >> 8);
				pDest[1] = (uint8)(((int32)pDest[1] * i32A + i32Grey) >> 8);
				pDest[2] = (uint8)(((int32)pDest[2] * i32A + i32Grey) >> 8);
				pDest[3] = pDest[3];

				pDest += 4;
			}
		}

	}
}


