/*
* [U]NITED [G]AMING [C]HEATS Client Hook
*
* Copyright (c) LIQUID     2001-2002
* Copyright (c) ZOOLABUS   2001-2002
* 
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* 
* GNU license doesn't cover Engine directory.
* Content of Engine directory is copyrighted (c) 1999, 2000, by Valve LLC
* and it is licensed under Valve's proprietary license (see original HL SDK).
*/

#define  WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "client.h"
#include <gl/gl.h>

// color stuff
#include <vector>
#include "stringfinder.h"
#include "color.h"
#include "cvar.h"
extern ColorManager colorList;

typedef void (APIENTRY *Tgl1ui) (unsigned int);
typedef void (APIENTRY *Tgl3f)( float , float , float );
typedef void (APIENTRY *Tgl4f)( float , float , float , float );
typedef void (APIENTRY *Tgl2ui) (unsigned int, unsigned int);
typedef void (APIENTRY *TglTexEnvi) (unsigned int, unsigned int, int);
typedef void (APIENTRY *Tglvui) (unsigned int,float*);
typedef void (APIENTRY *xglViewport) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef BOOL (APIENTRY *xwglSwapBuffers) (HDC);
typedef void (APIENTRY *xglBlendFunc) (GLenum sfactor, GLenum dfactor);
typedef void (APIENTRY *xglColor4f) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
typedef void (APIENTRY *xglLineWidth) (GLfloat width);
typedef void (APIENTRY *TglRectiFunc) (GLint x, GLint y, GLint x2, GLint y2);

Tgl1ui p_fnglBegin = NULL;
Tgl1ui p_fnglDisable= NULL;
Tgl1ui p_fnglEnable= NULL;
Tgl3f p_fnglColor3f = NULL;
Tgl3f p_fnglVertex3f = NULL;
TglTexEnvi p_fnglTexEnvi=NULL;
Tgl2ui p_fnglPolygonMode= NULL;
Tgl4f p_fnglClearColor=NULL;
Tgl1ui p_fnglClear=NULL;
Tglvui p_fnglGetFloatv=NULL;
xglViewport oglViewport=NULL;
xwglSwapBuffers owglSwapBuffers=NULL;
xglColor4f oglColor4f=NULL;
xglBlendFunc oglBlendFunc=NULL;
xglLineWidth oglLineWidth=NULL;
TglRectiFunc oglRecti = NULL;

bool oglSubtractive = false;

void opengl_ClearBackground()
{
	if(p_fnglClearColor && p_fnglClear)
	{
		ColorEntry* color = colorList.get(10);
		float r = float(color->r)/255.0f;
		float g = float(color->g)/255.0f;
		float b = float(color->b)/255.0f;
		float a = float(color->a)/255.0f;
		(*(Tgl4f )(p_fnglClearColor))(r,g,b,a);
		(*(Tgl1ui)(p_fnglClear))(GL_COLOR_BUFFER_BIT);
	}
}

//========================================================================
void APIENTRY pglBlendFunc(GLenum sfactor, GLenum dfactor)
{
	if(oglSubtractive)
	{
		oglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	} else {
		oglBlendFunc(sfactor, dfactor);
	}
}

