#include "2dEffect.h"
// not optimized radix(256) sort :) by moi hehe
void radixfaces(scen *daScn)
{
	long i,j,inc,pos;
//	fill dataToSort
	long *databuffer = daScn->radixDatabuffer;
	float maxz;
	daPoint *chople;

	// first build Z data
	for(i=0;i<daScn->nFaceLight;i++)
	{
		maxz = FLT_MIN;
		chople = daScn->bigFace[i].dataPoints;
		for(j=0;j<daScn->bigFace[i].ngone;j++)
		{
			if( chople->z > maxz) maxz = chople->z;
			chople++;
		}
		databuffer[i] = ~(long)(maxz * ftri);
		daScn->fOS[i] = i;
	}

	// now lets have a sort :)
	// zdata is used as a reference to sort offsets buffer
	for(i=0;i<4;i++)
	{
		for(j=0;j<256;j++) daScn->radixBuffer[j] = 0;
		for(j=0;j<daScn->nFaceLight;j++)
		{
			daScn->radixBuffer[ (UCHAR)((databuffer[daScn->fOS[j]]>>(i*8))&0xff) ]++;
		}
		pos = 0;
		for(j=0;j<256;j++)
		{
			inc = daScn->radixBuffer[j];
			daScn->radixBuffer[j] = pos;
			pos += inc;
		}
		for(j=0;j<daScn->nFaceLight;j++)
		{
			pos = daScn->radixBuffer[ (UCHAR)((databuffer[daScn->fOS[j]]>>(i*8))&0xff) ]++;
			daScn->fOSorted[pos] = daScn->fOS[j];
		}
		// swap buffers
		j = (long)daScn->fOS;
		daScn->fOS = daScn->fOSorted;
		daScn->fOSorted = (long*)j;
	}
}

