/****************************************************************************************/

/*  OglMisc.c                                                                           */

/*                                                                                      */

/*	Author: Christopher Plymire (chrisjp@eudoramail.com)								*/

/*																						*/

/*  Description: OpenGL Polygon Caching Module							                */

/*                                                                                      */

/*  The contents of this file are subject to the Genesis3D Public License               */

/*  Version 1.01 (the "License"); you may not use this file except in                   */

/*  compliance with the License. You may obtain a copy of the License at                */

/*  http://www.genesis3d.com                                                            */

/*                                                                                      */

/*  Software distributed under the License is distributed on an "AS IS"                 */

/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */

/*  the License for the specific language governing rights and limitations              */

/*  under the License.                                                                  */

/*                                                                                      */

/*                                                                                      */

/****************************************************************************************/



/* Todo:

	Implement sort key as bound texture id.



	Add PCache.



	paletted textures.

*/



#define USE_PCACHE



//#include <Windows.h>

#include <assert.h>

#include <stdio.h>

#include <GL/gl.h>

#include <stdlib.h>

//#include "glext.h"

#include <Dcommon.h>

#include <memory.h>

//#include <Jet.h>



#include "THandle.h"

#include "PCache.h"

#include "Render.h"



void PCache_BeginScene(void);

void PCache_InitStaticsAndGlobals(void);

jeBoolean PCache_InsertGouraudPoly(jeTLVertex *Verts, int32 NumVerts, uint32 Flags);

jeBoolean PCache_InsertWorldPoly(jeTLVertex *Verts, int32 NumVerts, jeRDriver_Layer *Layers, int32 NumLayers, void *LMapCBContext, uint32 Flags);

jeBoolean PCache_InsertMiscPoly(jeTLVertex *Verts, int32 NumVerts, jeRDriver_Layer *Layers, int32 NumLayers, uint32 Flags);

jeBoolean DRIVERCC PCache_BeginBatch(void);

jeBoolean DRIVERCC PCache_EndBatch(void);

jeBoolean PCache_FlushALLBatches(void);

jeBoolean PCache_FlushBatch(PCache_PolyList *PolyList);

void PCache_Reset(void);





extern GLuint				boundTexture ;  // Currently bound OpenGL texture object

extern GLuint				boundTexture2 ; // Currently bound OpenGL tex object on second TMU



extern GLuint				decalTexObj;



#define MAX_BATCHES					32				// 32 max batches



#define PCACHE_MAX_TOTAL_POLYS			1024

#define PCACHE_MAX_TOTAL_POLY_VERTS		4096



#define PCACHE_MAX_POLYS				256

#define PCACHE_MAX_POLY_VERTS			1024



typedef struct

{

	float		u;

	float		v;

	uint32		Color;

} PCache_TVert;



#define MAX_TEXTURE_STAGES			2				// Up to 2 tmu's (stages)



typedef struct

{

	float			u,v;

} PCache_UVSet;



typedef struct

{

	float			x,y,z;							// Screen x, y, z

	float			ooz;

	jeRGBA color; //DWORD			color;							// color

	PCache_UVSet	uv[MAX_TEXTURE_STAGES];			// uv sets for each stage

} PCache_Vert;



typedef struct

{

	jeRDriver_Layer		Layers[MAX_TEXTURE_STAGES];

	void				*LMapCBContext;				// LMapCBContext (Layer 1)

	uint32				Flags;						// Flags for this poly

	int32				MipLevel;

	uint32				SortKey;

	int32				FirstVert;

	int32				NumVerts;

} PCache_Poly;



typedef struct PCache_PolyList

{

	PCache_Poly		Polys[PCACHE_MAX_TOTAL_POLYS];



	PCache_Vert		Verts[PCACHE_MAX_TOTAL_POLY_VERTS];

	PCache_TVert	TVerts[PCACHE_MAX_TOTAL_POLY_VERTS];		// Original uv



	PCache_Poly		*SortedPolys[PCACHE_MAX_TOTAL_POLYS];



	int32			NumPolys;									// Total number of polys

	int32			NumVerts;									// Total number of verts



	int32			FirstPolyInBatch[MAX_BATCHES];				// First poly in batch

	int32			NumPolysInBatch[MAX_BATCHES];				// Num polys in each batch

	int32			NumVertsInBatch[MAX_BATCHES];				// Num polys in each batch



	jeBoolean		ZSorted;



} PCache_PolyList;



static PCache_PolyList					PolyList;

