#include "stdafx.h"
#include "basic.h"
#include "Eroc.h"
#include "time.h"
#include "OGLState.h"
#include <stdlib.h>

#ifdef import_globals
#undef import_globals
#endif
#include "globals.h"

// Framerate
int theNrFramesThisSec = 0;
int theFPSLastSec = 0;
time_t theLastTime = 0;

#define PI 3.141592654

/////////////////////////////////////////////////////////////////////////////
int gNrAnims = 0;
Animation gAnims[256];

void	LoadAnims()
{
	FILE* AnimList = fopen("AnimList.txt", "r");
	if (! AnimList )
		return;

	long int Duration;
	char Token[256];
	while (1 == fscanf(AnimList, " %s", Token ))
	{		
		if (strcmp(Token, "BEGIN") == 0)
		{		
			Animation& Anim = gAnims[gNrAnims];
			while(2 == fscanf(AnimList, " %s %ld", Token, &Duration ))
			{
				CreateTextureFromFile(Token);
				Anim.mFrames[Anim.mNrFrames++] = new Frame(Token, Duration);
			}

			gNrAnims++;

			if (strcmp(Token, "END") != 0)
				break;			
		}
	}
	fclose(AnimList);
}

Animation*	GetAnim(int inNr)
{
	Animation* Result = 0;
	if (inNr >= 0 && inNr < gNrAnims)
		Result = &(gAnims[inNr]);
	return Result;
}

void	FreeAnims()
{
	for (int i = 0; i < gNrAnims; i++)
	{
		for ( int j = 0; j < gAnims[i].mNrFrames; j++)
			delete gAnims[i].mFrames[j];
	}
	gNrAnims = 0;
}

/////////////////////////////////////////////////////////////////////////////

EROC_API BOOL Clear ( void ) 
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	return true;
}

EROC_API BOOL Background ( signed long inImageNr ) 
{
	return BackgroundFade(inImageNr, 256);
}


EROC_API BOOL BackgroundFade ( signed long inImageNr, signed long inOpacity ) 
{
	PushOGL_Blend(true);
	PushOGL_BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	PushOGL_Texture2D(true);

	Texture* Tex = GetTexture(inImageNr);
	PushOGL_TextureUsed(Tex->mOpenGLTex);

	// sanity check
	if (inOpacity < 0)
		inOpacity = 0;
	else if (inOpacity > 256)
		inOpacity = 256;

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix ( );
	
	float ScaleX = Tex->mScaleX;
	float ScaleY = Tex->mScaleY;
	glBegin ( GL_QUADS );
		glNormal3f( 0.0f, 0.0f, 1.0f);
		glColor4f ( 1, 1, 1, inOpacity/256.0f );
		glTexCoord2f(0, ScaleY);		glVertex3f (-1.0,-1.0, 0 );
		glTexCoord2f(ScaleX, ScaleY);	glVertex3f ( 1.0,-1.0, 0 );
		glTexCoord2f(ScaleX, 0);		glVertex3f ( 1.0, 1.0, 0 );
		glTexCoord2f(0, 0);				glVertex3f (-1.0, 1.0, 0 );
	glEnd ( );	
	glPopMatrix ( );

	PopOGL_TextureUsed();
	PopOGL_Texture2D();
	PopOGL_BlendFunc();	
	PopOGL_Blend();						
	return true;
}

EROC_API BOOL FastBackground ( signed long inImageNr, signed long inPosX, signed long inPosY,
							   signed long inSizeX, signed long inSizeY )
{
	PushOGL_Texture2D(true);
	Texture* Tex = GetTexture(inImageNr);		
	PushOGL_TextureUsed(Tex->mOpenGLTex);
	
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix ( );
	
	float ScaleX = Tex->mScaleX;
	float ScaleY = Tex->mScaleY;

	float TexX1 = ScaleX*inPosX/1000.0f;
	float TexY1 = ScaleY*inPosY/1000.0f;
	float TexX2 = TexX1 + ScaleX*inSizeX/1000.0f;
	float TexY2 = TexY1 + ScaleY*inSizeY/1000.0f;
	glBegin ( GL_QUADS );
		glNormal3f( 0.0f, 0.0f, 1.0f);
		glColor3f ( 1, 1, 1 );
		glTexCoord2f(TexX1,TexY2);		glVertex3f ( -1.0, -1.0, 0 );
		glTexCoord2f(TexX2,TexY2);		glVertex3f (  1.0, -1.0, 0 );
		glTexCoord2f(TexX2,TexY1);		glVertex3f (  1.0,  1.0, 0 );
		glTexCoord2f(TexX1,TexY1);		glVertex3f ( -1.0,  1.0, 0 );
	glEnd ( );

	glPopMatrix ( );

	PopOGL_TextureUsed();
	PopOGL_Texture2D();

	return true;
}