void scen::drawGL()
{
	long i,j,k;
	long trFace = 0;
	long trPoint = 0;
	float maxZ = FLT_MIN;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	tLightsGL();	// trsf lights to world space
	if( bgImage != NULL)
	{
		initProjFor2D();
		glLoadIdentity();		// current matrix is MODEL_MATRIX
		glColor4f( 1, 1, 1, 1);
		glEnable(GL_TEXTURE_2D);
		glDepthMask( false );
		glBindTexture(GL_TEXTURE_2D, GLtexture[bgImageGL]);
		glBegin(GL_QUADS);
		glTexCoord2f( 0, 1);
		glVertex3f(-1, 1,-1);
		glTexCoord2f( 1, 1);
		glVertex3f( 1, 1,-1);
		glTexCoord2f( 1, 0);
		glVertex3f( 1,-1,-1);
		glTexCoord2f( 0, 0);
		glVertex3f(-1,-1,-1);
		glEnd();
		glDisable(GL_TEXTURE_2D);
		glDepthMask( true );
		initProjFor3D();
	}

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	for(i=0;i<nobject;i++)
	{
	 if( !entity[i].type ) // render objects only :)
	 {
		glLoadMatrixf(entity[i].matrix_ObjectWorld);

		float tit,spec;
		float *p3D = aObject[i].shape3D;
		USHORT *rel = aObject[i].rel;
		USHORT *IDF = aObject[i].IDF;
		float  *tMAP = aObject[i].mc;
		float  *pn   = aObject[i].pNormals;
		float  *fn   = aObject[i].fNormals;
		surf *surf;
		long pCount = 0, ng;
		float alpha = 1;

		iLights(i);	// trsf lights to current object space

		for(j=0;j<aObject[i].nbf;j++)
		{
			ng = *rel++;
			surf = &surface[IDF[j]];
			Color *c = &surf->sColor;

		 if( entity[i].dissolve == 1 )
		 {
			switch( surf->flags & ~AF_FLAGS_OSRF )
			{
				case AF_FLAGS_FLAT:
					tit = getFaceItGL(&fn[j<<2]);
					glColor4f( tit * c->fRedValue, tit * c->fGreenValue, tit * c->fBlueValue, alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glVertex3f( p3D[*rel],
								p3D[*rel+1],
								p3D[*rel+2]);
						rel++;
					}
					glEnd();
				break;


				case ( AF_FLAGS_FLAT | AF_FLAGS_SPEC):
					tit = getFaceItGL(&fn[j<<2]);
					spec =(float)(pow(tit,surf->gloss))*surf->specLevel;
					glColor4f(spec + ( tit * c->fRedValue), spec + (tit * c->fGreenValue), spec + (tit * c->fBlueValue),alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glVertex3f( p3D[*rel],
								p3D[*rel+1],
								p3D[*rel+2]);
						rel++;
					}
					glEnd();
				break;

				case AF_FLAGS_SCOL:
					glColor4f( c->fRedValue, c->fGreenValue, c->fBlueValue,alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glVertex3f( p3D[*rel],
								p3D[*rel+1],
								p3D[*rel+2]);
						rel++;
					}
					glEnd();
				break;

				case AF_FLAGS_GOUR:
					glBegin(GL_POLYGON);
					for(k=0;k<(ng*3);k+=3)
					{
						tit = getItPtGL(&pn[k],0,0);
						glColor4f( tit * c->fRedValue, tit * c->fGreenValue, tit * c->fBlueValue,alpha);
						glVertex3f( p3D[*rel],
								p3D[*rel+1],
								p3D[*rel+2]);
						rel++;
					}
					glEnd();
				break;


				case (AF_FLAGS_GOUR | AF_FLAGS_ADDI):
					glBlendFunc(GL_ONE,GL_ONE);
					glBegin(GL_POLYGON);
					for(k=0;k<(ng*3);k+=3)
					{
						tit = getItPtGL(&pn[k],0,0);
						glColor3f( tit * c->fRedValue, tit * c->fGreenValue, tit * c->fBlueValue);
						glVertex3f( p3D[*rel],
								p3D[*rel+1],
								p3D[*rel+2]);
						rel++;
					}
					glEnd();
					glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
				break;

				case (AF_FLAGS_GOUR | AF_FLAGS_SPEC):
					glBegin(GL_POLYGON);

					for(k=0;k<(ng*3);k+=3)
					{
//						tit = getItPtGL(&pn[k],surf->gloss,surf->specLevel);
						tit = getItPtGL(&pn[k],0,0);
						glColor4f( (tit * c->fRedValue), (tit * c->fGreenValue), (tit * c->fBlueValue),alpha);

						glVertex3f( p3D[*rel],
								p3D[*rel+1],
								p3D[*rel+2]);
						rel++;
					}
					glEnd();
				break;

				case AF_FLAGS_TMAP:
				case AF_FLAGS_FMAP:
					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surface[IDF[j]].bitmap]);
					glColor4f( 1.0, 1.0, 1.0,alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glTexCoord2f( tMAP[(pCount+k)<<1], tMAP[((pCount+k)<<1)+1]);
						glVertex3f( p3D[    *rel],
									p3D[1 + *rel],
									p3D[2 + *rel] );
						*rel++;
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);
				break;

				case (AF_FLAGS_TMAP | AF_FLAGS_ADDI):
				case (AF_FLAGS_FMAP | AF_FLAGS_ADDI):
					glEnable(GL_TEXTURE_2D);
					glDepthMask(false);
					glBlendFunc(GL_ONE, GL_ONE);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surf->bitmap]);
					glColor4f( 1.0, 1.0, 1.0,alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glTexCoord2f( tMAP[(pCount+k)<<1], tMAP[((pCount+k)<<1)+1]);
						glVertex3f( p3D[    *rel],
									p3D[1 + *rel],
									p3D[2 + *rel] );
						*rel++;
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);
					glDepthMask(true);
				break;

				case (AF_FLAGS_TMAP | AF_FLAGS_GOUR):
				case (AF_FLAGS_FMAP | AF_FLAGS_GOUR):
					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surface[IDF[j]].bitmap]);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						tit = getItPtGL(&pn[k*3],0,0);
						glColor4f( tit, tit, tit,alpha);
						glTexCoord2f( tMAP[(pCount+k)<<1], tMAP[((pCount+k)<<1)+1]);
						glVertex3f( p3D[    *rel],
									p3D[1 + *rel],
									p3D[2 + *rel]);
						*rel++;
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);
				break;


				case (AF_FLAGS_TMAP | AF_FLAGS_GOUR | AF_FLAGS_SPEC):
				case (AF_FLAGS_FMAP | AF_FLAGS_GOUR | AF_FLAGS_SPEC):
					float *buffTit;
					USHORT *lastRel;
					buffTit = new float[ng];