static PCache_PolyList					ZSortedPolyList;



static int32							BatchCounter;

static int32							CurrentBatch;



DRV_CacheInfo					PCache_CacheInfo;



// Toggle and function pointers for OpenGL multitexture extention

extern GLboolean multitexture;



static jeBoolean FlushBatchSimultaneousPass(PCache_PolyList *PolyList);

static jeBoolean FlushBatchSerialPass(PCache_PolyList *PolyList);



// Now heres a hack..

extern DRV_Driver OGLDRV;



//====================================================================================

//	Initialization

//====================================================================================

void PCache_InitStaticsAndGlobals(void)

{

	memset(&PCache_CacheInfo, 0, sizeof(PCache_CacheInfo));



//	PCache_MipBias = 1.0f;

//	PCache_CurrentTextureRopMode = TEXTURE_ROP_TEXTURE_NONE;



	CurrentBatch = 0;

	BatchCounter = 0;



	memset(&PolyList, 0, sizeof(PolyList));

	memset(&ZSortedPolyList, 0, sizeof(ZSortedPolyList));

	

	PolyList.ZSorted = JE_FALSE;

	ZSortedPolyList.ZSorted = JE_TRUE;

}





//====================================================================================

//	PCache_InsertGouraudPoly

//====================================================================================

jeBoolean PCache_InsertGouraudPoly(jeTLVertex *Verts, int32 NumVerts, uint32 Flags)

{

	PCache_Poly			*pCachePoly;

	jeTLVertex			*pVerts;

	PCache_Vert			*pRenderVerts;

	int32				i, SAlpha;

	PCache_PolyList		*pPolyList;

	uint32				SortKey;



	assert(Verts);

	assert(NumVerts >= 3);



	if (Flags & JE_RENDER_FLAG_ALPHA)

	{

		float		CenterZ;



		pVerts = Verts;



		// Find the center of the poly to use for sorting

		CenterZ = 0.0f;



		for (i=0; i< NumVerts; i++, pVerts++)

			CenterZ += pVerts->z;



		CenterZ /= NumVerts;

		

		SortKey = (uint32)(CenterZ*(1<<15));



		pPolyList = &ZSortedPolyList;

	}

	else

	{

	#ifdef ALTERNATE_SORTKEY

		if (Scene_CurrentFrame & 1) // @@ reverse order every other frame

			SortKey = 0xFFFFFFFF;

		else

	#endif

			SortKey = 0;



		pPolyList = &PolyList;

	}

	

	if (pPolyList->NumVerts+NumVerts >= PCACHE_MAX_POLY_VERTS)

	{

		// If the cache is full, we must flush it before going on...

		if (!PCache_FlushBatch(pPolyList))

			return JE_FALSE;

	}

	else if (PolyList.NumPolys+1 >= PCACHE_MAX_POLYS)

	{

		// If the cache is full, we must flush it before going on...

		if (!PCache_FlushBatch(pPolyList))

			return JE_FALSE;

	}



	// Store info about this poly in the cache

	pCachePoly = &pPolyList->Polys[pPolyList->NumPolys];



	pCachePoly->Layers->THandle = NULL;

	pCachePoly->LMapCBContext = NULL;

	pCachePoly->Flags = Flags;

	pCachePoly->FirstVert = pPolyList->NumVerts;

	pCachePoly->NumVerts = NumVerts;

	pCachePoly->MipLevel = -1;



	// Precompute the alpha value...

	SAlpha = ((int32)Verts->a)<<24;



	// Get a pointer to the original polys verts

	pVerts = Verts;



	// Get a pointer into the world verts

	pRenderVerts = &pPolyList->Verts[pPolyList->NumVerts];



	for (i=0; i< NumVerts; i++)

	{

		float	ZRecip;



		ZRecip = 1/(pVerts->z);



		pRenderVerts->x = pVerts->x;

		pRenderVerts->y = pVerts->y;



		pRenderVerts->z = pVerts->z;//(1.0f - ZRecip);		// ZBUFFER

		pRenderVerts->ooz = ZRecip;



		pRenderVerts->color.r = pVerts->r;// = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b;

		pRenderVerts->color.g = pVerts->g;

		pRenderVerts->color.b = pVerts->b;

		pRenderVerts->color.a = pVerts->a;



		pVerts++;

		pRenderVerts++;

	}

	

	pPolyList->NumVertsInBatch[CurrentBatch] += NumVerts;

	pPolyList->NumPolysInBatch[CurrentBatch]++;



	pPolyList->NumVerts += NumVerts;

	pPolyList->NumPolys++;



	return JE_TRUE;

}



