/*
===========================================================================
Copyright (C) 1999 - 2005, Id Software, Inc.
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2013 - 2015, OpenJK contributors

This file is part of the OpenJK source code.

OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

// tr_QuickSprite.cpp: implementation of the CQuickSpriteSystem class.
//
//////////////////////////////////////////////////////////////////////
#include "../server/exe_headers.h"
#include "tr_quicksprite.h"

extern void R_BindAnimatedImage( const textureBundle_t *bundle );


//////////////////////////////////////////////////////////////////////
// Singleton System
//////////////////////////////////////////////////////////////////////
CQuickSpriteSystem SQuickSprite;


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CQuickSpriteSystem::CQuickSpriteSystem() :
	mTexBundle(NULL),
	mGLStateBits(0),
	mFogIndex(-1),
	mUseFog(qfalse),
	mNextVert(0)
{
	int i;

	memset( mVerts, 0, sizeof( mVerts ) );
	memset( mFogTextureCoords, 0, sizeof( mFogTextureCoords ) );
	memset( mColors, 0, sizeof( mColors ) );

	for (i = 0; i < SHADER_MAX_VERTEXES; i += 4)
	{
		// Bottom right
		mTextureCoords[i + 0][0] = 1.0;
		mTextureCoords[i + 0][1] = 1.0;
		// Top right
		mTextureCoords[i + 1][0] = 1.0;
		mTextureCoords[i + 1][1] = 0.0;
		// Top left
		mTextureCoords[i + 2][0] = 0.0;
		mTextureCoords[i + 2][1] = 0.0;
		// Bottom left
		mTextureCoords[i + 3][0] = 0.0;
		mTextureCoords[i + 3][1] = 1.0;
	}
}

CQuickSpriteSystem::~CQuickSpriteSystem(void)
{
}

void CQuickSpriteSystem::Flush(void)
{
	if (mNextVert==0)
	{
		return;
	}

	/*
	if (mUseFog && r_drawfog->integer == 2 &&
		mFogIndex == tr.world->globalFog)
	{ //enable hardware fog when we draw this thing if applicable -rww
		jk_fog_t *fog = tr.world->fogs + mFogIndex;

		qglFogf(GL_FOG_MODE, GL_EXP2);
		qglFogf(GL_FOG_DENSITY, logtestExp2 / fog->parms.depthForOpaque);
		qglFogfv(GL_FOG_COLOR, fog->parms.color);
		qglEnable(GL_FOG);
	}
	*/
	//this should not be needed, since I just wait to disable fog for the surface til after surface sprites are done

	//
	// render the main pass
	//
	R_BindAnimatedImage( mTexBundle );
	GL_State(mGLStateBits);

	//
	// set arrays and lock
	//
#ifdef HAVE_GLES
	unsigned short indexes[(mNextVert/2)*3];
	int idx;
	// split TRIANGLE_FAN in 2 TRIANGLES
	qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
	qglEnableClientState( GL_COLOR_ARRAY);
	/*for (int i=0; i<mNextVert; i+=4) {
		qglTexCoordPointer(2, GL_FLOAT, 0, mTextureCoords+i);
		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors+i );
		qglVertexPointer (3, GL_FLOAT, 16, mVerts+i);
		qglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
	}*/
	qglTexCoordPointer( 2, GL_FLOAT, 0, mTextureCoords );
	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors );
	qglVertexPointer (3, GL_FLOAT, 16, mVerts);
	idx = 0;
	for (int i=0; i<mNextVert; i+=4) {
		// Triangle 1
		indexes[idx+0]=i;
		indexes[idx+1]=i+1;
		indexes[idx+2]=i+2;
		idx+=3;
		// Triangle 2
		indexes[idx+0]=i;
		indexes[idx+1]=i+2;
		indexes[idx+2]=i+3;
		idx+=3;
	}
	qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes);

#else
	qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
	qglTexCoordPointer( 2, GL_FLOAT, 0, mTextureCoords );

	qglEnableClientState( GL_COLOR_ARRAY);
	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, mColors );

	qglVertexPointer (3, GL_FLOAT, 16, mVerts);

	if ( qglLockArraysEXT )
	{
		qglLockArraysEXT(0, mNextVert);
		GLimp_LogComment( "glLockArraysEXT\n" );
	}

	qglDrawArrays(GL_QUADS, 0, mNextVert);
