/*
Copyright (C) 2002-2003 Victor Luchits

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "r_local.h"

#ifdef MYSTICARB

extern shaderpass_t *r_accumPasses[MAX_TEXTURE_UNITS];
extern void R_ModifyColor( const shaderpass_t *pass );
extern void R_BindShaderpass( const shaderpass_t *pass, image_t *tex, int unit );
extern void R_ModifyColor( const shaderpass_t *pass );
extern void R_SetShaderpassState( const shaderpass_t *pass, qboolean mtex );
extern int	r_numAccumPasses;
extern float r_currentShaderTime;

/*
================
R_RenderMesh_ARB_Program
================
*/
// Typhontaur arb programs

#define MAX_ARB_LIGHTS 2
vec4_t lightpos[MAX_ARB_LIGHTS];
vec4_t lightcolor[MAX_ARB_LIGHTS];
int n_lightpos;

void R_RenderMesh_ARB_Program( void )
{
	// These vectors are used only for creating a tied up light to the player.
	// Naturally it will need to develop some entities of lights to hold in consideration.
	// When we have more than a light, then the second pass of rendering must have done in
	// blending with ambient put to zero.
	vec4_t campos;
	static vec4_t zero = { 0.0f,0.0f,0.0f,0.0f };
	ARB_program_t	*vertexprogram, *fragmentprogram;
	const shaderpass_t *pass;

	if (!glConfig.arb_program) return;

	pass = r_accumPasses[0];
	
	if(!pass->vertexProgram && !pass->fragmentProgram) return;

	if (!(pass->flags & SHADER_PASS_VERTEXPROGRAM) || !(pass->flags & SHADER_PASS_FRAGMENTPROGRAM))
		return;

	n_lightpos = 1;
	VectorCopy(r_refdef.vieworg, lightpos[0]);
	Vector4Set(lightcolor[0], 1.0f, 1.0f, 1.0f, 1.0f);

	VectorCopy(r_refdef.vieworg, campos);
	campos[3] = 1.0f;

	vertexprogram = pass->vertexProgram;
	fragmentprogram = pass->fragmentProgram;

	if(vertexprogram) {
		qglEnable(GL_VERTEX_PROGRAM_ARB);
		qglBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexprogram->progNum);
	}
	if(fragmentprogram) {
		qglEnable(GL_FRAGMENT_PROGRAM_ARB);
		qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fragmentprogram->progNum);
	}

	switch(pass->render_type) {


			/*
			===============================================================================================================
			RENDER_TYPE VERTEX PROGRAM
			===============================================================================================================
			*/
			case RENDER_TYPE_V_DEFAULT:
			case RENDER_TYPE_V_GENERIC:
			{
				if( !vertexprogram ) {
					qglDisable(GL_VERTEX_PROGRAM_ARB);
					break;
				}
				//TODO
				qglDisable(GL_VERTEX_PROGRAM_ARB);
				break;
			}
			/*
			===============================================================================================================
			RENDER_TYPE FRAGMENT PROGRAM
			===============================================================================================================
			*/
			case RENDER_TYPE_F_DEFAULT:
			case RENDER_TYPE_F_GENERIC:
			{
				if( !fragmentprogram ) {
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
					break;
				}
				//TODO
				qglDisable(GL_FRAGMENT_PROGRAM_ARB);
				break;
			}
			
			/*
			===============================================================================================================
			RENDER_TYPE VERTEX/FRAGMENT PROGRAMS
			===============================================================================================================
			*/



			/*
			========================================
					RENDER_TYPE_VF_DEFAULT
			========================================
			*/
			case RENDER_TYPE_VF_DEFAULT: // **PASSED**
			{
				if( !vertexprogram || !fragmentprogram ) { // Require both vertex & fragment program!
					qglDisable(GL_VERTEX_PROGRAM_ARB);
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
					break;
				}
				// Enable attributes
				R_EnableVertexAttribsArrays(pass->flag_attrib);
				// Set the pointers
				R_SetVertexAttribPointers(pass->flag_attrib, inVertsArray, inCoordsArray, NULL/*coord1*/, inTangentsArray, inBinormalsArray, inNormalsArray, NULL/*lights*/, colorArray);
				// Set Diffusemap
				R_BindShaderpass( pass, pass->anim_frames[0], 0 );
				GL_TexEnv( pass->blendmode );
				R_ModifyColor( pass );
				R_SetShaderpassState( pass, qtrue );
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_LIGHT_COLOR_POS, (const GLfloat *)lightcolor[0]);
				// draw the buffer
				R_FlushArrays();
				// Disable attributes
				R_DisableVertexAttribsArrays(pass->flag_attrib);
				// Disable programs
				qglDisable(GL_VERTEX_PROGRAM_ARB);
				qglDisable(GL_FRAGMENT_PROGRAM_ARB);
			}
				break;

			/*
			========================================
					RENDER_TYPE_VF_GENERIC
			========================================
			*/
			case RENDER_TYPE_VF_GENERIC:
			{
				if( !vertexprogram || !fragmentprogram ) { // Require both vertex & fragment program!
					qglDisable(GL_VERTEX_PROGRAM_ARB);
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
					break;
				}
				// Enable attributes
				R_EnableVertexAttribsArrays(pass->flag_attrib);
				// Set the pointers
				R_SetVertexAttribPointers(pass->flag_attrib, inVertsArray, inCoordsArray, NULL/*coord1*/, inTangentsArray, inBinormalsArray, inNormalsArray, NULL/*lights*/, colorArray);
				// Set Diffusemap
				R_BindShaderpass( pass, pass->anim_frames[0], 0 );
				GL_TexEnv( pass->blendmode );
				R_ModifyColor( pass );
				R_SetShaderpassState( pass, qtrue );
				// Set metal specular
				GL_Bind( 1, pass->anim_frames[1]);

				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_LIGHT_ORIGIN_POS, lightpos[0]);
				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_VIEW_ORIGIN_POS, campos);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_SPECULAR_EXP_POS, (const GLfloat *)pass->arbParams.param_SpecularExponent);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_SPECULAR_SCALE_POS, (const GLfloat *)pass->arbParams.param_SpecularScale);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_AMBIENT_POS, (const GLfloat *)pass->arbParams.param_Ambient);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_DIFFUSE_POS, (const GLfloat *)pass->arbParams.param_Diffuse);

				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_ATTPARAMS_POS, (const GLfloat *)pass->arbParams.param_attParams);
				qglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, LOC_BOOLMODIFYCOLORS_POS, 1.0f,0,0,0);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_LIGHT_COLOR_POS, (const GLfloat *)lightcolor[0]);

				// draw the buffer
				R_FlushArrays();
			
				// Disable attributes
				R_DisableVertexAttribsArrays(pass->flag_attrib);
				qglDisable(GL_VERTEX_PROGRAM_ARB);
				qglDisable(GL_FRAGMENT_PROGRAM_ARB);
			
				// Cleanup
				GL_SelectTexture( 1 );
				qglDisable( GL_TEXTURE_2D );
				GL_SelectTexture( 0 );
			}
			break;

			/*
			========================================
				RENDER_TYPE_VF_DIFFUSE_BUMPMAP
			========================================
			*/
			case RENDER_TYPE_VF_DIFFUSE_BUMPMAP: // **PASSED**
			{
				if( !vertexprogram || !fragmentprogram ) { // Require both vertex & fragment program!
					qglDisable(GL_VERTEX_PROGRAM_ARB);
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
					break;
				}
				// Enable attributes
				R_EnableVertexAttribsArrays(pass->flag_attrib);
				// Set the pointers
				R_SetVertexAttribPointers(pass->flag_attrib, inVertsArray, inCoordsArray, NULL/*coord1*/, inTangentsArray, inBinormalsArray, inNormalsArray, NULL/*lights*/, colorArray);
				
				// Set Diffusemap
				R_BindShaderpass( pass, pass->anim_frames[0], 0 );
				GL_TexEnv( pass->blendmode );
				R_ModifyColor( pass );
				R_SetShaderpassState( pass, qtrue );
				// Set Bumpmap
				GL_Bind( 1, pass->anim_frames[1]);

				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_LIGHT_ORIGIN_POS, lightpos[0]);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_AMBIENT_POS, (const GLfloat *)pass->arbParams.param_Ambient);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_ATTPARAMS_POS, (const GLfloat *)pass->arbParams.param_attParams);
				qglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, LOC_BOOLMODIFYCOLORS_POS, 1.0f,0,0,0);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_LIGHT_COLOR_POS, (const GLfloat *)lightcolor[0]);
				
				// draw the buffer
				R_FlushArrays();
			
				// Disable attributes
				R_DisableVertexAttribsArrays(pass->flag_attrib);
				qglDisable(GL_VERTEX_PROGRAM_ARB);
				qglDisable(GL_FRAGMENT_PROGRAM_ARB);
			
				// Cleanup
				GL_SelectTexture( 1 );
				qglDisable( GL_TEXTURE_2D );
				GL_SelectTexture( 0 );
			}
				break;

			/*
			========================================
			RENDER_TYPE_VF_DIFFUSE_BUMPMAP_SPECULAR
			========================================
			*/
			case RENDER_TYPE_VF_DIFFUSE_BUMPMAP_SPECULAR: // **PASSED**
			{
				if( !vertexprogram || !fragmentprogram ) { // Require both vertex & fragment program!
					qglDisable(GL_VERTEX_PROGRAM_ARB);
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
					break;
				}
				// Enable attributes
				R_EnableVertexAttribsArrays(pass->flag_attrib);
				// Set the pointers
				R_SetVertexAttribPointers(pass->flag_attrib, inVertsArray, inCoordsArray, NULL/*coord1*/, inTangentsArray, inBinormalsArray, inNormalsArray, NULL/*lights*/, colorArray);
				// Set Diffusemap
				R_BindShaderpass( pass, pass->anim_frames[0], 0 );
				GL_TexEnv( pass->blendmode );
				R_ModifyColor( pass );
				R_SetShaderpassState( pass, qtrue );
				// Set Bumpmap
				GL_Bind( 1, pass->anim_frames[1]);

				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_LIGHT_ORIGIN_POS, lightpos[0]);
				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_VIEW_ORIGIN_POS, campos);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_SPECULAR_EXP_POS, (const GLfloat *)pass->arbParams.param_SpecularExponent);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_SPECULAR_SCALE_POS, (const GLfloat *)pass->arbParams.param_SpecularScale);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_LIGHT_COLOR_POS, (const GLfloat *)lightcolor[0]);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_AMBIENT_POS, (const GLfloat *)pass->arbParams.param_Ambient);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_ATTPARAMS_POS, (const GLfloat *)pass->arbParams.param_attParams);
				qglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, LOC_BOOLMODIFYCOLORS_POS, 1.0f,0,0,0);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_BUMP_SCALE_POS, (const GLfloat *)pass->arbParams.param_BumpScale);
				
				// draw the buffer
				R_FlushArrays();
			
				// Disable attributes
				R_DisableVertexAttribsArrays(pass->flag_attrib);
				qglDisable(GL_VERTEX_PROGRAM_ARB);
				qglDisable(GL_FRAGMENT_PROGRAM_ARB);
			
				// Cleanup
				GL_SelectTexture( 1 );
				qglDisable( GL_TEXTURE_2D );
				GL_SelectTexture( 0 );
			}
				break;

			/*
			=============================================
			RENDER_TYPE_VF_DIFFUSE_BUMPMAP_GLOSS_SPECULAR
			=============================================
			*/
			case RENDER_TYPE_VF_DIFFUSE_BUMPMAP_GLOSS_SPECULAR: // **PASSED**
			{
				if( !vertexprogram || !fragmentprogram ) { // Require both vertex & fragment program!
					qglDisable(GL_VERTEX_PROGRAM_ARB);
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
					break;
				}
				// Enable attributes
				R_EnableVertexAttribsArrays(pass->flag_attrib);
				// Set the pointers
				R_SetVertexAttribPointers(pass->flag_attrib, inVertsArray, inCoordsArray, NULL/*coord1*/, inTangentsArray, inBinormalsArray, inNormalsArray, NULL/*lights*/, colorArray);
				// Set Diffusemap
				R_BindShaderpass( pass, pass->anim_frames[0], 0 );
				GL_TexEnv( pass->blendmode );
				R_ModifyColor( pass );
				R_SetShaderpassState( pass, qtrue );
				// Set Bumpemap
				GL_Bind( 1, pass->anim_frames[1]);
				// Set Glossmap
				GL_Bind( 2, pass->anim_frames[2]);

				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_VIEW_ORIGIN_POS, campos);
				qglProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ENV_LIGHT_ORIGIN_POS, lightpos[0]);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_SPECULAR_EXP_POS, (const GLfloat *)pass->arbParams.param_SpecularExponent);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_SPECULAR_SCALE_POS, (const GLfloat *)pass->arbParams.param_SpecularScale);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_LIGHT_COLOR_POS, (const GLfloat *)lightcolor[0]);
				qglProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ENV_AMBIENT_POS, (const GLfloat *)pass->arbParams.param_Ambient);
				qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, LOC_ATTPARAMS_POS, (const GLfloat *)pass->arbParams.param_attParams);
				qglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, LOC_BOOLMODIFYCOLORS_POS, 1.0f,0,0,0);
				
				// draw the buffer
				R_FlushArrays();
			
				// Disable attributes
				R_DisableVertexAttribsArrays(pass->flag_attrib);
				qglDisable(GL_VERTEX_PROGRAM_ARB);
				qglDisable(GL_FRAGMENT_PROGRAM_ARB);
			
				// Cleanup
				GL_SelectTexture( 1 );
				qglDisable( GL_TEXTURE_2D );
				GL_SelectTexture( 0 );
			}
				break;

			/*
			=============================================
			default
			=============================================
			*/
			default:
				if( vertexprogram )
					qglDisable(GL_VERTEX_PROGRAM_ARB);
				if(fragmentprogram )
					qglDisable(GL_FRAGMENT_PROGRAM_ARB);
			break;
	}