//====================================================================================

//	PCache_InsertWorldPoly

//====================================================================================

jeBoolean PCache_InsertWorldPoly(jeTLVertex *Verts, int32 NumVerts, jeRDriver_Layer *Layers, int32 NumLayers, void *LMapCBContext, uint32 Flags)

{

	jeRDriver_LMapCBInfo	LMapCBInfo;

	int32			Mip;

	float			ZRecip, DrawScaleU, DrawScaleV;

	PCache_Poly		*pCachePoly;

	jeTLVertex		*pVerts;

	PCache_TVert	*pTVerts;

	PCache_Vert		*pRenderVerts;

	int32			i;

	uint32			Alpha;

	PCache_PolyList	*pPolyList;

	uint32			SortKey;



	assert(Verts);

	assert(NumVerts >= 3);

	assert(Layers);

	assert(NumLayers > 0);

	assert(NumLayers <= MAX_TEXTURE_STAGES);



//	Mip = ChooseMipLevel(Verts, NumVerts, 1, 1, Layers->THandle->NumMipLevels);



	if (Layers->THandle->PixelFormat.Flags & RDRIVER_PF_ALPHA)

		Flags |= JE_RENDER_FLAG_COLORKEY;

		

	if (Flags & (JE_RENDER_FLAG_ALPHA|JE_RENDER_FLAG_COLORKEY))

	{

		float		CenterZ;



		pVerts = Verts;



		// Find the center of the poly to use for sorting

		CenterZ = 0.0f;



		for (i=0; i< NumVerts; i++, pVerts++)

			CenterZ += pVerts->z;



		CenterZ /= NumVerts;

		

		SortKey = (uint32)(CenterZ*(1<<15));



		pPolyList = &ZSortedPolyList;

	}

	else

	{

		SortKey = ((uint32)Layers->THandle<<2);// + Mip;



	#ifdef ALTERNATE_SORTKEY

		if ( Scene_CurrentFrame & 1 ) // @@ reverse order every other frame

			SortKey = 0xFFFFFFFF - SortKey;

	#endif



		pPolyList = &PolyList;

	}

	

	if (pPolyList->NumVerts + NumVerts >= PCACHE_MAX_POLY_VERTS)

	{

		// If the cache is full, we must flush it before going on...

		if (!PCache_FlushBatch(pPolyList))

			return JE_FALSE;

	}

	else if (PolyList.NumPolys+1 >= PCACHE_MAX_POLYS)

	{

		// If the cache is full, we must flush it before going on...

		if (!PCache_FlushBatch(pPolyList))

			return JE_FALSE;

	}



	DrawScaleU = 1.0f / Layers->ScaleU;

	DrawScaleV = 1.0f / Layers->ScaleV;



	// Stuff the poly in the cache for later use

	pCachePoly = &pPolyList->Polys[pPolyList->NumPolys];



	pCachePoly->Layers[0] = Layers[0];



	if (NumLayers > 1)

		pCachePoly->Layers[1] = Layers[1];

	else

		pCachePoly->Layers[1].THandle = NULL;



	pCachePoly->LMapCBContext = LMapCBContext;

	pCachePoly->Flags = Flags;

	pCachePoly->FirstVert = pPolyList->NumVerts;

	pCachePoly->NumVerts = NumVerts;

	pCachePoly->MipLevel = 1; // Jack the mip, as it does auto-mipping and were not gouraud



	pCachePoly->SortKey = SortKey;



	// Get a pointer into the world verts

	pRenderVerts = &pPolyList->Verts[pPolyList->NumVerts];

	pTVerts = &pPolyList->TVerts[pPolyList->NumVerts];



	// Get a pointer to the verts

	pVerts = Verts;



	// Setup alpha

	if (Flags & JE_RENDER_FLAG_ALPHA)

		Alpha = (uint32)pVerts->a<<24;

	else

		Alpha = (uint32)(255<<24);



	for (i=0; i< NumVerts; i++)

	{

		float ZVal = (pVerts->z);

		ZRecip = 1.0f/ZVal;



		pRenderVerts->x = pVerts->x;

		pRenderVerts->y = pVerts->y;



		pRenderVerts->z = (1.0f - ZRecip);	// ZBUFFER

		pRenderVerts->ooz = ZRecip;

		

		// Store the uv's so the prep pass can use them...

		pRenderVerts->uv[0].u = pVerts->u * DrawScaleU + Layers[0].ShiftU;//pTVerts->u = pVerts->u * Layers->ScaleU + Layers->ScaleU;

		pRenderVerts->uv[0].v = pVerts->v * DrawScaleV + Layers[0].ShiftV; //pTVerts->v = pVerts->v * Layers->ScaleV + Layers->ScaleV;



		pRenderVerts->uv[1].u = pVerts->u - Layers[1].ShiftU;//			lu = pPnt->u - shiftU2;

		pRenderVerts->uv[1].v = pVerts->v - Layers[1].ShiftV;//			lv = pPnt->v - shiftV2;



		pRenderVerts->color.r = pVerts->r; //pTVerts->Color = Alpha | ((uint32)pVerts->r<<16) | ((uint32)pVerts->g<<8) | (uint32)pVerts->b;

		pRenderVerts->color.g = pVerts->g;

		pRenderVerts->color.b = pVerts->b;

		pRenderVerts->color.a = pVerts->a;



		pTVerts++;

		pVerts++;	 

		pRenderVerts++;



	}



	if( NumLayers > 1) // lightmap poly.

	{

		// Call the engine to setup the lightmap..

		OGLDRV.SetupLightmap(&LMapCBInfo, LMapCBContext);



		if(LMapCBInfo.Dynamic || Layers[1].THandle->Flags & THANDLE_UPDATE_LM)

		{

			THandle_DownloadLightmap(Layers[1].THandle, &LMapCBInfo);

			

			if(LMapCBInfo.Dynamic)

			{

				Layers[1].THandle->Flags |= THANDLE_UPDATE_LM;

			}

			else

			{

				Layers[1].THandle->Flags &= ~THANDLE_UPDATE_LM;

			} 

		}

	}



	pPolyList->NumVertsInBatch[CurrentBatch] += NumVerts;

	pPolyList->NumPolysInBatch[CurrentBatch]++;



	pPolyList->NumVerts += NumVerts;

	pPolyList->NumPolys++;



	return JE_TRUE;

}