EROC_API BOOL Image( signed long inImageNr, signed long inPosX, signed long inPosY,
					 signed long inScale, signed long inOpacity ) 
{
	PushOGL_Texture2D(true);
	Texture* Tex = GetTexture(inImageNr);
	PushOGL_TextureUsed(Tex->mOpenGLTex);

	// sanity check
	if (inOpacity < 0)
		inOpacity = 0;
	else if (inOpacity > 256)
		inOpacity = 256;

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix ( );

	float TCenterX = Tex->mScaleX/2;
	float TCenterY = Tex->mScaleY/2;
	float THalfX =  Tex->mScaleX/2;
	float THalfY =  Tex->mScaleY/2;
	
	float CenterX = 2*inPosX/gVScreenX - 1;
	float CenterY = 1-2*inPosY/gVScreenY ;
	float HalfX = inScale *Tex->mSizeX/(gVScreenX*1000);
	float HalfY = inScale *Tex->mSizeY/(gVScreenY*1000);
	
	glBegin ( GL_QUADS );
		glNormal3f( 0.0f, 0.0f, 1.0f);
		glColor4f ( 1, 1, 1, inOpacity/256.0f );
		glTexCoord2f(TCenterX -THalfX, TCenterY+THalfY);	glVertex3f (CenterX-HalfX,CenterY-HalfY, 0 );
		glTexCoord2f(TCenterX +THalfX, TCenterY+THalfY);	glVertex3f (CenterX+HalfX,CenterY-HalfY, 0 );
		glTexCoord2f(TCenterX +THalfX, TCenterY-THalfY);	glVertex3f (CenterX+HalfX,CenterY+HalfY, 0 );
		glTexCoord2f(TCenterX -THalfX, TCenterY-THalfY);	glVertex3f (CenterX-HalfX,CenterY+HalfY, 0 );
	glEnd ( );

	glPopMatrix ( );

	PopOGL_TextureUsed();
	PopOGL_Texture2D();

	return true;
}

EROC_API BOOL Animate( signed long inAnimNr, signed long inPosX, signed long inPosY,
					 signed long inScale, signed long inOpacity, signed long inTime ) 
{
	Animation* Anim = GetAnim(inAnimNr);
	if ( Anim )
	{
		int Frame = -1;
		while (inTime >= 0)
		{
			if ( ++Frame >= Anim->mNrFrames)
				Frame = 0;

			inTime -= Anim->mFrames[Frame]->mDuration;
		}
		int ImageNr = CreateTextureFromFile(Anim->mFrames[Frame]->mName);

		Image( ImageNr, inPosX, inPosY, inScale, inOpacity);
	}
	return true;
}

EROC_API BOOL PrintNr ( signed long inNr, signed long inPosX, signed long inPosY )
{
	int theX = inPosX;
	int theY = (int)(gVScreenY - inPosY);

	PushOGL_Blend(false);

	char String[256];
	sprintf (String, "%li", inNr);
	glPrint(theX, theY,String, 0);

	PopOGL_Blend();
	return true;
}

EROC_API BOOL ShowFPS ( signed long inPosX, signed long inPosY )
{
	PushOGL_Blend(false);
	// Calculate FPS, should move to BeginNewFrame
	time_t theTime = time(0);
	if (theTime != theLastTime)
	{
		theLastTime = theTime;
		theFPSLastSec = theNrFramesThisSec;
		theNrFramesThisSec = 0;
	}
	theNrFramesThisSec++;

	int theX = inPosX;
	int theY = (int)(gVScreenY - inPosY);
	char theFPS[10];
	sprintf(theFPS, "%d", theFPSLastSec);
	glPrint(theX, theY, theFPS ,0);	// Print GL Text To The Screen

	PopOGL_Blend();
	return true;
}