#endif

	backEnd.pc.c_vertexes += mNextVert;
	backEnd.pc.c_indexes += mNextVert;
	backEnd.pc.c_totalIndexes += mNextVert;

#ifdef JK2_MODE
	if (mUseFog)
#else
	//only for software fog pass (global soft/volumetric) -rww
	if (mUseFog && (r_drawfog->integer != 2 || mFogIndex != tr.world->globalFog))
#endif
	{
		jk_fog_t *fog = tr.world->fogs + mFogIndex;

		//
		// render the fog pass
		//
		GL_Bind( tr.fogImage );
		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );

		//
		// set arrays and lock
		//
#ifdef HAVE_GLES
		qglDisableClientState( GL_COLOR_ARRAY );
		qglColor4ubv((GLubyte *)&fog->colorInt);
		/*for (int i=0; i<mNextVert; i+=4) {
			qglTexCoordPointer(2, GL_FLOAT, 0, mFogTextureCoords+i);
			qglVertexPointer (3, GL_FLOAT, 16, mVerts+i);
			qglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
		}*/
		qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes);
#else
		qglTexCoordPointer( 2, GL_FLOAT, 0, mFogTextureCoords);
//		qglEnableClientState( GL_TEXTURE_COORD_ARRAY);	// Done above

		qglDisableClientState( GL_COLOR_ARRAY );
		qglColor4ubv((GLubyte *)&fog->colorInt);

//		qglVertexPointer (3, GL_FLOAT, 16, mVerts);	// Done above

		qglDrawArrays(GL_QUADS, 0, mNextVert);
#endif

		// Second pass from fog
		backEnd.pc.c_totalIndexes += mNextVert;
	}

	//
	// unlock arrays
	//
	if (qglUnlockArraysEXT)
	{
		qglUnlockArraysEXT();
		GLimp_LogComment( "glUnlockArraysEXT\n" );
	}

	mNextVert=0;
}


void CQuickSpriteSystem::StartGroup(textureBundle_t *bundle, uint32_t glbits, int fogIndex )
{
	mNextVert = 0;

	mTexBundle = bundle;
	mGLStateBits = glbits;
	if (fogIndex != -1)
	{
		mUseFog = qtrue;
		mFogIndex = fogIndex;
	}
	else
	{
		mUseFog = qfalse;
	}

	int cullingOn;
	qglGetIntegerv(GL_CULL_FACE,&cullingOn);

	if(cullingOn)
	{
		mTurnCullBackOn=qtrue;
	}
	else
	{
		mTurnCullBackOn=qfalse;
	}
	qglDisable(GL_CULL_FACE);
}


void CQuickSpriteSystem::EndGroup(void)
{
	Flush();

	qglColor4ub(255,255,255,255);
	if(mTurnCullBackOn)
	{
		qglEnable(GL_CULL_FACE);
	}
}




void CQuickSpriteSystem::Add(float *pointdata, color4ub_t color, vec2_t fog)
{
	float *curcoord;
	float *curfogtexcoord;
	uint32_t *curcolor;

	if (mNextVert>SHADER_MAX_VERTEXES-4)
	{
		Flush();
	}

	curcoord = mVerts[mNextVert];
	// This is 16*sizeof(float) because, pointdata comes from a float[16]
	memcpy(curcoord, pointdata, 16*sizeof(float));

	// Set up color
	curcolor = &mColors[mNextVert];
	*curcolor++ = *(uint32_t *)color;
	*curcolor++ = *(uint32_t *)color;
	*curcolor++ = *(uint32_t *)color;
	*curcolor++ = *(uint32_t *)color;

	if (fog)
	{
		curfogtexcoord = &mFogTextureCoords[mNextVert][0];
		*curfogtexcoord++ = fog[0];
		*curfogtexcoord++ = fog[1];

		*curfogtexcoord++ = fog[0];
		*curfogtexcoord++ = fog[1];

		*curfogtexcoord++ = fog[0];
		*curfogtexcoord++ = fog[1];

		*curfogtexcoord++ = fog[0];
		*curfogtexcoord++ = fog[1];

		mUseFog=qtrue;
	}
	else
	{
		mUseFog=qfalse;
	}

	mNextVert+=4;
}