//====================================================================================

//	PCache_InsertMiscPoly

//====================================================================================

jeBoolean PCache_InsertMiscPoly(jeTLVertex *Verts, int32 NumVerts, jeRDriver_Layer *Layers, int32 NumLayers, uint32 Flags)

{

//	int32				Mip;

	PCache_Poly			*pCachePoly;

	jeTLVertex			*pVerts;

	PCache_Vert			*pRenderVerts;

	int32				i, SAlpha;

	jeRDriver_THandle	*THandle;

	PCache_PolyList		*pPolyList;

	uint32				SortKey;

	float ZRecip;



	assert(Verts);

	assert(NumVerts >= 3);

	assert(Layers);

	assert(NumLayers == 1);



	THandle = Layers->THandle;

	assert(THandle);



	//	Get the mip level

//	Mip = ChooseMipLevel(Verts,NumVerts, THandle->Width,THandle->Height,THandle->NumMipLevels);



	if (Layers->THandle->PixelFormat.Flags & RDRIVER_PF_ALPHA)

		Flags |= JE_RENDER_FLAG_COLORKEY;



	if (Flags & (JE_RENDER_FLAG_ALPHA|JE_RENDER_FLAG_COLORKEY))

	{

		float		CenterZ;



		pVerts = Verts;



		// Find the center of the poly to use for sorting

		CenterZ = 0.0f;



		for (i=0; i< NumVerts; i++, pVerts++)

			CenterZ += pVerts->z;



		CenterZ /= NumVerts;

		

		SortKey = (uint32)(CenterZ*(1<<15));



		pPolyList = &ZSortedPolyList;

	}

	else

	{

		SortKey = ((uint32)THandle->TextureID);// + Mip;



	#ifdef ALTERNATE_SORTKEY

		if ( Scene_CurrentFrame & 1 ) // @@ reverse order every other frame

			SortKey = 0xFFFFFFFF - SortKey;

	#endif



		pPolyList = &PolyList;

	}

	

	if (pPolyList->NumVerts+NumVerts >= PCACHE_MAX_POLY_VERTS)

	{

		// If the cache is full, we must flush it before going on...

		if (!PCache_FlushBatch(pPolyList))

			return JE_FALSE;

	}

	else if (PolyList.NumPolys+1 >= PCACHE_MAX_POLYS)

	{

		// If the cache is full, we must flush it before going on...

		if (!PCache_FlushBatch(pPolyList))

			return JE_FALSE;

	}



	// Store info about this poly in the cache

	pCachePoly = &pPolyList->Polys[pPolyList->NumPolys];



	pCachePoly->Layers[0].THandle = THandle;

	pCachePoly->Layers[1].THandle = NULL;



	pCachePoly->LMapCBContext = NULL;

	pCachePoly->Flags = Flags;

	pCachePoly->FirstVert = pPolyList->NumVerts;

	pCachePoly->NumVerts = NumVerts;

	pCachePoly->MipLevel = 1; // Jack the mip, as it does auto-mipping and were not gouraud

	pCachePoly->SortKey = SortKey;



	// Get scale value for vertices

	// InvScale = 1.0f / (float)((1<<THandle->Log));



	// Convert them to take account that the vertices are allready from 0 to 1

	// ScaleU = (float)THandle->Width * InvScale;

	// ScaleV = (float)THandle->Height * InvScale;



	// Precompute the alpha value...

	SAlpha = ((int32)Verts->a)<<24;



	// Get a pointer to the original polys verts

	pVerts = Verts;



	// Get a pointer into the world verts

	pRenderVerts = &pPolyList->Verts[pPolyList->NumVerts];



	for (i=0; i< NumVerts; i++)

	{

		ZRecip = 1/(pVerts->z);



		pRenderVerts->x = pVerts->x;

		pRenderVerts->y = pVerts->y;



		pRenderVerts->z = (1.0f - ZRecip);		// ZBUFFER

		pRenderVerts->ooz = ZRecip;

		

		pRenderVerts->uv[0].u = pVerts->u * ZRecip;

		pRenderVerts->uv[0].v = pVerts->v * ZRecip;



		pRenderVerts->color.r = pVerts->r;// = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b;

		pRenderVerts->color.g = pVerts->g;

		pRenderVerts->color.b = pVerts->b;

		pRenderVerts->color.a = pVerts->a;



		pVerts++;

		pRenderVerts++;

	}

	

	pPolyList->NumVertsInBatch[CurrentBatch] += NumVerts;

	pPolyList->NumPolysInBatch[CurrentBatch]++;



	pPolyList->NumVerts += NumVerts;

	pPolyList->NumPolys++;



	return JE_TRUE;

}