//#define USE_OTHERACCUMPASS
#ifdef USE_OTHERACCUMPASS
		/*
		=============================================
		RENDER OTHER STAGES (lightmap, enviroment,...)
		=============================================
		*/
		if(r_numAccumPasses > 1) {
		int	i;
		qglEnable( GL_POLYGON_OFFSET_FILL );
		qglPolygonOffset( -2.f, -2.f);
		for( i = 1; i < r_numAccumPasses; i++ )	{
			pass = r_accumPasses[i];
			if( r_accumPasses[i]->flags & (SHADER_PASS_VERTEXPROGRAM | SHADER_PASS_FRAGMENTPROGRAM) )
				continue; // others stage arb-shaders not allowed
			R_BindShaderpass( pass, NULL, i-1 );
			GL_TexEnv( pass->blendmode );
			R_ModifyColor( pass );
			R_SetShaderpassState( pass, qtrue );
		}

		R_FlushArrays ();

		// Not you try to use R_CleanUpTextureUnits (), it works wrong for this case!!!
		for( i = r_numAccumPasses - 2; i > 0; i-- ) {
			GL_SelectTexture( i );
			qglDisable(GL_BLEND);
			qglDisable( GL_TEXTURE_2D );
			qglDisable( GL_TEXTURE_GEN_S );
			qglDisable( GL_TEXTURE_GEN_T );
			qglDisable( GL_TEXTURE_GEN_R );
			qglDisable( GL_TEXTURE_CUBE_MAP_ARB );
			qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
		}
		GL_SelectTexture( 0 );
		qglDisable(GL_BLEND);
		qglDisable( GL_TEXTURE_GEN_S );
		qglDisable( GL_TEXTURE_GEN_T );
		qglDisable( GL_TEXTURE_GEN_R );
		qglDisable( GL_TEXTURE_CUBE_MAP_ARB );
		qglDisableClientState( GL_TEXTURE_COORD_ARRAY );

		}
#endif
}

#endif // MYSTICARB