//					glDepthMask(GL_FALSE);

					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surf->bitmap]);
					glBegin(GL_POLYGON);
					lastRel = rel;
					for(k=0;k<ng;k++)
					{
						buffTit[k] = tit = getItPtGL(&pn[k*3],0,0);
						glColor3f( tit, tit, tit);
						glTexCoord2f( tMAP[(pCount+k)<<1], tMAP[((pCount+k)<<1)+1]);
						glVertex3f( p3D[    *rel],
									p3D[1 + *rel],
									p3D[2 + *rel] );
						*rel++;
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);
/*
					glDepthMask(GL_TRUE);
					glBlendFunc(GL_ONE,GL_ONE);

					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						spec =(float)(pow(buffTit[k],surf->gloss));
						glColor3f( spec, spec, spec);
						glVertex3f( p3D[*lastRel],
								p3D[*lastRel+1],
								p3D[*lastRel+2]);
						lastRel++;
					}
					glEnd();
					glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
*/
					delete buffTit;
				break;

				default:
					rel += ng;
				break;
			}
		 }
		 else
		 {
			bigFace[trFace].dataPoints = &bigPoint[trPoint];
			bigFace[trFace].nx = fn[j<<2];
			bigFace[trFace].ny = fn[(j<<2)+1];
			bigFace[trFace].nz = fn[(j<<2)+2];
			bigFace[trFace].nsurf = IDF[j];
			bigFace[trFace].diss = entity[i].dissolve;
			*(int*)(&bigFace[trFace].itf) = i;
			bigFace[trFace].ngone = (USHORT)ng;
			for(k=0;k<ng;k++)
			{
				if( tMAP )
				{
					bigPoint[trPoint+k].xm1 = tMAP[(pCount+k)<<1];
					bigPoint[trPoint+k].ym1 = tMAP[((pCount+k)<<1)+1];
				}
				bigPoint[trPoint+k].x   = p3D[*rel];
				bigPoint[trPoint+k].y   = p3D[*rel+1];
				float temp = bigPoint[trPoint+k].z   = p3D[*rel+2];
				if( temp > maxZ ) maxZ = temp;
				// !! put point normal vector in It,xm2,ym2 !!
				if( pn )
				{
					bigPoint[trPoint+k].xm2  = pn[k*3];
					bigPoint[trPoint+k].ym2  = pn[(k*3)+1];
					bigPoint[trPoint+k].fill  = pn[(k*3)+2];
				}

				rel++;
			}
			trFace++;
			trPoint += ng;
		 }
		 if( pn ) pn += ng*3;
		 pCount += ng;
		}

		if( entity[i].sousType == 1 )
		{
			rel = aObject[i].rel;
			glBlendFunc(GL_ONE,GL_ONE);
			for(j=0;j<aObject[i].nbf;j++)
			{
				ng = *rel++;
				surf = &surface[IDF[j]];
				Color *c = &surf->sColor;

				glBegin(GL_POLYGON);
				for(k=0;k<(ng*3);k+=3)
				{
					glColor3f( c->fRedValue,  c->fGreenValue, c->fBlueValue);
					glVertex3f( p3D[*rel] * 1.1f,
							p3D[*rel+1] * 1.1f,
							p3D[*rel+2] * 1.1f);
					rel++;
				}
				glEnd();
			}
			glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
		}
	 }
	 else if( entity[i].type == 4 )
	 {
		glLoadIdentity();
		updateParticules();
		drawParticules(  (float) entity[i].currentFrame[3],
						 (float) entity[i].currentFrame[4],
						 (float) entity[i].currentFrame[5]);
	 }
	 else if( entity[i].type == 5 )		// LEns flare
	 {
		float x = (float) entity[i].currentFrame[3];
		float y = (float) entity[i].currentFrame[4];
		float z = (float) entity[i].currentFrame[5];
		float ps = 0.5f;

		glLoadIdentity();		// current matrix is MODEL_MATRIX
		glColor4f( 1, 1, 1, 1);
		glBlendFunc( GL_ONE, GL_ONE);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, GLtexture[glPart]);
		glDepthMask( false );
		glBegin(GL_QUADS);
		glTexCoord2f( 0, 0);
		glVertex3f(x-ps, y+ps,z);
		glTexCoord2f( 0, 1);
		glVertex3f( x+ps, y+ps,z);
		glTexCoord2f( 1, 1);
		glVertex3f( x+ps,y-ps,z);
		glTexCoord2f( 1, 0);
		glVertex3f(x-ps,y-ps,z);
		glEnd();
		glDisable(GL_TEXTURE_2D);
		glDepthMask( true );
		glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
	 }
	}

	// sort the alpha faces
	ftri = (0x7fffffff / maxZ );		// init the filling value for 32 bits
	this->nFaceLight = trFace;
	radixfaces(this);