//====================================================================================

//	PrepBatchBegin

//====================================================================================

static jeBoolean PrepBatchBegin(PCache_PolyList *PolyList)

{

	if (!CurrentBatch)		// Special case the first batch

		PolyList->FirstPolyInBatch[CurrentBatch] = 0;

	else

		PolyList->FirstPolyInBatch[CurrentBatch] = PolyList->NumPolysInBatch[CurrentBatch-1];



	PolyList->NumPolysInBatch[CurrentBatch] = 0;

	PolyList->NumVertsInBatch[CurrentBatch] = 0;



	return JE_TRUE;

}



//====================================================================================

//	PCache_BeginBatch

//====================================================================================

jeBoolean DRIVERCC PCache_BeginBatch(void)

{

#ifdef USE_PCACHE

	assert(BatchCounter >= 0);



	if (BatchCounter >= MAX_BATCHES)

		return JE_FALSE;



	BatchCounter++;

	





	CurrentBatch = BatchCounter - 1;



	if (!PrepBatchBegin(&PolyList))

		return JE_FALSE;



	if (!PrepBatchBegin(&ZSortedPolyList))

		return JE_FALSE;



#endif

	return JE_TRUE;

}



//====================================================================================

//	PCache_EndBatch

//====================================================================================

jeBoolean DRIVERCC PCache_EndBatch(void)

{

#ifdef USE_PCACHE

	assert(BatchCounter > 0);



	// Flush all polys for the current batch

	if (!PCache_FlushALLBatches())

		return JE_FALSE;



	BatchCounter--;

	CurrentBatch = BatchCounter - 1;

#endif





	return JE_TRUE;

}



//====================================================================================

//	PCache_FlushALLBatches

//====================================================================================

jeBoolean PCache_FlushALLBatches(void)

{

	if (!PCache_FlushBatch(&PolyList))

		return JE_FALSE;



	if (!PCache_FlushBatch(&ZSortedPolyList))

		return JE_FALSE;



	return JE_TRUE;

}



//====================================================================================

//	PCache_FlushBatch

//====================================================================================

jeBoolean PCache_FlushBatch(PCache_PolyList *PolyList)