void APIENTRY pglBegin(unsigned int mode)
{
	unsigned int mode2=mode;
	switch (cvar.wall) 
	{
	case 0:
		break;
	case 1:
		if (mode == GL_TRIANGLE_STRIP || mode == GL_TRIANGLE_FAN)
			(*p_fnglDisable)(GL_DEPTH_TEST);
		break;
	case 2:
		if (mode != GL_TRIANGLE_STRIP && mode != GL_TRIANGLE_FAN)
		{
			float curcolor[4];
			p_fnglGetFloatv(GL_CURRENT_COLOR, curcolor);
			p_fnglDisable(GL_DEPTH_TEST);
			p_fnglEnable (GL_BLEND);
			oglBlendFunc(GL_SRC_ALPHA, GL_ONE);
			oglColor4f(curcolor[0], curcolor[1], curcolor[2], colorList.get(10)->onebased_a );
		}
		break;
	case 3:
		if (mode != GL_TRIANGLE_STRIP && mode != GL_TRIANGLE_FAN)
		{
			float curcolor[4];
			p_fnglGetFloatv(GL_CURRENT_COLOR, curcolor);
			p_fnglDisable(GL_DEPTH_TEST);
			p_fnglEnable (GL_BLEND);
			oglBlendFunc(1,2);
			oglColor4f(curcolor[0], curcolor[1], curcolor[2], 0.5 );
		}
		break;
	case 4:
		if (mode != GL_TRIANGLE_STRIP && mode != GL_TRIANGLE_FAN)
		{
			float curcolor[4];
			p_fnglGetFloatv(GL_CURRENT_COLOR, curcolor);
			p_fnglDisable(GL_DEPTH_TEST);
			p_fnglEnable (GL_BLEND);
			oglBlendFunc(1,GL_SRC_ALPHA_SATURATE);
			oglColor4f(curcolor[0], curcolor[1], curcolor[2], 0.5 );
		}
	}
	
	switch (cvar.glextra)
	{
	case 0:
		break;
	case 1:{if(mode != GL_TRIANGLES && mode != GL_TRIANGLE_STRIP  && mode != GL_TRIANGLE_FAN  && mode != GL_QUADS) (*p_fnglTexEnvi) (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);break;}
	case 2:{if(mode != GL_TRIANGLES && mode != GL_TRIANGLE_STRIP  && mode != GL_TRIANGLE_FAN  && mode != GL_QUADS) (*p_fnglTexEnvi) (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);break;}
	case 3:
		{
			if(mode == GL_POLYGON)
			{
				ColorEntry* c = colorList.get(14);
				p_fnglColor3f( c->onebased_r, c->onebased_g, c->onebased_b);
				p_fnglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
				oglLineWidth(2);
			}
			else p_fnglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			break;
		}
	case 4:{if(mode != GL_TRIANGLES && mode != GL_TRIANGLE_STRIP  && mode != GL_TRIANGLE_FAN  && mode != GL_QUADS) (*p_fnglTexEnvi) (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, GL_BLEND);break;}
	}  
	if (p_fnglBegin) (*p_fnglBegin)(mode);
}

void APIENTRY pglVertex3f( float x, float y, float z) 
{
	if (cvar.lambert && p_fnglColor3f)
	{ 
		ColorEntry* c = colorList.get(15);
		(*p_fnglColor3f)( c->onebased_r, c->onebased_g, c->onebased_b);
	}
	if (p_fnglVertex3f) (*p_fnglVertex3f)(x, y, z);
}

void APIENTRY pglClear (GLbitfield mask)
{
	if((mask==GL_DEPTH_BUFFER_BIT)&&(cvar.wall == 3))
	{
		p_fnglClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);	// If So Then Clear Both Color And Depth Buffer
	}
	else
	{
		p_fnglClear(mask);
	}
}

void CheckForOpenGlHook(FARPROC* pProc,LPCTSTR lpProcName)
{
	if (!strcmp(lpProcName,"glDisable")) 
	{
		p_fnglDisable = (Tgl1ui)*pProc;
	} else 
	if (!strcmp(lpProcName,"glEnable")) 
	{
		p_fnglEnable = (Tgl1ui)*pProc;
	} else 
    if (!strcmp(lpProcName,"glColor4f")) 
	{
		oglColor4f = (xglColor4f)*pProc;
	} else 
	if (!strcmp(lpProcName,"glBlendFunc")) 
	{
		oglBlendFunc = (xglBlendFunc)*pProc;
		*pProc = (FARPROC)&pglBlendFunc;
	} else 
	if (!strcmp(lpProcName,"glLineWidth")) 
	{
		oglLineWidth = (xglLineWidth)*pProc;
	} else 
	if (!strcmp(lpProcName,"glClear")) 
	{
		p_fnglClear = (Tgl1ui)*pProc;
		*pProc = (FARPROC)&pglClear;
	} else 
	if (!strcmp(lpProcName,"glTexEnvi")) 
	{
		p_fnglTexEnvi = (TglTexEnvi)*pProc;
	} else 
	if (!strcmp(lpProcName,"glColor3f")) 
	{
		p_fnglColor3f = (Tgl3f)*pProc;
	} else 
	if (!strcmp(lpProcName,"glPolygonMode")) 
	{
		p_fnglPolygonMode = (Tgl2ui)*pProc;
	} else 
	if (!strcmp(lpProcName,"glRecti")) 
	{
		oglRecti = (TglRectiFunc)*pProc;
	} else 
    if (!strcmp(lpProcName,"glGetFloatv")) 
	{
		p_fnglGetFloatv = (Tglvui)*pProc;
    } else 
    if (!strcmp(lpProcName,"glVertex3f")) 
	{
		p_fnglVertex3f = (Tgl3f)*pProc;
		*pProc = (FARPROC)&pglVertex3f;
	} else 
	if (!strcmp(lpProcName,"glBegin")) 
	{
		p_fnglBegin = (Tgl1ui)*pProc;
		*pProc = (FARPROC)&pglBegin;
	} else 
	if (!strcmp(lpProcName,"glClearColor")) 
	{ 
		p_fnglClearColor = (Tgl4f)*pProc;
	}	
}