//	trPoint = 0;
	int lo = -1;
	for(int e=0;e<trFace;e++)
	{
		// j real offset
		j = fOS[e];
		i = *(int*)(&bigFace[j].itf);

		float tit,spec;
		surf *surf;
		long pCount = 0, ng;
		float alpha = 1;

		if( i!=lo) 
		{
			iLights(i);	// trsf lights to current object space
			glLoadMatrixf(entity[i].matrix_ObjectWorld);
		}
		lo = i;

		ng = bigFace[j].ngone;
		surf = &surface[bigFace[j].nsurf];
		Color *c = &surf->sColor;
		alpha = bigFace[j].diss;
		daPoint *poinPoints = bigFace[j].dataPoints;
		switch( surf->flags & ~AF_FLAGS_OSRF )
		{
				case AF_FLAGS_FLAT:
					tit = getFaceItGL(&bigFace[j].nx);
					glColor4f( tit * c->fRedValue, tit * c->fGreenValue, tit * c->fBlueValue, alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
				break;


				case ( AF_FLAGS_FLAT | AF_FLAGS_SPEC):
					tit = getFaceItGL(&bigFace[j].nx);
					spec =(float)(pow(tit,surf->gloss));
					glColor4f( tit * c->fRedValue, tit * c->fGreenValue, tit * c->fBlueValue, alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();

				break;

				case AF_FLAGS_SCOL:
					glColor4f( c->fRedValue, c->fGreenValue, c->fBlueValue, alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
				break;

				case AF_FLAGS_GOUR:
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						tit = getItPtGL(&poinPoints[k].xm2,0,0);
						glColor4f( tit * c->fRedValue, tit * c->fGreenValue, tit * c->fBlueValue,alpha);
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
				break;


				case (AF_FLAGS_GOUR | AF_FLAGS_SPEC):
					glBegin(GL_POLYGON);

					for(k=0;k<ng;k++)
					{
//						tit = getItPtGL(&poinPoints[k].xm2,surf->gloss,surf->specLevel);
						tit = getItPtGL(&poinPoints[k].xm2,0,0);
						glColor4f( (tit * c->fRedValue), (tit * c->fGreenValue), (tit * c->fBlueValue),alpha);
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
				break;

				case AF_FLAGS_TMAP:
				case AF_FLAGS_FMAP:
					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surf->bitmap]);
					glColor4f( 1.0, 1.0, 1.0,alpha);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						glTexCoord2f( poinPoints[k].xm1, poinPoints[k].ym1);
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);
				break;

				case (AF_FLAGS_TMAP | AF_FLAGS_GOUR):
				case (AF_FLAGS_FMAP | AF_FLAGS_GOUR):
					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surf->bitmap]);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						tit = getItPtGL(&poinPoints[k].xm2,0,0);
						glColor4f( tit, tit, tit,alpha);
						glTexCoord2f( poinPoints[k].xm1, poinPoints[k].ym1);
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);
				break;


				case (AF_FLAGS_TMAP | AF_FLAGS_GOUR | AF_FLAGS_SPEC):
				case (AF_FLAGS_FMAP | AF_FLAGS_GOUR | AF_FLAGS_SPEC):
					float *buffTit;
					buffTit = new float[ng];
					glDepthMask(GL_FALSE);
					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, GLtexture[surf->bitmap]);
					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						buffTit[k] = tit = getItPtGL(&poinPoints[k].xm2,0,0);
						glColor4f( tit, tit, tit,alpha);
						glTexCoord2f( poinPoints[k].xm1, poinPoints[k].ym1);
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();
					glDisable(GL_TEXTURE_2D);

					glDepthMask(GL_TRUE);
					glBlendFunc(GL_ONE,GL_ONE);

					glBegin(GL_POLYGON);
					for(k=0;k<ng;k++)
					{
						spec =(float)(pow(buffTit[k],surf->gloss));
						glColor4f( spec, spec, spec,alpha);
						glVertex3f( poinPoints[k].x,
								poinPoints[k].y,
								poinPoints[k].z);
					}
					glEnd();

					glBlendFunc(GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
					delete buffTit;
				break;

				default:
				break;
		}