{

	assert(BatchCounter > 0);



	if (!PolyList->NumPolysInBatch[CurrentBatch])

		return JE_TRUE;



//	if (!THandle_CheckCache())

//		return JE_FALSE;



	if(multitexture)

	{

		FlushBatchSimultaneousPass(PolyList);

	}

	else

	{

		FlushBatchSerialPass(PolyList);

	}



	glFlush();

	

#if 0

	if (D3DInfo.CanDoMultiTexture)

	{

		FlushBatchSimultaneousPass(PolyList);

	}

	else

	{

		#if 1

			FlushBatchSerialPass(PolyList);

		#else

			if (PolyList->ZSorted)

				FlushZSortedBatchSerialPass(PolyList);

			else

				FlushBatchSerialPass(PolyList);

		#endif

	}



	D3DInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);

	D3DInfo.lpD3DDevice->EndScene();

	D3DInfo.lpD3DDevice->BeginScene();



#endif

	return JE_TRUE;

}



//====================================================================================

//	PCache_Reset

//====================================================================================

void PCache_Reset(void)

{

	BatchCounter = 0;

	CurrentBatch = 0;



	PolyList.NumPolys = 0;

	PolyList.NumVerts = 0;

	ZSortedPolyList.NumPolys = 0;

	ZSortedPolyList.NumVerts = 0;

}





//====================================================================================

//	PolyComp

//====================================================================================

static int PolyComp(const void *a, const void *b)

{

	int32			Id1, Id2;



#if 0

	// Push all the lightmaps to the front of the list 

	if ((*(PCache_Poly**)a)->LMapCBContext && !(*(PCache_Poly**)b)->LMapCBContext)

		return 0;		// Lightmap already in front, leave it

	if (!(*(PCache_Poly**)a)->LMapCBContext && (*(PCache_Poly**)b)->LMapCBContext)

		return 1;		// Put Lightmap in front of non lightmap

#endif



	// Both are same type, so sort by key

	Id1 = (*(PCache_Poly**)a)->SortKey;

	Id2 = (*(PCache_Poly**)b)->SortKey;



	if ( Id1 == Id2)

		return 0;



	if (Id1 > Id2)

		return -1;



	return 1;

}



//====================================================================================

//	SortBatch

//====================================================================================

static void SortBatch(PCache_PolyList *PolyList)

{

	PCache_Poly	*pPoly;

	int32		i, NumPolys;



	NumPolys = PolyList->NumPolysInBatch[CurrentBatch];



	pPoly = &PolyList->Polys[PolyList->FirstPolyInBatch[CurrentBatch]];



	for (i=0; i<NumPolys; i++, pPoly++)

		PolyList->SortedPolys[i] = pPoly;

	

	// Sort the polys

	qsort(&PolyList->SortedPolys, NumPolys, sizeof(PolyList->SortedPolys[0]), PolyComp);

}



void RenderGouraudPoly(PCache_PolyList *PolyList, PCache_Poly* pPoly)

{

	GLint i;

//	GLfloat zRecip;

	PCache_Vert *pPnt = &PolyList->Verts[pPoly->FirstVert];

	GLubyte alpha;





	if(pPoly->Flags & JE_RENDER_FLAG_ALPHA)

	{

		alpha = (GLubyte)pPnt->color.a;

	}

	else

	{

		alpha = 255;

	}





	glDisable(GL_TEXTURE_2D);



 	glBegin(GL_TRIANGLE_FAN);



	for(i = 0; i < pPoly->NumVerts; i++)

	{

	//	zRecip = 1.0f / pPnt->z;   

		

		glColor4ub((GLubyte)pPnt->color.r, (GLubyte)pPnt->color.g, (GLubyte)pPnt->color.b, alpha);



		glVertex3f(pPnt->x, pPnt->y, -1.0f + pPnt->ooz);//zRecip);



		pPnt++;

	}



	glEnd(); 



	glEnable(GL_TEXTURE_2D); 



	return;

}



// When this gets called.. I don't want to have to update lightmaps or even texture coords

void RenderSimultaneousPoly(PCache_PolyList *PolyList, PCache_Poly* pPoly)