// Nr waves = x/1000 * up & down wave
// Size : 1000 = size image
// Offset: 1000 = 1 up/down sine wave
EROC_API BOOL Wave( signed long inImageNr, signed long inPosX, signed long inPosY,
					 signed long inScale, signed long inOpacity,
					 signed long inWavesX, signed long inWavesY, signed long inSizeX, signed long inSizeY,
					 signed long inOffsetX,signed long inOffsetY)
{
	Texture* Tex = GetTexture(inImageNr);

	int SectionsX = 1;
	int SectionsY = 1;
	if (inWavesX)
	{
		// for now, take about 15 sections per wave, regardless of magnitude
		SectionsX = 15*inWavesX;
	}
	if (inWavesY)
	{
		// for now, take about 15 sections per wave, regardless of magnitude
		SectionsY = 15*inWavesY;
	}

	// sanity check
	if (inOpacity < 0)
		inOpacity = 0;
	else if (inOpacity > 256)
		inOpacity = 256;

	GLboolean TextureEnable = glIsEnabled(GL_TEXTURE_2D);
	if ( !TextureEnable)
		glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix ( );

	float TCenterX = Tex->mScaleX/2;
	float TCenterY = Tex->mScaleY/2;
	float THalfX =  Tex->mScaleX/2;
	float THalfY =  Tex->mScaleY/2;
	
	float CenterX = 2*inPosX/gVScreenX - 1;
	float CenterY = 1-2*inPosY/gVScreenY ;
	float HalfX = inScale *Tex->mSizeX/(gVScreenX*1000);
	float HalfY = inScale *Tex->mSizeY/(gVScreenY*1000);

	glBindTexture(GL_TEXTURE_2D, Tex->mOpenGLTex);
	glNormal3f( 0.0f, 0.0f, 1.0f);
	glColor4f ( 1, 1, 1, inOpacity/256.0f );

	float StartX = CenterX - HalfX;
	float StartY = CenterY - HalfY;
	float IncX = 2*HalfX/SectionsX;
	float IncY = 2*HalfY/SectionsY;

	float TStartX = TCenterX - THalfX;
	float TStartY = TCenterY + THalfY;
	float TIncX = 2*THalfX/SectionsX;
	float TIncY = 2*THalfY/SectionsY;

	for (int j = 0; j < SectionsY; j++)
	{

		// X waves are based on y-coordinates and vice-versa
		float WaveX = HalfX*inSizeY/1000.0 * sin( 2.0*PI * inOffsetY/1000.0 +  (2.0*PI * j * inWavesX) / SectionsX );
		float WaveXP = HalfX*inSizeY/1000.0 * sin( 2.0*PI * inOffsetY/1000.0 + (2.0*PI * (j+1) * inWavesX) / SectionsX );

		for (int i = 0; i < SectionsX; i++)
		{
			float WaveY = HalfY*inSizeX/1000.0 * sin( 2.0*PI*inOffsetX/1000.0 + (2.0*PI * i * inWavesY) / SectionsY );
			float WaveYP = HalfY*inSizeX/1000.0 * sin( 2.0*PI*inOffsetX/1000.0 + (2.0*PI * (i+1) * inWavesY) / SectionsY );

			glBegin(GL_QUADS);
				glTexCoord2f(TStartX + i*TIncX, TStartY - j*TIncY);			glVertex3f (StartX + i*IncX +WaveX, StartY + j*IncY +WaveY, 0 );
				glTexCoord2f(TStartX + (i+1)*TIncX, TStartY - j*TIncY);		glVertex3f (StartX + (i+1)*IncX +WaveX, StartY + j*IncY +WaveYP, 0 );
				glTexCoord2f(TStartX + (i+1)*TIncX, TStartY - (j+1)*TIncY);	glVertex3f (StartX + (i+1)*IncX +WaveXP, StartY + (j+1)*IncY +WaveYP, 0 );
				glTexCoord2f(TStartX + i*TIncX, TStartY - (j+1)*TIncY);		glVertex3f (StartX + i*IncX +WaveXP, StartY + (j+1)*IncY +WaveY, 0 );
			glEnd();
		}
	}

	glPopMatrix ( );

	if (! TextureEnable)
		glDisable(GL_TEXTURE_2D);

	return true;
}

// 
void	
GreyTexture(unsigned int* inLFB, int inX, int inY)
{
	for (unsigned int y = 0; y < inY; y++)
		for (unsigned int x = 0; x < inX; x++)
		{		
			// Monochrome:  red		= 30% = 76/255;
			//				green	= 59% = 151/255
			//				blue	= 11% = 28/255

			unsigned int theColor = *(inLFB + y*inX + x);
			unsigned int theRed   = 76 * ((theColor >> 16 ) & 0xFF);
			unsigned int theGreen = 151 * ((theColor >> 8 ) & 0xFF);
			unsigned int theBlue  = 28 * ((theColor >> 0 ) & 0xFF);

			*(inLFB + y*inX + x) = 0x010101 * ((theRed + theGreen + theBlue) >> 8);
		}
}