//		trPoint += ng;
	}

//	opengl video ( 2D effects )
	if( demoMode )
	{
		if( scnMan.currentScene == 0 )
		{
			ULONG time = MyGetTickCount() - startTick;
			float al = 1.0f - (float)time/7000;
			if( al > 0 )
			{
				videoEffect.updateTime();
				ULONG t = videoEffect.time;
				videoEffect.DrawTunnel( t/10, t/10, 0);
				videoEffect.drawBuffer( al );
				videoEffect.DrawTunnel( -(long)t/10, -(long)t/10, 1);
				videoEffect.drawBuffer( al );
			}
		}
		else if( scnMan.currentScene == 2 ) videoEffect.flag = 0;
		else if( scnMan.currentScene == 3 )
		{
				if( videoEffect.flag == 0) 
				{
					videoEffect.clearBuffer();
					videoEffect.flag = 1;
				}
				for(long po=0;po<16;po++) videoEffect.Foyer();
				videoEffect.Blur();
				videoEffect.drawBufferAdd();
		}
		else if( scnMan.currentScene == 5 )
		{
			ULONG time = MyGetTickCount() - startTick;
			if( time > (13333 - 4000) )
			{
				float al = (float)(time-(13333-4000))/4000;
				videoEffect.updateTime();
				videoEffect.writeFlower(1);
				videoEffect.drawBuffer( al);
			}
		}
		else if( scnMan.currentScene == 6 )
		{
			ULONG time = MyGetTickCount() - startTick;
			float al = 1.0f - (float)time/4000;
			if( al > 0 )
			{
				videoEffect.updateTime();
				videoEffect.writeFlower(1);
				videoEffect.drawBuffer( al );
			}
		}
		else if( scnMan.currentScene == 8 )
		{
			videoEffect.updateTime();
			videoEffect.Blit(3);
			videoEffect.RadialBlurFX( 128 +  (int)(64 * cos( (float)videoEffect.time / 800.0f )), 128 + (int)(60 * sin(videoEffect.time / 900.0f )), 10000.0f );
			videoEffect.drawBufferAdd( );
		}
		else if( scnMan.currentScene == 9 )
		{
			ULONG time = MyGetTickCount() - startTick;
			if( time > 15000 )
			{
				float al;
				if( time < (15000+4333) ) al = (float)(time-15000)/4333;
				else al = 1.0f - (float)(time-(15000+4333))/4333;
			
				videoEffect.writeRayPrim();
				videoEffect.drawBuffer( al );
			}
		}
	}
//	videoEffect.updateTime();
//	videoEffect.writeFlower(1);
//	videoEffect.drawBuffer( 0.9f );
//	------- End of opengl Video --------

	if( debug())
	{
		sprintf(OutputBuffer, "\ndissolve faces: %i",nFaceLight);
		debugPrint->addText(OutputBuffer);
		debugPrint->printText();
	}
}