{

	GLubyte alpha;

	PCache_Vert *pPnt;

//	GLfloat zRecip;

	GLfloat  lu, lv;

//	GLfloat shiftU2, shiftV2;

	GLint	i;



	pPnt = &PolyList->Verts[pPoly->FirstVert];



	if(pPoly->Flags & JE_RENDER_FLAG_ALPHA)

	{

		alpha = (GLubyte)pPnt->color.a;

	}

	else

	{

		alpha = 255;

	}



	

	if(boundTexture != pPoly->Layers[0].THandle->TextureID)

	{

		glBindTexture(GL_TEXTURE_2D, pPoly->Layers[0].THandle->TextureID);

		boundTexture = pPoly->Layers[0].THandle->TextureID;

	}



	if(pPoly->Layers[0].THandle->Flags & THANDLE_UPDATE)

	{

		THandle_Update(pPoly->Layers[0].THandle);

	}



	if(pPoly->Layers[1].THandle != NULL)// > 1)

	{

		glActiveTextureARB(GL_TEXTURE1_ARB);

		glEnable(GL_TEXTURE_2D);



		if(boundTexture2 != pPoly->Layers[1].THandle->TextureID)

		{

			glBindTexture(GL_TEXTURE_2D,pPoly->Layers[1].THandle->TextureID);

			boundTexture2 = pPoly->Layers[1].THandle->TextureID;

		}



		if(pPoly->Layers[1].THandle->Flags & THANDLE_UPDATE)

		{

			THandle_Update(pPoly->Layers[1].THandle);

		}



//		shiftU2 = (GLfloat)pPoly->Layers[1].ShiftU;//MinU - 8.0f;

//		shiftV2 = (GLfloat)pPoly->Layers[1].ShiftV;//(GLfloat)LInfo->MinV - 8.0f;

	}









	glBegin(GL_TRIANGLE_FAN);	



	for(i = 0; i < pPoly->NumVerts; i++)

	{	

//		zRecip = 1.0f / pPnt->z;   



//		tu = (pPnt->u * scaleU + shiftU);

//		tv = (pPnt->v * scaleV + shiftV);



		glColor4ub((GLubyte)pPnt->color.r, (GLubyte)pPnt->color.g, (GLubyte)pPnt->color.b, alpha);



		glMultiTexCoord4fARB(GL_TEXTURE0_ARB, pPnt->uv[0].u * pPoly->Layers->THandle->InvScale * pPnt->ooz, 

			pPnt->uv[0].v * pPoly->Layers->THandle->InvScale * pPnt->ooz, 0.0f, pPnt->ooz);





		if(pPoly->Layers[1].THandle != NULL)

		{

//			lu = pPnt->uv[1].u - shiftU2;

//			lv = pPnt->uv[1].v - shiftV2;



			glMultiTexCoord4fARB(GL_TEXTURE1_ARB, pPnt->uv[1].u * pPoly->Layers[1].THandle->InvScale * pPnt->ooz, 

				pPnt->uv[1].v * pPoly->Layers[1].THandle->InvScale * pPnt->ooz, 0.0f,pPnt->ooz);

		}





		glVertex3f(pPnt->x, pPnt->y, -1.0f + pPnt->ooz);

		

		pPnt++;

	}



	glEnd(); 



	if( pPoly->Layers[1].THandle != NULL)// > 1)

	{

		glDisable(GL_TEXTURE_2D);

		glActiveTextureARB(GL_TEXTURE0_ARB);

	}



}



void RenderTexturePoly(PCache_PolyList* PolyList, PCache_Poly* pPoly)

{

	GLint i;

//	GLfloat zRecip;

//	jeTLVertex *pPnt = pPoly->Pnts;

	PCache_Vert* pPnt = &PolyList->Verts[pPoly->FirstVert];



	GLubyte alpha;



	if(pPoly->Flags & JE_RENDER_FLAG_ALPHA)

	{

		alpha = (GLubyte)pPnt->color.a;

	}

	else

	{

		alpha = 255;

	}



	if(boundTexture != pPoly->Layers[0].THandle->TextureID)

	{

		glBindTexture(GL_TEXTURE_2D, pPoly->Layers[0].THandle->TextureID);

		boundTexture = pPoly->Layers[0].THandle->TextureID;

	}



	if(pPoly->Layers[0].THandle->Flags & THANDLE_UPDATE)

	{

		THandle_Update(pPoly->Layers[0].THandle);

	}



	if (pPoly->Flags & JE_RENDER_FLAG_NO_ZTEST)		// We are assuming that this is not going to change all that much

		glDisable(GL_DEPTH_TEST);



	if (pPoly->Flags & JE_RENDER_FLAG_NO_ZWRITE)	// We are assuming that this is not going to change all that much

		glDepthMask(0);



	glBegin(GL_TRIANGLE_FAN);



	for(i = 0; i < pPoly->NumVerts; i++)

	{

//		zRecip = 1.0f / pPnt->pPnt->z;                    



		glColor4ub((GLubyte)pPnt->color.r, (GLubyte)pPnt->color.g, (GLubyte)pPnt->color.b, alpha);



		glTexCoord4f(pPnt->uv[0].u, pPnt->uv[0].v , 0.0f, pPnt->ooz);//pPnt->u * zRecip, pPnt->v * zRecip, 0.0f, zRecip);



		glVertex3f(pPnt->x, pPnt->y, -1.0f + pPnt->ooz);



		pPnt++;

	}



	glEnd();  





	if (pPoly->Flags & JE_RENDER_FLAG_NO_ZTEST)		// We are assuming that this is not going to change all that much

		glEnable(GL_DEPTH_TEST);



	if (pPoly->Flags & JE_RENDER_FLAG_NO_ZWRITE)	// We are assuming that this is not going to change all that much

		glDepthMask(1);

}