void
DeformTextureBlurHor(unsigned int* inLFB, int inX, int inY, int inAmount)
{
	unsigned int* theTempLFB = new unsigned int[inX*inY];

	for (int y = 0; y < inY; y++)
	{
		// Start cumulative total		
		unsigned int theTotalA = 0, theTotalR = 0, theTotalG = 0, theTotalB = 0;

		for (int i = inX - inAmount; i <= inX + inAmount; i++) 
			// add inX so it's always positive, for the % inX later
		{
			unsigned int* theCurPixel = inLFB + (y * inX) + ( i % inX);
			theTotalA += ((*theCurPixel) >> 24) & 0xFF;
			theTotalR += ((*theCurPixel) >> 16) & 0xFF;
			theTotalG += ((*theCurPixel) >> 8) & 0xFF;
			theTotalB += (*theCurPixel) & 0xFF;
		}
		
		for (int x = 0; x < inX; x++)
		{
			// Draw pixel
			unsigned int theA = (theTotalA*2 + 1) / (2 + (inAmount << 2));
			unsigned int theR = (theTotalR*2 + 1) / (2 + (inAmount << 2));
			unsigned int theG = (theTotalG*2 + 1) / (2 + (inAmount << 2));
			unsigned int theB = (theTotalB*2 + 1) / (2 + (inAmount << 2));
			*(theTempLFB + y * inX + x) = (theA << 24) + (theR << 16) + (theG << 8) + theB;

			// Update Total
			unsigned int* theNewPixel = inLFB + (y * inX) + ( (x + inAmount + 1 ) % inX);
			theTotalA += ((*theNewPixel) >> 24) & 0xFF;
			theTotalR += ((*theNewPixel) >> 16) & 0xFF;
			theTotalG += ((*theNewPixel) >> 8) & 0xFF;
			theTotalB += (*theNewPixel) & 0xFF;

			unsigned int* theOldPixel = inLFB + (y * inX) + ( (x + inX - inAmount ) % inX);
			theTotalA -= ((*theOldPixel) >> 24) & 0xFF;
			theTotalR -= ((*theOldPixel) >> 16) & 0xFF;
			theTotalG -= ((*theOldPixel) >> 8) & 0xFF;
			theTotalB -= (*theOldPixel) & 0xFF;
		}	
	}
	for (int i = 0; i < inX*inY; i++)
		*(inLFB+i) = *(theTempLFB+i);
    
    delete[] theTempLFB;
}

void
DeformTextureBlurVer(unsigned int* inLFB, int inX, int inY, int inAmount)
{
	unsigned int* theTempLFB = new unsigned int[inX*inY];

	for (int x = 0; x < inX; x++)
	{
		// Start cumulative total		
		unsigned int theTotalA = 0, theTotalR = 0, theTotalG = 0, theTotalB = 0;

		for (int i = inY - inAmount; i <= inY + inAmount; i++)
		{	
			// add inX so it's always positive, for the % inX later
			unsigned int* theCurPixel = inLFB + (( i % inY) * inX) + x;
			theTotalA += ((*theCurPixel) >> 24) & 0xFF;
			theTotalR += ((*theCurPixel) >> 16) & 0xFF;
			theTotalG += ((*theCurPixel) >> 8) & 0xFF;
			theTotalB += (*theCurPixel) & 0xFF;			
		}
		
		for (int y = 0; y < inY; y++)
		{
			// Draw pixel
			unsigned int theA = (theTotalA*2 + 1) / (2 + (inAmount << 2));
			unsigned int theR = (theTotalR*2 + 1) / (2 + (inAmount << 2));
			unsigned int theG = (theTotalG*2 + 1) / (2 + (inAmount << 2));
			unsigned int theB = (theTotalB*2 + 1) / (2 + (inAmount << 2));
			*(theTempLFB + y * inX + x) = (theA << 24) + (theR << 16) + (theG << 8) + theB;

			// Update Total
			unsigned int* theNewPixel = inLFB + x + ( (y + inAmount + 1 ) % inY) * inX;
			theTotalA += ((*theNewPixel) >> 24) & 0xFF;
			theTotalR += ((*theNewPixel) >> 16) & 0xFF;
			theTotalG += ((*theNewPixel) >> 8) & 0xFF;
			theTotalB += (*theNewPixel) & 0xFF;

			unsigned int* theOldPixel = inLFB + x + ( (y + inY - inAmount ) % inY) * inX;
			theTotalA -= ((*theOldPixel) >> 24) & 0xFF;
			theTotalR -= ((*theOldPixel) >> 16) & 0xFF;
			theTotalG -= ((*theOldPixel) >> 8) & 0xFF;
			theTotalB -= (*theOldPixel) & 0xFF;
		}
	}
	for (int i = 0; i < inX*inY; i++)
		*(inLFB+i) = *(theTempLFB+i);
    
    delete[] theTempLFB;
}