void RenderLightmapPoly(PCache_PolyList* PolyList, PCache_Poly* pPoly)

{





}





//====================================================================================

//	FlushBatchSimultaneousPass

//====================================================================================

static jeBoolean FlushBatchSimultaneousPass(PCache_PolyList *PolyList)

{

	PCache_Poly		*pPoly;

	int32			i, NumPolys;



	NumPolys = PolyList->NumPolysInBatch[CurrentBatch];



	if (NumPolys <= 0)

	{

		assert(PolyList->NumVertsInBatch[CurrentBatch] == 0);

		return JE_TRUE;

	}

	

	// Sort them

	SortBatch(PolyList);

	

	// We know tex wrapping is always going to be off for Layer 1 (Lightmap)

	 //D3DTexWrap(TSTAJE_1, JE_FALSE);



	for (i=0; i< NumPolys; i++)

	{

		pPoly = PolyList->SortedPolys[i];



		if (pPoly->MipLevel == -1)

		{

			RenderGouraudPoly(PolyList, pPoly);

			continue;

		}



		if (pPoly->LMapCBContext)

			RenderSimultaneousPoly(PolyList, pPoly);

		else

			RenderTexturePoly(PolyList, pPoly);

	}



	PolyList->NumPolys -= NumPolys;

	PolyList->NumVerts -= PolyList->NumVertsInBatch[CurrentBatch];



	PolyList->NumPolysInBatch[CurrentBatch] = 0;

	PolyList->NumVertsInBatch[CurrentBatch] = 0;



	assert(!(PolyList->NumPolys > 0 && CurrentBatch == 0));

	assert(!(PolyList->NumVerts > 0 && CurrentBatch == 0));



	return JE_TRUE;

}





//====================================================================================

//	FlushBatchSerialPass

//====================================================================================

static jeBoolean FlushBatchSerialPass(PCache_PolyList *PolyList)

{

	return 1;

#if 0

	PCache_Poly		*pPoly, *LightmapPolys[PCACHE_MAX_POLYS];

	int32			i, NumLightmapPolys, NumPolys;



	NumPolys = PolyList->NumPolysInBatch[CurrentBatch];



	if (NumPolys <= 0)

	{

		assert(PolyList->NumVertsInBatch[CurrentBatch] == 0);

		return JE_TRUE;

	}



	NumLightmapPolys = 0;



	// Sort them

	 SortBatch(PolyList);

	

	for (i=0; i< NumPolys; i++)

	{

		pPoly = &PolyList->SortedPolys[i];

		

		if (pPoly->MipLevel == -1)

		{

			RenderGouraudPoly(PolyList, pPoly);

			continue;

		}



		RenderTexturePoly(PolyList, pPoly);



		if (pPoly->LMapCBContext)

			LightmapPolys[NumLightmapPolys++] = pPoly;

	}



	// We know tex wrapping is always going to be off for Layer 1 (Lightmap)

	D3DTexWrap(0, JE_FALSE);



	for (i=0; i< NumLightmapPolys; i++)

	{

		pPoly = LightmapPolys[i];

		

		RenderLightmapPoly(PolyList, pPoly);

	}



	PolyList->NumPolys -= NumPolys;

	PolyList->NumVerts -= PolyList->NumVertsInBatch[CurrentBatch];



	PolyList->NumPolysInBatch[CurrentBatch] = 0;

	PolyList->NumVertsInBatch[CurrentBatch] = 0;



	assert(!(PolyList->NumPolys > 0 && CurrentBatch == 0));

	assert(!(PolyList->NumVerts > 0 && CurrentBatch == 0));



	return JE_TRUE;

#endif

}