void CreateRaster(unsigned int* inLFB, int inSizeX, int inSizeY, unsigned int* inBackGround)
{
	const int RasterGap = 5;
	int i;

	// Clear
	for (i = 0; i < inSizeX*inSizeY; i++)
		inLFB[i] = 0x00;

	// Horizontal lines
	int y = rand() % RasterGap;
	for (i = 0; i < inSizeY/RasterGap - 1; i++)
	{
		y += RasterGap;

		int StartX = 0;
		int Length = 10 + rand() % 30;
		int Color = rand() % 256 ;

		while (StartX < inSizeX )
		{
			if (StartX + Length > inSizeX)
				Length = inSizeX - StartX;

			for (int j = 0; j < Length; j++)
				inLFB[y*inSizeX + StartX + j] = Color * 0x01010101;
				
			StartX += Length;
			Length = 10 + rand() % 30;
			Color = rand() % 256 ;
		}
	}

	//Vertical lines
	int x = rand() % RasterGap;
	for (i = 0; i < inSizeX/RasterGap - 1; i++)
	{	
		x += RasterGap;

		int StartY = 0;
		int Length = 10 + rand() % 30;
		int Color = rand() % 256 ;

		while (StartY < inSizeY )
		{
			if (StartY + Length > inSizeY)
				Length = inSizeY - StartY;

			for (int j = 0; j < Length; j++)
				inLFB[(StartY+j)*inSizeX + x] = Color * 0x01010101;
				
			StartY += Length;
			Length = 10 + rand() % 30;
			Color =  rand() % 256 ;
		}
	}

}


EROC_API BOOL Rasterize(signed long inImageNr, signed long inPosX, signed long inPosY,
					  signed long inScale, signed long inOpacity )
{
	Texture* Tex = GetTexture(inImageNr);
	static int Raster = 0;
    static int AlphaLayer = 0;

	// First create the alpha layer
	if (AlphaLayer == 0)
	{
		int i;
		SDL_Surface* Surface = GetSDLSurface(inImageNr);
		unsigned int* theSurfaceLFB = (unsigned int*)Surface->pixels;
		
		unsigned int* LFB = new unsigned int[Tex->mSizeX*Tex->mSizeY];
		for (i = 0; i < Tex->mSizeX*Tex->mSizeY; i++)
		{
			// format = ABGR
		
			// Monochrome:  red		= 30% = 76/255;
			//				green	= 59% = 151/255
			//				blue	= 11% = 28/255
			unsigned int theColor, theRed, theGreen, theBlue;
			theColor = theSurfaceLFB[i];
			theRed   = 76 * ((theColor >> 16 ) & 0xFF);
			theGreen = 151 * ((theColor >> 8 ) & 0xFF);
			theBlue  = 28 * ((theColor >> 0 ) & 0xFF);

			LFB[i] = ((theRed + theGreen + theBlue) >> 8) << 24;
		}

		DeformTextureBlurHor((unsigned int *)LFB, Tex->mSizeX, Tex->mSizeY, 10);
		DeformTextureBlurVer((unsigned int *)LFB, Tex->mSizeX, Tex->mSizeY, 10);

		AlphaLayer = CreateTextureFromMem(LFB, Tex->mSizeX, Tex->mSizeY);
		delete[] LFB;
	}

	// Create new raster
	unsigned int* LFB = new unsigned int[Tex->mSizeX*Tex->mSizeY];
	CreateRaster(LFB, Tex->mSizeX,Tex->mSizeY);

	if (Raster == 0)
		Raster = CreateTextureFromMem(LFB, Tex->mSizeX, Tex->mSizeY);	
	else
		ReplaceTextureFromMem(Raster, LFB, Tex->mSizeX, Tex->mSizeY);
	delete[] LFB;



	// Draw fuzzy alpha layer 
	PushOGL_ColorMask(false, false, false, true);
	Image(AlphaLayer, inPosX, inPosY, inScale, inOpacity);
	PopOGL_ColorMask();

	// Now draw raster

	PushOGL_Blend(true);
	PushOGL_BlendFunc(GL_DST_ALPHA, GL_ONE);
	Image(Raster, inPosX, inPosY, inScale, inOpacity);
	PopOGL_BlendFunc();
	PopOGL_Blend();

	return true;
}

///////////////////////////////////////////////////////////////////////////////
/// EXPERIMENTAL STUF
///////////////////////////////////////////////////////////////////////////////

Texture gSavedBG;

void CopyFromBackground( int inX, int inY, int inSizeX, int inSizeY, Texture& ioTex)
{
		// Free the texture
	glDeleteTextures(1, &ioTex.mOpenGLTex);
	glGenTextures(1, &ioTex.mOpenGLTex);

	// get the power-of-2 sizes
	int Width = 1, Height = 1;
	while (Width < inSizeX)
		Width *= 2;
	while (Height < inSizeY)
		Height *= 2;

	ioTex.mScaleX = (float)inSizeX/Width;
	ioTex.mScaleY = (float)inSizeY/Height;
	ioTex.mSizeX = inSizeX;
	ioTex.mSizeY = inSizeY;

	char* theDummy = new char[Width*Height*4];

	// Build The Texture
	glBindTexture(GL_TEXTURE_2D, ioTex.mOpenGLTex);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
	glTexImage2D(GL_TEXTURE_2D, 0, 4, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, theDummy);
	delete[] theDummy;

	glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, inX, eScreenY - inSizeY - inX, inSizeX, inSizeY );
}

void CopyToBackground( int inX, int inY, Texture ioTex)
{
	GLboolean BlendEnable = glIsEnabled(GL_BLEND);
	if ( BlendEnable)
		glDisable(GL_BLEND);

	GLboolean DepthEnable = glIsEnabled(GL_DEPTH_TEST);
	if ( DepthEnable)
		glDisable(GL_DEPTH_TEST);	

	glMatrixMode(GL_PROJECTION);				// Select The Projection Matrix
	glPushMatrix();								// Store The Projection Matrix

	glLoadIdentity();							// Reset The Projection Matrix
	glOrtho(0,eScreenX,0,eScreenY,-1,1);		// Set Up An Ortho Screen

	glMatrixMode(GL_MODELVIEW);					// Select The Modelview Matrix
	glPushMatrix();								// Store The Modelview Matrix
	glLoadIdentity();							// Reset The Modelview Matrix

	glTranslated(0,eScreenY-ioTex.mSizeY,-0.5);			

	glBindTexture(GL_TEXTURE_2D, ioTex.mOpenGLTex);

	glBegin ( GL_QUADS );
	glNormal3f( 0.0f, 0.0f, 1.0f);		
	glTexCoord2f(0, 0);								glVertex3f (0, 0, 0 );
	glTexCoord2f(ioTex.mScaleX, 0);					glVertex3f (ioTex.mSizeX,0, 0 );
	glTexCoord2f(ioTex.mScaleX, ioTex.mScaleY);		glVertex3f (ioTex.mSizeX,ioTex.mSizeY, 0 );
	glTexCoord2f(0, ioTex.mScaleY);					glVertex3f (0,ioTex.mSizeY, 0 );
	glEnd ( );

	glMatrixMode(GL_PROJECTION);				// Select The Projection Matrix
	glPopMatrix();								// Restore The Old Projection Matrix

	glMatrixMode(GL_MODELVIEW);					// Select The Modelview Matrix
	glPopMatrix();
					
	if ( DepthEnable)
		glEnable(GL_DEPTH_TEST);

	if ( BlendEnable)
		glEnable(GL_BLEND);	
}

int gCurrentCBlur = -1;
Texture gCBlurLowPlane, gCBlurHighPlane; // the bitplanes
Texture gCBlurLowAccum, gCBlurHighAccum; // the 16 images
Texture gCBlurLowRemain, gCBlurHighRemain; // the remainder (less than full 16) images

void MakeCircularBlurTextures(int inImageNr)
{
	if (inImageNr != gCurrentCBlur)
	{
		SDL_Surface* theSurface = GetSDLSurface(inImageNr);

		gCurrentCBlur = inImageNr;
		LoadGLTextureBitPlane(theSurface, 0, gCBlurLowPlane );
		LoadGLTextureBitPlane(theSurface, 1, gCBlurHighPlane );
	}
}

// implemented speedup: take remainder as partially-drawn repeat
// possible quality improvements: take remainder separately, with own brightness, and 
// spread between the repeats

EROC_API BOOL CircularBlur(signed long inImageNr, signed long inPosX, signed long inPosY,
					 signed long inScale, signed long inDegrees )
{	
	return true;
	if (inDegrees <= 0)
		return true;
	int i;

	MakeCircularBlurTextures(inImageNr);
	Texture* Tex = GetTexture(inImageNr);
	
	// get the diagonal of the texture, and use this size to save a piece of the background
	int diameter = 2 * int( sqrt( (gCBlurLowPlane.mSizeX/2.0)*(gCBlurLowPlane.mSizeX/2.0) +
								(gCBlurLowPlane.mSizeY/2.0)*(gCBlurLowPlane.mSizeY/2.0) ) + 0.9999 );
	CopyFromBackground(0, 0, diameter, diameter, gSavedBG);

	//clear the temp buffer
	glDisable(GL_BLEND);
	glColor4f ( 0, 0, 0, 0 );
	float TempX = 2*(float)diameter/eScreenX;
	float TempY = 2*(float)diameter/eScreenY;
	glRectf( -1.f, 1.f, -1 + TempX, 1 - TempY);
	glColor4f ( 1, 1, 1, 1 );
	glEnable(GL_BLEND);

	// sanity check
	if (inDegrees < 0)
		inDegrees = 0;
	else if (inDegrees > 3600)
		inDegrees = 3600;

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix ( );
	glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping	

	// coords of texture
	float TCenterX = gCBlurLowPlane.mScaleX/2;
	float TCenterY = gCBlurLowPlane.mScaleY/2;
	float THalfX =  gCBlurLowPlane.mScaleX/2;
	float THalfY =  gCBlurLowPlane.mScaleY/2;
	
	float CenterX = -1 + (float)diameter/eScreenX;
	float CenterY = 1 - (float)diameter/eScreenY ;
	float HalfX = (float)gCBlurLowPlane.mSizeX/eScreenX;
	float HalfY = (float)gCBlurLowPlane.mSizeY/eScreenY;

	glTranslatef(CenterX, CenterY, 0);

	// If we have less then 16 degrees, we draw them all one-by-one. 
	// Else we have to draw degrees/16 in an accumulation buffer
	int Remainder = inDegrees % 16;
	int NrRepeats = inDegrees / 16;

	// make sure the brightness stays the same (256) even with rounding, repeats etc
	int BrightnessForRemain = 256 * Remainder/inDegrees; //rounded downward

	int BrightnessPerRepeat = NrRepeats ? (256 - BrightnessForRemain)/NrRepeats : 0; // also rounded downward
	BrightnessForRemain = 256 - BrightnessPerRepeat*NrRepeats; // rounded upwards

	// Quick and dirty version: draw low remainder first
	glBlendFunc(GL_ONE,GL_ONE);
	glBindTexture(GL_TEXTURE_2D, gCBlurLowPlane.mOpenGLTex);
	for (i = 0; i < Remainder; i++)
	{
		// If we use floats, we lose way too much brightness due to accumulated round-off errors.
		// Hence the baroque brightness setting method.
		int Brightness = ( (BrightnessForRemain*(i+1) +0.5f) /Remainder)
								-((BrightnessForRemain*i + 0.5f)/Remainder);
		if (! Brightness)
				continue;
		glColor4ub ( 255, 255, 255, Brightness ); // total alpha of all layers combined should always be 255!	
	
		glBegin ( GL_QUADS );
		glNormal3f( 0.0f, 0.0f, 1.0f);	
		glTexCoord2f(TCenterX -THalfX, TCenterY-THalfY);	glVertex3f (-HalfX,-HalfY, 0 );
		glTexCoord2f(TCenterX +THalfX, TCenterY-THalfY);	glVertex3f (+HalfX,-HalfY, 0 );
		glTexCoord2f(TCenterX +THalfX, TCenterY+THalfY);	glVertex3f (+HalfX,+HalfY, 0 );
		glTexCoord2f(TCenterX -THalfX, TCenterY+THalfY);	glVertex3f (-HalfX,+HalfY, 0 );	
		glEnd ( );
		glRotatef ( 1, 0, 0, 1.0f ); // next layer 1 degree more rotated
	}
	// Save the low remainder
	CopyFromBackground(0, 0, diameter, diameter, gCBlurLowRemain);

	
	// draw the full low repeat
	if (NrRepeats)
	{	
		glBindTexture(GL_TEXTURE_2D, gCBlurLowPlane.mOpenGLTex);
		for (i = Remainder; i <= 16; i++)
		{
			// If we use floats, we lose way too much brightness due to accumulated round-off errors.
			// Hence the baroque brightness setting method.
			int Brightness = ( (BrightnessPerRepeat*(i+1) +0.5f) /16)
									-((BrightnessPerRepeat*i + 0.5f)/16);
			if (! Brightness)
					continue;
			glColor4ub ( 255, 255, 255, Brightness ); // total alpha of all layers combined should always be 255!	
		
			glBegin ( GL_QUADS );
			glNormal3f( 0.0f, 0.0f, 1.0f);	
			glTexCoord2f(TCenterX -THalfX, TCenterY-THalfY);	glVertex3f (-HalfX,-HalfY, 0 );
			glTexCoord2f(TCenterX +THalfX, TCenterY-THalfY);	glVertex3f (+HalfX,-HalfY, 0 );
			glTexCoord2f(TCenterX +THalfX, TCenterY+THalfY);	glVertex3f (+HalfX,+HalfY, 0 );
			glTexCoord2f(TCenterX -THalfX, TCenterY+THalfY);	glVertex3f (-HalfX,+HalfY, 0 );	
			glEnd ( );
			glRotatef ( 1, 0, 0, 1.0f ); // next layer 1 degree more rotated
		}
		// Save the low repeat
		CopyFromBackground(0, 0, diameter, diameter, gCBlurLowAccum);
	}

	glPopMatrix();

	//clear the temp buffer
	glDisable(GL_BLEND);
	glColor4f ( 0, 0, 0, 0 );	
	glRectf( -1.f, 1.f, -1 + TempX, 1 - TempY);
	glColor4f ( 1, 1, 1, 1 );
	glEnable(GL_BLEND);

	glPushMatrix();
	glTranslatef(CenterX, CenterY, 0);

	// now draw the high remainder
	glBindTexture(GL_TEXTURE_2D, gCBlurHighPlane.mOpenGLTex);
	for (i = 0; i < Remainder; i++)
	{
		// If we use floats, we lose way too much brightness due to accumulated round-off errors.
		// Hence the baroque brightness setting method.
		int Brightness = ( (BrightnessForRemain*(i+1) +0.5f) /Remainder)
								-((BrightnessForRemain*i + 0.5f)/Remainder);
		if (! Brightness)
				continue;
		glColor4ub ( 255, 255, 255, Brightness ); // total alpha of all layers combined should always be 255!	
	
		glBegin ( GL_QUADS );
		glNormal3f( 0.0f, 0.0f, 1.0f);	
		glTexCoord2f(TCenterX -THalfX, TCenterY-THalfY);	glVertex3f (-HalfX,-HalfY, 0 );
		glTexCoord2f(TCenterX +THalfX, TCenterY-THalfY);	glVertex3f (+HalfX,-HalfY, 0 );
		glTexCoord2f(TCenterX +THalfX, TCenterY+THalfY);	glVertex3f (+HalfX,+HalfY, 0 );
		glTexCoord2f(TCenterX -THalfX, TCenterY+THalfY);	glVertex3f (-HalfX,+HalfY, 0 );	
		glEnd ( );
		glRotatef ( 1, 0, 0, 1.0f ); // next layer 1 degree more rotated
	}
	// Save the high remainder
	CopyFromBackground(0, 0, diameter, diameter, gCBlurHighRemain);

	
	// draw the full high repeat
	if (NrRepeats)
	{	
		glBindTexture(GL_TEXTURE_2D, gCBlurHighPlane.mOpenGLTex);
		for (i = Remainder; i <= 16; i++)
		{
			// If we use floats, we lose way too much brightness due to accumulated round-off errors.
			// Hence the baroque brightness setting method.
			int Brightness = ( (BrightnessPerRepeat*(i+1) +0.5f) /16)
									-((BrightnessPerRepeat*i + 0.5f)/16);
			if (! Brightness)
					continue;
			glColor4ub ( 255, 255, 255, Brightness ); // total alpha of all layers combined should always be 255!	
		
			glBegin ( GL_QUADS );
			glNormal3f( 0.0f, 0.0f, 1.0f);	
			glTexCoord2f(TCenterX -THalfX, TCenterY-THalfY);	glVertex3f (-HalfX,-HalfY, 0 );
			glTexCoord2f(TCenterX +THalfX, TCenterY-THalfY);	glVertex3f (+HalfX,-HalfY, 0 );
			glTexCoord2f(TCenterX +THalfX, TCenterY+THalfY);	glVertex3f (+HalfX,+HalfY, 0 );
			glTexCoord2f(TCenterX -THalfX, TCenterY+THalfY);	glVertex3f (-HalfX,+HalfY, 0 );	
			glEnd ( );
			glRotatef ( 1, 0, 0, 1.0f ); // next layer 1 degree more rotated
		}
		// Save the High repeat
		CopyFromBackground(0, 0, diameter, diameter, gCBlurHighAccum);
	}
	
	glPopMatrix ( );

	CopyToBackground(0, 0, gSavedBG);

	// Now draw the final result (low + high, repeats + remainder) at the intended position

	glPushMatrix ( );
	// turn half the nr of degrees back, so the middle of the blur stays centered
	glRotatef ( -inDegrees/2.0f, 0, 0, 1.0f );

	TCenterX = Tex->mScaleX/2;
	TCenterY = Tex->mScaleY/2;
	THalfX =  Tex->mScaleX/2;
	THalfY =  Tex->mScaleY/2;
	
	CenterX = 2*inPosX/gVScreenX - 1;
	CenterY = 1-2*inPosY/gVScreenY ;
	HalfX = inScale *Tex->mSizeX/(gVScreenX*1000);
	HalfY = inScale *Tex->mSizeY/(gVScreenY*1000);
 
	glBindTexture(GL_TEXTURE_2D, gCBlurHighAccum.mOpenGLTex);

	glBegin ( GL_QUADS );
	glNormal3f( 0.0f, 0.0f, 1.0f);	
	glTexCoord2f(TCenterX -THalfX, TCenterY-THalfY);	glVertex3f (-HalfX,-HalfY, 0 );
	glTexCoord2f(TCenterX +THalfX, TCenterY-THalfY);	glVertex3f (+HalfX,-HalfY, 0 );
	glTexCoord2f(TCenterX +THalfX, TCenterY+THalfY);	glVertex3f (+HalfX,+HalfY, 0 );
	glTexCoord2f(TCenterX -THalfX, TCenterY+THalfY);	glVertex3f (-HalfX,+HalfY, 0 );	
	glEnd ( );	

	glPopMatrix ( );
	// set blending back as before.
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);


	return true;
}



