/*
Copyright (C) 2001-2002 Charles Hollemeersch
Radeon Version (C) 2002 Jarno Paananen

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.

PENTA: the whole file is freakin penta...

Same as gl_bumpmap.c but Radeon 8500+ optimized 
These routines require 6 texture units, vertex shader and pixel shader

This could be further optimized for Radeon 9700 (specular exponent for
example), but would need better documentation and extension.

All lights not require only 1 pass:
1 diffuse + specular with optional light filter

*/

#include "quakedef.h"

#include "glATI.h"

PFNGLGENFRAGMENTSHADERSATIPROC		qglGenFragmentShadersATI = NULL;
PFNGLBINDFRAGMENTSHADERATIPROC		qglBindFragmentShaderATI = NULL;
PFNGLDELETEFRAGMENTSHADERATIPROC 	qglDeleteFragmentShaderATI = NULL;
PFNGLBEGINFRAGMENTSHADERATIPROC 	qglBeginFragmentShaderATI = NULL;
PFNGLENDFRAGMENTSHADERATIPROC 		qglEndFragmentShaderATI = NULL;
PFNGLPASSTEXCOORDATIPROC		qglPassTexCoordATI = NULL;
PFNGLSAMPLEMAPATIPROC			qglSampleMapATI = NULL;
PFNGLCOLORFRAGMENTOP1ATIPROC		qglColorFragmentOp1ATI = NULL;
PFNGLCOLORFRAGMENTOP2ATIPROC		qglColorFragmentOp2ATI = NULL;
PFNGLCOLORFRAGMENTOP3ATIPROC		qglColorFragmentOp3ATI = NULL;
PFNGLALPHAFRAGMENTOP1ATIPROC		qglAlphaFragmentOp1ATI = NULL;
PFNGLALPHAFRAGMENTOP2ATIPROC		qglAlphaFragmentOp2ATI = NULL;
PFNGLALPHAFRAGMENTOP3ATIPROC		qglAlphaFragmentOp3ATI = NULL;
PFNGLSETFRAGMENTSHADERCONSTANTATIPROC	qglSetFragmentShaderConstantATI = NULL;
PFNGLBEGINVERTEXSHADEREXTPROC		qglBeginVertexShaderEXT = NULL;
PFNGLENDVERTEXSHADEREXTPROC		qglEndVertexShaderEXT = NULL;
PFNGLBINDVERTEXSHADEREXTPROC		qglBindVertexShaderEXT = NULL;
PFNGLGENVERTEXSHADERSEXTPROC		qglGenVertexShadersEXT = NULL;
PFNGLDELETEVERTEXSHADEREXTPROC		qglDeleteVertexShaderEXT = NULL;
PFNGLSHADEROP1EXTPROC			qglShaderOp1EXT = NULL;
PFNGLSHADEROP2EXTPROC			qglShaderOp2EXT = NULL;
PFNGLSHADEROP3EXTPROC			qglShaderOp3EXT = NULL;
PFNGLSWIZZLEEXTPROC			qglSwizzleEXT = NULL;
PFNGLWRITEMASKEXTPROC			qglWriteMaskEXT = NULL;
PFNGLINSERTCOMPONENTEXTPROC		qglInsertComponentEXT = NULL;
PFNGLEXTRACTCOMPONENTEXTPROC		qglExtractComponentEXT = NULL;
PFNGLGENSYMBOLSEXTPROC			qglGenSymbolsEXT = NULL;
PFNGLSETINVARIANTEXTPROC		qglSetInvariantEXT = NULL;
PFNGLSETLOCALCONSTANTEXTPROC		qglSetLocalConstantEXT = NULL;
PFNGLVARIANTBVEXTPROC			qglVariantbvEXT = NULL;
PFNGLVARIANTSVEXTPROC			qglVariantsvEXT = NULL;
PFNGLVARIANTIVEXTPROC			qglVariantivEXT = NULL;
PFNGLVARIANTFVEXTPROC			qglVariantfvEXT = NULL;
PFNGLVARIANTDVEXTPROC			qglVariantdvEXT = NULL;
PFNGLVARIANTUBVEXTPROC			qglVariantubvEXT = NULL;
PFNGLVARIANTUSVEXTPROC			qglVariantusvEXT = NULL;
PFNGLVARIANTUIVEXTPROC			qglVariantuivEXT = NULL;
PFNGLVARIANTPOINTEREXTPROC		qglVariantPointerEXT = NULL;
PFNGLENABLEVARIANTCLIENTSTATEEXTPROC	qglEnableVariantClientStateEXT = NULL;
PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC	qglDisableVariantClientStateEXT = NULL;
PFNGLBINDLIGHTPARAMETEREXTPROC		qglBindLightParameterEXT = NULL;
PFNGLBINDMATERIALPARAMETEREXTPROC	qglBindMaterialParameterEXT = NULL;
PFNGLBINDTEXGENPARAMETEREXTPROC		qglBindTexGenParameterEXT = NULL;
PFNGLBINDTEXTUREUNITPARAMETEREXTPROC	qglBindTextureUnitParameterEXT = NULL;
PFNGLBINDPARAMETEREXTPROC		qglBindParameterEXT = NULL;
PFNGLISVARIANTENABLEDEXTPROC		qglIsVariantEnabledEXT = NULL;
PFNGLGETVARIANTBOOLEANVEXTPROC		qglGetVariantBooleanvEXT = NULL;
PFNGLGETVARIANTINTEGERVEXTPROC		qglGetVariantIntegervEXT = NULL;
PFNGLGETVARIANTFLOATVEXTPROC		qglGetVariantFloatvEXT = NULL;
PFNGLGETVARIANTPOINTERVEXTPROC		qglGetVariantPointervEXT = NULL;
PFNGLGETINVARIANTBOOLEANVEXTPROC	qglGetInvariantBooleanvEXT = NULL;
PFNGLGETINVARIANTINTEGERVEXTPROC	qglGetInvariantIntegervEXT = NULL;
PFNGLGETINVARIANTFLOATVEXTPROC		qglGetInvariantFloatvEXT = NULL;
PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC	qglGetLocalConstantBooleanvEXT = NULL;
PFNGLGETLOCALCONSTANTINTEGERVEXTPROC	qglGetLocalConstantIntegervEXT = NULL;
PFNGLGETLOCALCONSTANTFLOATVEXTPROC	qglGetLocalConstantFloatvEXT = NULL;

PFNGLPNTRIANGLESIATIPROC qglPNTrianglesiATI = NULL;
PFNGLPNTRIANGLESFATIPROC qglPNTrianglesfATI = NULL;

static unsigned int fragment_shaders;
static unsigned int vertex_shaders;

//#define RADEONDEBUG

#ifdef RADEONDEBUG
void checkerror()
{
    GLuint error = glGetError();
    if ( error != GL_NO_ERROR )
    {
        _asm { int 3 };
    }
}
#else

#define checkerror() do { } while(0)

#endif

// <AWE> We look up the symbols here, this way we don't need to prototype all the "qgl" functions!
#if defined (__APPLE__) || defined (MACOSX)

extern void *	GL_GetProcAddress (const char *theName, qboolean theSafeMode);

qboolean	GL_LookupRadeonSymbols (void)
{
    qglGenFragmentShadersATI = GL_GetProcAddress ("glGenFragmentShadersATI", false);
    qglBindFragmentShaderATI = GL_GetProcAddress ("glBindFragmentShaderATI", false);
    qglDeleteFragmentShaderATI = GL_GetProcAddress ("glDeleteFragmentShaderATI", false);
    qglBeginFragmentShaderATI = GL_GetProcAddress ("glBeginFragmentShaderATI", false);
    qglEndFragmentShaderATI = GL_GetProcAddress ("glEndFragmentShaderATI", false);
    qglPassTexCoordATI = GL_GetProcAddress ("glPassTexCoordATI", false);
    qglSampleMapATI = GL_GetProcAddress ("glSampleMapATI", false);
    qglColorFragmentOp1ATI = GL_GetProcAddress ("glColorFragmentOp1ATI", false);
    qglColorFragmentOp2ATI = GL_GetProcAddress ("glColorFragmentOp2ATI", false);
    qglColorFragmentOp3ATI = GL_GetProcAddress ("glColorFragmentOp3ATI", false);
    qglAlphaFragmentOp1ATI = GL_GetProcAddress ("glAlphaFragmentOp1ATI", false);
    qglAlphaFragmentOp2ATI = GL_GetProcAddress ("glAlphaFragmentOp2ATI", false);
    qglAlphaFragmentOp3ATI = GL_GetProcAddress ("glAlphaFragmentOp3ATI", false);
    qglSetFragmentShaderConstantATI = GL_GetProcAddress ("glSetFragmentShaderConstantATI", false);
    qglBeginVertexShaderEXT = GL_GetProcAddress ("glBeginVertexShaderEXT", false);            
    qglEndVertexShaderEXT = GL_GetProcAddress ("glEndVertexShaderEXT", false);          
    qglBindVertexShaderEXT = GL_GetProcAddress ("glBindVertexShaderEXT", false);               
    qglGenVertexShadersEXT = GL_GetProcAddress ("glGenVertexShadersEXT", false);               
    qglDeleteVertexShaderEXT = GL_GetProcAddress ("glDeleteVertexShaderEXT", false);         
    qglShaderOp1EXT = GL_GetProcAddress ("glShaderOp1EXT", false);            
    qglShaderOp2EXT = GL_GetProcAddress ("glShaderOp2EXT", false);            
    qglShaderOp3EXT = GL_GetProcAddress ("glShaderOp3EXT", false);            
    qglSwizzleEXT = GL_GetProcAddress ("glSwizzleEXT", false);          
    qglWriteMaskEXT = GL_GetProcAddress ("glWriteMaskEXT", false);            
    qglInsertComponentEXT = GL_GetProcAddress ("glInsertComponentEXT", false);          
    qglExtractComponentEXT = GL_GetProcAddress ("glExtractComponentEXT", false);               
    qglGenSymbolsEXT = GL_GetProcAddress ("glGenSymbolsEXT", false);         
    qglSetInvariantEXT = GL_GetProcAddress ("glSetInvariantEXT", false);           
    qglSetLocalConstantEXT = GL_GetProcAddress ("glSetLocalConstantEXT", false);               
    qglVariantbvEXT = GL_GetProcAddress ("glVariantbvEXT", false);            
    qglVariantsvEXT = GL_GetProcAddress ("glVariantsvEXT", false);            
    qglVariantivEXT = GL_GetProcAddress ("glVariantivEXT", false);            
    qglVariantfvEXT = GL_GetProcAddress ("glVariantfvEXT", false);            
    qglVariantdvEXT = GL_GetProcAddress ("glVariantdvEXT", false);            
    qglVariantubvEXT = GL_GetProcAddress ("glVariantubvEXT", false);         
    qglVariantusvEXT = GL_GetProcAddress ("glVariantusvEXT", false);         
    qglVariantuivEXT = GL_GetProcAddress ("glVariantuivEXT", false);         
    qglVariantPointerEXT = GL_GetProcAddress ("glVariantPointerEXT", false);             
    qglEnableVariantClientStateEXT = GL_GetProcAddress ("glEnableVariantClientStateEXT", false);
    qglDisableVariantClientStateEXT = GL_GetProcAddress ("glDisableVariantClientStateEXT", false);
    qglBindLightParameterEXT = GL_GetProcAddress ("glBindLightParameterEXT", false);
    qglBindMaterialParameterEXT = GL_GetProcAddress ("glBindMaterialParameterEXT", false);
    qglBindTexGenParameterEXT = GL_GetProcAddress ("glBindTexGenParameterEXT", false);
    qglBindTextureUnitParameterEXT = GL_GetProcAddress ("glBindTextureUnitParameterEXT", false);
    qglBindParameterEXT = GL_GetProcAddress ("glBindParameterEXT", false);
    qglIsVariantEnabledEXT = GL_GetProcAddress ("glIsVariantEnabledEXT", false);
    qglGetVariantBooleanvEXT = GL_GetProcAddress ("glGetVariantBooleanvEXT", false);
    qglGetVariantIntegervEXT = GL_GetProcAddress ("glGetVariantIntegervEXT", false);
    qglGetVariantFloatvEXT = GL_GetProcAddress ("glGetVariantFloatvEXT", false);
    qglGetVariantPointervEXT = GL_GetProcAddress ("glGetVariantPointervEXT", false);
    qglGetInvariantBooleanvEXT = GL_GetProcAddress ("glGetInvariantBooleanvEXT", false);
    qglGetInvariantIntegervEXT = GL_GetProcAddress ("glGetInvariantIntegervEXT", false);
    qglGetInvariantFloatvEXT = GL_GetProcAddress ("glGetInvariantFloatvEXT", false);
    qglGetLocalConstantBooleanvEXT = GL_GetProcAddress ("glGetLocalConstantBooleanvEXT", false);
    qglGetLocalConstantIntegervEXT = GL_GetProcAddress ("glGetLocalConstantIntegervEXT", false);
    qglGetLocalConstantFloatvEXT = GL_GetProcAddress ("glGetLocalConstantFloatvEXT", false);

    if (qglGenFragmentShadersATI != NULL &&
        qglBindFragmentShaderATI != NULL &&
        qglDeleteFragmentShaderATI != NULL &&
        qglBeginFragmentShaderATI != NULL &&
        qglEndFragmentShaderATI != NULL &&
        qglPassTexCoordATI != NULL &&
        qglSampleMapATI != NULL &&
        qglColorFragmentOp1ATI != NULL &&
        qglColorFragmentOp2ATI != NULL &&
        qglColorFragmentOp3ATI != NULL &&
        qglAlphaFragmentOp1ATI != NULL &&
        qglAlphaFragmentOp2ATI != NULL &&
        qglAlphaFragmentOp3ATI != NULL &&
        qglSetFragmentShaderConstantATI != NULL &&
        qglBeginVertexShaderEXT != NULL &&          
        qglEndVertexShaderEXT != NULL &&         
        qglBindVertexShaderEXT != NULL &&               
        qglGenVertexShadersEXT != NULL &&               
        qglDeleteVertexShaderEXT != NULL &&         
        qglShaderOp1EXT != NULL &&           
        qglShaderOp2EXT != NULL &&            
        qglShaderOp3EXT != NULL &&           
        qglSwizzleEXT != NULL &&         
        qglWriteMaskEXT != NULL &&             
        qglInsertComponentEXT != NULL &&           
        qglExtractComponentEXT != NULL &&               
        qglGenSymbolsEXT != NULL &&        
        qglSetInvariantEXT != NULL &&            
        qglSetLocalConstantEXT != NULL &&                
        qglVariantbvEXT != NULL &&             
        qglVariantsvEXT != NULL &&            
        qglVariantivEXT != NULL &&             
        qglVariantfvEXT != NULL &&             
        qglVariantdvEXT != NULL &&            
        qglVariantubvEXT != NULL &&          
        qglVariantusvEXT != NULL &&         
        qglVariantuivEXT != NULL &&         
        qglVariantPointerEXT != NULL &&             
        qglEnableVariantClientStateEXT != NULL && 
        qglDisableVariantClientStateEXT != NULL && 
        qglBindLightParameterEXT != NULL && 
        qglBindMaterialParameterEXT != NULL && 
        qglBindTexGenParameterEXT != NULL && 
        qglBindTextureUnitParameterEXT != NULL && 
        qglBindParameterEXT != NULL && 
        qglIsVariantEnabledEXT != NULL && 
        qglGetVariantBooleanvEXT != NULL && 
        qglGetVariantIntegervEXT != NULL && 
        qglGetVariantFloatvEXT != NULL && 
        qglGetVariantPointervEXT != NULL && 
        qglGetInvariantBooleanvEXT != NULL && 
        qglGetInvariantIntegervEXT != NULL && 
        qglGetInvariantFloatvEXT != NULL && 
        qglGetLocalConstantBooleanvEXT != NULL && 
        qglGetLocalConstantIntegervEXT != NULL && 
        qglGetLocalConstantFloatvEXT != NULL)
    {
        return (true);
    }
    
    return (false);
}

#endif /* __APPLE__ || MACOSX */

void GL_CreateShadersRadeon()
{
    float scaler[4] = {0.5f, 0.5f, 0.5f, 0.5f};
    int i;
    GLuint mvp, modelview, zcomp;
    GLuint texturematrix, texturematrix2;
    GLuint vertex;
    GLuint texcoord0;
    GLuint texcoord1;
    GLuint texcoord2;
    GLuint color;
    GLuint supportedTmu;
    GLuint disttemp, disttemp2;
    GLuint fogstart, fogend;

#if !defined(__APPLE__) && !defined (MACOSX)
    SAFE_GET_PROC( qglGenFragmentShadersATI, PFNGLGENFRAGMENTSHADERSATIPROC, "glGenFragmentShadersATI");
    SAFE_GET_PROC( qglBindFragmentShaderATI, PFNGLBINDFRAGMENTSHADERATIPROC, "glBindFragmentShaderATI");
    SAFE_GET_PROC( qglDeleteFragmentShaderATI, PFNGLDELETEFRAGMENTSHADERATIPROC, "glDeleteFragmentShaderATI");
    SAFE_GET_PROC( qglBeginFragmentShaderATI, PFNGLBEGINFRAGMENTSHADERATIPROC, "glBeginFragmentShaderATI");
    SAFE_GET_PROC( qglEndFragmentShaderATI, PFNGLENDFRAGMENTSHADERATIPROC, "glEndFragmentShaderATI");
    SAFE_GET_PROC( qglPassTexCoordATI, PFNGLPASSTEXCOORDATIPROC, "glPassTexCoordATI");
    SAFE_GET_PROC( qglSampleMapATI, PFNGLSAMPLEMAPATIPROC, "glSampleMapATI");
    SAFE_GET_PROC( qglColorFragmentOp1ATI, PFNGLCOLORFRAGMENTOP1ATIPROC, "glColorFragmentOp1ATI");
    SAFE_GET_PROC( qglColorFragmentOp2ATI, PFNGLCOLORFRAGMENTOP2ATIPROC, "glColorFragmentOp2ATI");
    SAFE_GET_PROC( qglColorFragmentOp3ATI, PFNGLCOLORFRAGMENTOP3ATIPROC, "glColorFragmentOp3ATI");
    SAFE_GET_PROC( qglAlphaFragmentOp1ATI, PFNGLALPHAFRAGMENTOP1ATIPROC, "glAlphaFragmentOp1ATI");
    SAFE_GET_PROC( qglAlphaFragmentOp2ATI, PFNGLALPHAFRAGMENTOP2ATIPROC, "glAlphaFragmentOp2ATI");
    SAFE_GET_PROC( qglAlphaFragmentOp3ATI, PFNGLALPHAFRAGMENTOP3ATIPROC, "glAlphaFragmentOp3ATI");
    SAFE_GET_PROC( qglSetFragmentShaderConstantATI, PFNGLSETFRAGMENTSHADERCONSTANTATIPROC, "glSetFragmentShaderConstantATI");
    SAFE_GET_PROC( qglBeginVertexShaderEXT, PFNGLBEGINVERTEXSHADEREXTPROC, "glBeginVertexShaderEXT");            
    SAFE_GET_PROC( qglEndVertexShaderEXT, PFNGLENDVERTEXSHADEREXTPROC, "glEndVertexShaderEXT");          
    SAFE_GET_PROC( qglBindVertexShaderEXT, PFNGLBINDVERTEXSHADEREXTPROC, "glBindVertexShaderEXT");               
    SAFE_GET_PROC( qglGenVertexShadersEXT, PFNGLGENVERTEXSHADERSEXTPROC, "glGenVertexShadersEXT");               
    SAFE_GET_PROC( qglDeleteVertexShaderEXT, PFNGLDELETEVERTEXSHADEREXTPROC, "glDeleteVertexShaderEXT");         
    SAFE_GET_PROC( qglShaderOp1EXT, PFNGLSHADEROP1EXTPROC, "glShaderOp1EXT");            
    SAFE_GET_PROC( qglShaderOp2EXT, PFNGLSHADEROP2EXTPROC, "glShaderOp2EXT");            
    SAFE_GET_PROC( qglShaderOp3EXT, PFNGLSHADEROP3EXTPROC, "glShaderOp3EXT");            
    SAFE_GET_PROC( qglSwizzleEXT, PFNGLSWIZZLEEXTPROC, "glSwizzleEXT");          
    SAFE_GET_PROC( qglWriteMaskEXT, PFNGLWRITEMASKEXTPROC, "glWriteMaskEXT");            
    SAFE_GET_PROC( qglInsertComponentEXT, PFNGLINSERTCOMPONENTEXTPROC, "glInsertComponentEXT");          
    SAFE_GET_PROC( qglExtractComponentEXT, PFNGLEXTRACTCOMPONENTEXTPROC, "glExtractComponentEXT");               
    SAFE_GET_PROC( qglGenSymbolsEXT, PFNGLGENSYMBOLSEXTPROC, "glGenSymbolsEXT");         
    SAFE_GET_PROC( qglSetInvariantEXT, PFNGLSETINVARIANTEXTPROC, "glSetInvariantEXT");           
    SAFE_GET_PROC( qglSetLocalConstantEXT, PFNGLSETLOCALCONSTANTEXTPROC, "glSetLocalConstantEXT");               
    SAFE_GET_PROC( qglVariantbvEXT, PFNGLVARIANTBVEXTPROC, "glVariantbvEXT");            
    SAFE_GET_PROC( qglVariantsvEXT, PFNGLVARIANTSVEXTPROC, "glVariantsvEXT");            
    SAFE_GET_PROC( qglVariantivEXT, PFNGLVARIANTIVEXTPROC, "glVariantivEXT");            
    SAFE_GET_PROC( qglVariantfvEXT, PFNGLVARIANTFVEXTPROC, "glVariantfvEXT");            
    SAFE_GET_PROC( qglVariantdvEXT, PFNGLVARIANTDVEXTPROC, "glVariantdvEXT");            
    SAFE_GET_PROC( qglVariantubvEXT, PFNGLVARIANTUBVEXTPROC, "glVariantubvEXT");         
    SAFE_GET_PROC( qglVariantusvEXT, PFNGLVARIANTUSVEXTPROC, "glVariantusvEXT");         
    SAFE_GET_PROC( qglVariantuivEXT, PFNGLVARIANTUIVEXTPROC, "glVariantuivEXT");         
    SAFE_GET_PROC( qglVariantPointerEXT, PFNGLVARIANTPOINTEREXTPROC, "glVariantPointerEXT");             
    SAFE_GET_PROC( qglEnableVariantClientStateEXT, PFNGLENABLEVARIANTCLIENTSTATEEXTPROC, "glEnableVariantClientStateEXT");
    SAFE_GET_PROC( qglDisableVariantClientStateEXT, PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC, "glDisableVariantClientStateEXT");
    SAFE_GET_PROC( qglBindLightParameterEXT, PFNGLBINDLIGHTPARAMETEREXTPROC, "glBindLightParameterEXT");
    SAFE_GET_PROC( qglBindMaterialParameterEXT, PFNGLBINDMATERIALPARAMETEREXTPROC, "glBindMaterialParameterEXT");
    SAFE_GET_PROC( qglBindTexGenParameterEXT, PFNGLBINDTEXGENPARAMETEREXTPROC, "glBindTexGenParameterEXT");
    SAFE_GET_PROC( qglBindTextureUnitParameterEXT, PFNGLBINDTEXTUREUNITPARAMETEREXTPROC, "glBindTextureUnitParameterEXT");
    SAFE_GET_PROC( qglBindParameterEXT, PFNGLBINDPARAMETEREXTPROC, "glBindParameterEXT");
    SAFE_GET_PROC( qglIsVariantEnabledEXT, PFNGLISVARIANTENABLEDEXTPROC, "glIsVariantEnabledEXT");
    SAFE_GET_PROC( qglGetVariantBooleanvEXT, PFNGLGETVARIANTBOOLEANVEXTPROC, "glGetVariantBooleanvEXT");
    SAFE_GET_PROC( qglGetVariantIntegervEXT, PFNGLGETVARIANTINTEGERVEXTPROC, "glGetVariantIntegervEXT");
    SAFE_GET_PROC( qglGetVariantFloatvEXT, PFNGLGETVARIANTFLOATVEXTPROC, "glGetVariantFloatvEXT");
    SAFE_GET_PROC( qglGetVariantPointervEXT, PFNGLGETVARIANTPOINTERVEXTPROC, "glGetVariantPointervEXT");
    SAFE_GET_PROC( qglGetInvariantBooleanvEXT, PFNGLGETINVARIANTBOOLEANVEXTPROC, "glGetInvariantBooleanvEXT");
    SAFE_GET_PROC( qglGetInvariantIntegervEXT, PFNGLGETINVARIANTINTEGERVEXTPROC, "glGetInvariantIntegervEXT");
    SAFE_GET_PROC( qglGetInvariantFloatvEXT, PFNGLGETINVARIANTFLOATVEXTPROC, "glGetInvariantFloatvEXT");
    SAFE_GET_PROC( qglGetLocalConstantBooleanvEXT, PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC, "glGetLocalConstantBooleanvEXT");
    SAFE_GET_PROC( qglGetLocalConstantIntegervEXT, PFNGLGETLOCALCONSTANTINTEGERVEXTPROC, "glGetLocalConstantIntegervEXT");
    SAFE_GET_PROC( qglGetLocalConstantFloatvEXT, PFNGLGETLOCALCONSTANTFLOATVEXTPROC, "glGetLocalConstantFloatvEXT");

    SAFE_GET_PROC( qglPNTrianglesiATI, PFNGLPNTRIANGLESIATIPROC, "glPNTrianglesiATI");
    SAFE_GET_PROC( qglPNTrianglesfATI, PFNGLPNTRIANGLESFATIPROC, "glPNTrianglesfATI");
#endif /* !__APPLE__ && !MACOSX */

    glEnable(GL_FRAGMENT_SHADER_ATI);

    fragment_shaders = qglGenFragmentShadersATI(2);

    // combined diffuse & specular shader w/ vertex color
    qglBindFragmentShaderATI(fragment_shaders);
    checkerror();
    qglBeginFragmentShaderATI();
    checkerror();

    qglSetFragmentShaderConstantATI(GL_CON_0_ATI, &scaler[0]);
    checkerror();

    // texld r0, t0
    qglSampleMapATI (GL_REG_0_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r1, t1
    qglSampleMapATI (GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r2, t2
    qglSampleMapATI (GL_REG_2_ATI, GL_TEXTURE2_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r3, t3
    qglSampleMapATI (GL_REG_3_ATI, GL_TEXTURE3_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r4, t4
    qglSampleMapATI (GL_REG_4_ATI, GL_TEXTURE4_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();

    // gloss * atten * light color * specular +
    // dot * color * atten * light color * self shadow =
    // (gloss * specular + dot * color * self shadow ) * atten * light color
    // Alpha ops rule :-)

    // dp3_sat r2.rgb, r0_bx2.rgb, r2_bx2.rgb   // specular
    qglColorFragmentOp2ATI(GL_DOT3_ATI,
                           GL_REG_2_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_SATURATE_BIT_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI,
                           GL_REG_2_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI);
    checkerror();

    // +mov_x8_sat r2.a, r1_bx2.b               // self shadow term
    qglAlphaFragmentOp1ATI(GL_MOV_ATI,
                           GL_REG_2_ATI, GL_8X_BIT_ATI|GL_SATURATE_BIT_ATI,
                           GL_REG_1_ATI, GL_BLUE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI);
    checkerror();

    // dp3_sat r1.rgb, r0_bx2.rgb, r1_bx2.rgb   // diffuse
    qglColorFragmentOp2ATI(GL_DOT3_ATI,
                           GL_REG_1_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_SATURATE_BIT_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI,
                           GL_REG_1_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI);
    checkerror();

    // +mad_x2_sat r1.a, r2.b, r2.b, -c0.b      // specular exponent
    qglAlphaFragmentOp3ATI(GL_MAD_ATI,
                           GL_REG_1_ATI, GL_2X_BIT_ATI|GL_SATURATE_BIT_ATI,
                           GL_REG_2_ATI, GL_BLUE, GL_NONE,
                           GL_REG_2_ATI, GL_BLUE, GL_NONE,
                           GL_CON_0_ATI, GL_BLUE, GL_NEGATE_BIT_ATI);
    checkerror();

    // mul r1.rgb, r1.rgb, r3.rgb               // diffuse color * diffuse bump
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_3_ATI, GL_NONE, GL_NONE);
    checkerror();

    // +mul r1.a, r1.a, r1.a                    // raise exponent
    qglAlphaFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE);
    checkerror();

    // mul r4.rgb, r4.rgb, v0.rgb               // atten * light color
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_4_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_4_ATI, GL_NONE, GL_NONE,
                           GL_PRIMARY_COLOR_ARB, GL_NONE, GL_NONE);
    checkerror();

    // +mul r1.a, r1.a, r1.a                    // raise exponent
    qglAlphaFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE);
    checkerror();

    // mul r1.rgb, r1.rgb, r2.a                 // self shadow * diffuse
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_2_ATI, GL_ALPHA, GL_NONE);
    checkerror();

    // +mul r0.a, r1.a, r0.a                    // specular * gloss map
    qglAlphaFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_0_ATI, GL_SATURATE_BIT_ATI,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_0_ATI, GL_NONE, GL_NONE);
    checkerror();

    // add r0.rgb, r1.rgb, r0.a                 // diffuse + specular
    qglColorFragmentOp2ATI(GL_ADD_ATI,
                           GL_REG_0_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_0_ATI, GL_ALPHA, GL_NONE);
    checkerror();

    // mul_sat r0.rgb, r0.rgb, r4.rgb           // (diffuse + specular)*atten*color
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_NONE,
                           GL_REG_4_ATI, GL_NONE, GL_NONE);
    checkerror();


    qglEndFragmentShaderATI();
    checkerror();

    // Second shader with cube filter
    qglBindFragmentShaderATI(fragment_shaders+1);
    checkerror();
    qglBeginFragmentShaderATI();
    checkerror();

    qglSetFragmentShaderConstantATI(GL_CON_0_ATI, &scaler[0]);
    checkerror();

    // texld r0, t0
    qglSampleMapATI (GL_REG_0_ATI, GL_TEXTURE0_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r1, t1
    qglSampleMapATI (GL_REG_1_ATI, GL_TEXTURE1_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r2, t2
    qglSampleMapATI (GL_REG_2_ATI, GL_TEXTURE2_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r3, t3
    qglSampleMapATI (GL_REG_3_ATI, GL_TEXTURE3_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r4, t4
    qglSampleMapATI (GL_REG_4_ATI, GL_TEXTURE4_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();
    // texld r5, t5
    qglSampleMapATI (GL_REG_5_ATI, GL_TEXTURE5_ARB, GL_SWIZZLE_STR_ATI);
    checkerror();

    // gloss * atten * light color * specular +
    // dot * color * atten * light color * self shadow =
    // (gloss * specular + dot * color * self shadow ) * atten * light color * filter
    // Alpha ops rule :-)

    // dp3_sat r2.rgb, r0_bx2.rgb, r2_bx2.rgb      // specular
    qglColorFragmentOp2ATI(GL_DOT3_ATI,
                           GL_REG_2_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_SATURATE_BIT_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI,
                           GL_REG_2_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI);
    checkerror();

    // +mov_x8_sat r2.a, r1_bx2.b                  // self shadow term
    qglAlphaFragmentOp1ATI(GL_MOV_ATI,
                           GL_REG_2_ATI, GL_8X_BIT_ATI|GL_SATURATE_BIT_ATI,
                           GL_REG_1_ATI, GL_BLUE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI);
    checkerror();

    // dp3_sat r1.rgb, r0_bx2.rgb, r1_bx2.rgb  // diffuse
    qglColorFragmentOp2ATI(GL_DOT3_ATI,
                           GL_REG_1_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_SATURATE_BIT_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI,
                           GL_REG_1_ATI, GL_NONE, GL_2X_BIT_ATI|GL_BIAS_BIT_ATI);
    checkerror();

    // +mad_x2_sat r1.a, r2.b, r2.b, -c0.b     // specular exponent
    qglAlphaFragmentOp3ATI(GL_MAD_ATI,
                           GL_REG_1_ATI, GL_2X_BIT_ATI|GL_SATURATE_BIT_ATI,
                           GL_REG_2_ATI, GL_BLUE, GL_NONE,
                           GL_REG_2_ATI, GL_BLUE, GL_NONE,
                           GL_CON_0_ATI, GL_BLUE, GL_NEGATE_BIT_ATI);
    checkerror();

    // mul r1.rgb, r1.rgb, r3.rgb              // diffuse color * diffuse bump
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_3_ATI, GL_NONE, GL_NONE);
    checkerror();

    // +mul r1.a, r1.a, r1.a                   // raise exponent
    qglAlphaFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE);
    checkerror();

    // mul r4.rgb, r4.rgb, v0.rgb              // atten * light color
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_4_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_4_ATI, GL_NONE, GL_NONE,
                           GL_PRIMARY_COLOR_ARB, GL_NONE, GL_NONE);
    checkerror();

    // +mul r1.a, r1.a, r1.a                   // raise exponent
    qglAlphaFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE);
    checkerror();

    // mul r1.rgb, r1.rgb, r2.a               // self shadow * diffuse
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_1_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_2_ATI, GL_ALPHA, GL_NONE);
    checkerror();

    // +mul r0.a, r1.a, r0.a                 // specular * gloss map
    qglAlphaFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_0_ATI, GL_SATURATE_BIT_ATI,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_0_ATI, GL_NONE, GL_NONE);
    checkerror();

    // add r0.rgb, r0.rgb, r0.a              // diffuse + specular
    qglColorFragmentOp2ATI(GL_ADD_ATI,
                           GL_REG_0_ATI, GL_RED_BIT_ATI|GL_GREEN_BIT_ATI|GL_BLUE_BIT_ATI, GL_NONE,
                           GL_REG_1_ATI, GL_NONE, GL_NONE,
                           GL_REG_0_ATI, GL_ALPHA, GL_NONE);
    checkerror();

    // mul r0.rgb, r0.rgb, r4.rgb            // (diffuse + specular)*atten*color
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_NONE,
                           GL_REG_0_ATI, GL_NONE, GL_NONE,
                           GL_REG_4_ATI, GL_NONE, GL_NONE);
    checkerror();

    // mul_sat r0.rgb, r0.rgb, r5.rgb    // (diffuse + specular)*atten*color*filter
    qglColorFragmentOp2ATI(GL_MUL_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_SATURATE_BIT_ATI,
                           GL_REG_0_ATI, GL_NONE, GL_NONE,
                           GL_REG_5_ATI, GL_NONE, GL_NONE);
    checkerror();


    qglEndFragmentShaderATI();
    checkerror();

    glDisable(GL_FRAGMENT_SHADER_ATI);


    glEnable(GL_VERTEX_SHADER_EXT);

    vertex_shaders = qglGenVertexShadersEXT(2);
    checkerror();
    qglBindVertexShaderEXT(vertex_shaders);
    checkerror();
    qglBeginVertexShaderEXT();
    checkerror();

    // Generates a necessary input for the diffuse bumpmapping registers
    mvp           = qglBindParameterEXT( GL_MVP_MATRIX_EXT );
    checkerror();
    modelview     = qglBindParameterEXT( GL_MODELVIEW_MATRIX );
    checkerror();
    vertex        = qglBindParameterEXT( GL_CURRENT_VERTEX_EXT );
    checkerror();
    color         = qglBindParameterEXT( GL_CURRENT_COLOR );
    checkerror();
    texturematrix = qglBindTextureUnitParameterEXT( GL_TEXTURE4_ARB, GL_TEXTURE_MATRIX );
    checkerror();
    texcoord0     = qglBindTextureUnitParameterEXT( GL_TEXTURE0_ARB, GL_CURRENT_TEXTURE_COORDS );
    checkerror();
    texcoord1     = qglBindTextureUnitParameterEXT( GL_TEXTURE1_ARB, GL_CURRENT_TEXTURE_COORDS );
    checkerror();
    texcoord2     = qglBindTextureUnitParameterEXT( GL_TEXTURE2_ARB, GL_CURRENT_TEXTURE_COORDS );
    checkerror();
    disttemp      = qglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
    checkerror();
    disttemp2     = qglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
    checkerror();
    zcomp         = qglGenSymbolsEXT(GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
    checkerror();
    fogstart      = qglBindParameterEXT( GL_FOG_START );
    checkerror();
    fogend        = qglBindParameterEXT( GL_FOG_END );
    checkerror();

    // Transform vertex to view-space
    qglShaderOp2EXT( GL_OP_MULTIPLY_MATRIX_EXT, GL_OUTPUT_VERTEX_EXT, mvp, vertex );
    checkerror();
    
    // Transform vertex by texture matrix and copy to output
    qglShaderOp2EXT( GL_OP_MULTIPLY_MATRIX_EXT, GL_OUTPUT_TEXTURE_COORD4_EXT, texturematrix, vertex );
    checkerror();

    // copy tex coords of unit 0 to unit 3
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD0_EXT, texcoord0);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD1_EXT, texcoord1);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD2_EXT, texcoord2);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD3_EXT, texcoord0);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_COLOR0_EXT, color);
    checkerror();

    // Transform vertex and take z for fog
    qglExtractComponentEXT( zcomp, modelview, 2);
    checkerror();
    qglShaderOp2EXT( GL_OP_DOT4_EXT, disttemp, zcomp, vertex );
    checkerror();

    // calculate fog values end - z and end - start
    qglShaderOp2EXT( GL_OP_SUB_EXT, disttemp, fogend, disttemp);
    checkerror();
    qglShaderOp2EXT( GL_OP_SUB_EXT, disttemp2, fogend, fogstart);
    checkerror();

    // divide end - z by end - start, that's it
    qglShaderOp1EXT( GL_OP_RECIP_EXT, disttemp2, disttemp2);
    checkerror();
    qglShaderOp2EXT( GL_OP_MUL_EXT, GL_OUTPUT_FOG_EXT, disttemp, disttemp2);
    checkerror();

    qglEndVertexShaderEXT();
    checkerror();

    // Two transformed textures
    qglBindVertexShaderEXT(vertex_shaders+1);
    checkerror();
    qglBeginVertexShaderEXT();
    checkerror();

    // Generates a necessary input for the diffuse bumpmapping registers
    mvp            = qglBindParameterEXT( GL_MVP_MATRIX_EXT );
    checkerror();
    modelview      = qglBindParameterEXT( GL_MODELVIEW_MATRIX );
    checkerror();
    vertex         = qglBindParameterEXT( GL_CURRENT_VERTEX_EXT );
    checkerror();
    color          = qglBindParameterEXT( GL_CURRENT_COLOR );
    checkerror();
    texturematrix  = qglBindTextureUnitParameterEXT( GL_TEXTURE4_ARB, GL_TEXTURE_MATRIX );
    checkerror();
    texturematrix2 = qglBindTextureUnitParameterEXT( GL_TEXTURE5_ARB, GL_TEXTURE_MATRIX );
    checkerror();
    texcoord0      = qglBindTextureUnitParameterEXT( GL_TEXTURE0_ARB, GL_CURRENT_TEXTURE_COORDS );
    checkerror();
    texcoord1      = qglBindTextureUnitParameterEXT( GL_TEXTURE1_ARB, GL_CURRENT_TEXTURE_COORDS );
    checkerror();
    texcoord2      = qglBindTextureUnitParameterEXT( GL_TEXTURE2_ARB, GL_CURRENT_TEXTURE_COORDS );
    checkerror();
    disttemp       = qglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
    checkerror();
    disttemp2      = qglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
    checkerror();
    zcomp          = qglGenSymbolsEXT(GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
    checkerror();
    fogstart       = qglBindParameterEXT( GL_FOG_START );
    checkerror();
    fogend         = qglBindParameterEXT( GL_FOG_END );
    checkerror();

    // Transform vertex to view-space
    qglShaderOp2EXT( GL_OP_MULTIPLY_MATRIX_EXT, GL_OUTPUT_VERTEX_EXT, mvp, vertex );
    checkerror();
    
    // Transform vertex by texture matrix and copy to output
    qglShaderOp2EXT( GL_OP_MULTIPLY_MATRIX_EXT, GL_OUTPUT_TEXTURE_COORD4_EXT, texturematrix, vertex );
    checkerror();

    // Transform vertex by texture matrix and copy to output
    qglShaderOp2EXT( GL_OP_MULTIPLY_MATRIX_EXT, GL_OUTPUT_TEXTURE_COORD5_EXT, texturematrix2, vertex );
    checkerror();

    // copy tex coords of unit 0 to unit 3
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD0_EXT, texcoord0);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD1_EXT, texcoord1);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD2_EXT, texcoord2);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_TEXTURE_COORD3_EXT, texcoord0);
    checkerror();
    qglShaderOp1EXT( GL_OP_MOV_EXT, GL_OUTPUT_COLOR0_EXT, color);
    checkerror();

    // Transform vertex and take z for fog
    qglExtractComponentEXT( zcomp, modelview, 2);
    checkerror();
    qglShaderOp2EXT( GL_OP_DOT4_EXT, disttemp, zcomp, vertex );
    checkerror();

    // calculate fog values end - z and end - start
    qglShaderOp2EXT( GL_OP_SUB_EXT, disttemp, fogend, disttemp);
    checkerror();
    qglShaderOp2EXT( GL_OP_SUB_EXT, disttemp2, fogend, fogstart);
    checkerror();

    // divide end - z by end - start, that's it
    qglShaderOp1EXT( GL_OP_RECIP_EXT, disttemp2, disttemp2);
    checkerror();
    qglShaderOp2EXT( GL_OP_MUL_EXT, GL_OUTPUT_FOG_EXT, disttemp, disttemp2);
    checkerror();

    qglEndVertexShaderEXT();
    checkerror();

    glDisable(GL_VERTEX_SHADER_EXT);
}


void GL_DisableDiffuseShaderRadeon()
{
    //tex 0 = normal map
    //tex 1 = normalization cube map (tangent space light vector)
    //tex 2 = normalization cube map (tangent space half vector)
    //tex 3 = color map
    //tex 4 = (attenuation or light filter, depends on light settings)

    glDisable(GL_VERTEX_SHADER_EXT);
    glDisable(GL_FRAGMENT_SHADER_ATI);

    GL_SelectTexture(GL_TEXTURE1_ARB);
    glDisable(GL_TEXTURE_CUBE_MAP_ARB);

    GL_SelectTexture(GL_TEXTURE2_ARB);
    glDisable(GL_TEXTURE_CUBE_MAP_ARB);

    GL_SelectTexture(GL_TEXTURE3_ARB);
    glDisable(GL_TEXTURE_2D);

    GL_SelectTexture(GL_TEXTURE4_ARB);
    if (currentshadowlight->filtercube)
    {
        glDisable(GL_TEXTURE_CUBE_MAP_ARB);
        glPopMatrix();
        GL_SelectTexture(GL_TEXTURE5_ARB);
    }
    glDisable(GL_TEXTURE_3D);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);

    GL_SelectTexture(GL_TEXTURE0_ARB);
}

void GL_EnableDiffuseSpecularShaderRadeon(qboolean world, vec3_t lightOrig)
{
    float invrad = 1/currentshadowlight->radius;

    //tex 0 = normal map
    //tex 1 = normalization cube map (tangent space light vector)
    //tex 2 = normalization cube map (tangent space half vector)
    //tex 3 = color map
    //tex 4 = (attenuation or light filter, depends on light settings but the actual
    //  register combiner setup does not change only the bound texture)

    GL_SelectTexture(GL_TEXTURE1_ARB);
    glEnable(GL_TEXTURE_CUBE_MAP_ARB);
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normcube_texture_object);

    GL_SelectTexture(GL_TEXTURE2_ARB);
    glEnable(GL_TEXTURE_CUBE_MAP_ARB);
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normcube_texture_object);

    GL_SelectTexture(GL_TEXTURE3_ARB);
    glEnable(GL_TEXTURE_2D);

    glEnable(GL_FRAGMENT_SHADER_ATI);
    glEnable(GL_VERTEX_SHADER_EXT);
   
    GL_SelectTexture(GL_TEXTURE4_ARB);
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glLoadIdentity();
    if (currentshadowlight->filtercube)
    {
        glGetError();
        qglBindFragmentShaderATI( fragment_shaders + 1 );
        checkerror();
        qglBindVertexShaderEXT( vertex_shaders + 1);
        checkerror();

        glEnable(GL_TEXTURE_CUBE_MAP_ARB);
        glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, currentshadowlight->filtercube);
        GL_SetupCubeMapMatrix(world);

        GL_SelectTexture(GL_TEXTURE5_ARB);
        glMatrixMode(GL_TEXTURE);
        glPushMatrix();
        glLoadIdentity();
    }
    else
    {
        glGetError();
        qglBindFragmentShaderATI( fragment_shaders );
        checkerror();
        qglBindVertexShaderEXT( vertex_shaders );
        checkerror();
    }

    glEnable(GL_TEXTURE_3D);
    glBindTexture(GL_TEXTURE_3D, atten3d_texture_object);

    glTranslatef(0.5,0.5,0.5);
    glScalef(0.5,0.5,0.5);
    glScalef(invrad, invrad, invrad);
    glTranslatef(-lightOrig[0], -lightOrig[1], -lightOrig[2]);

    GL_SelectTexture(GL_TEXTURE0_ARB);

}


void R_DrawWorldRadeonDiffuseSpecular(lightcmd_t *lightCmds) 
{
    int command, num, i;
    int lightPos = 0;
    vec3_t lightOr;
    msurface_t *surf;
    float               *v;
    float* lightP;
    vec3_t lightDir;
    vec3_t tsH,H;

    texture_t	*t;//XYZ

    //support flickering lights
    VectorCopy(currentshadowlight->origin,lightOr);

    while (1)
    {
        command = lightCmds[lightPos++].asInt;
        if (command == 0) break; //end of list

        surf = lightCmds[lightPos++].asVoid;

        if (surf->visframe != r_framecount) {
            lightPos+=(4+surf->polys->numverts*(2+3));
            continue;
        }

        num = surf->polys->numverts;
        lightPos+=4;//skip color

        //XYZ
        t = R_TextureAnimation (surf->texinfo->texture);

        GL_SelectTexture(GL_TEXTURE0_ARB);
        GL_Bind(t->gl_texturenum+1);
        GL_SelectTexture(GL_TEXTURE3_ARB);
        GL_Bind(t->gl_texturenum);

        glBegin(command);
        //v = surf->polys->verts[0];
        v = (float *)(&globalVertexTable[surf->polys->firstvertex]);
        for (i=0; i<num; i++, v+= VERTEXSIZE)
        {
            //skip attent texture coord.
            lightPos += 2;

            lightP = &lightCmds[lightPos].asFloat;
            lightPos += 3;

            VectorCopy(lightP, lightDir);
            VectorNormalize(lightDir);

            //calculate local H vector and put it into tangent space

            //r_origin = camera position
            VectorSubtract(r_refdef.vieworg,v,H);
            VectorNormalize(H);

            //put H in tangent space first since lightDir (precalc) is already in tang space
            if (surf->flags & SURF_PLANEBACK)
            {
                tsH[2] = -DotProduct(H,surf->plane->normal);
            }
            else
            { 
                tsH[2] = DotProduct(H,surf->plane->normal);
            }

            tsH[1] = -DotProduct(H,surf->texinfo->vecs[1]);
            tsH[0] = DotProduct(H,surf->texinfo->vecs[0]);

            VectorAdd(lightDir,tsH,tsH);

            // diffuse
            qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
	    
            qglMultiTexCoord3fvARB(GL_TEXTURE1_ARB, lightP);

            // half vector for specular
            qglMultiTexCoord3fvARB(GL_TEXTURE2_ARB,&tsH[0]);

            glVertex3fv(&v[0]);
        }
        glEnd();
    }

    GL_SelectTexture(GL_TEXTURE0_ARB);
}



void R_DrawBrushRadeonDiffuseSpecular(entity_t *e)
{
    model_t     *model = e->model;
    msurface_t *surf;
    glpoly_t    *poly;
    int         i, j, count;
    brushlightinstant_t *ins = e->brushlightinstant;
    float       *v;
    texture_t	*t;//XYZ	

    count = 0;

    surf = &model->surfaces[model->firstmodelsurface];
    for (i=0; i<model->nummodelsurfaces; i++, surf++)
    {
        if (!ins->polygonVis[i]) continue;

        poly = surf->polys;

        //XYZ
        t = R_TextureAnimation (surf->texinfo->texture);

        GL_SelectTexture(GL_TEXTURE0_ARB);
        GL_Bind(t->gl_texturenum+1);
        GL_SelectTexture(GL_TEXTURE3_ARB);
        GL_Bind(t->gl_texturenum);

        glBegin(GL_TRIANGLE_FAN);
        //v = poly->verts[0];
        v = (float *)(&globalVertexTable[poly->firstvertex]);
        for (j=0 ; j<poly->numverts ; j++, v+= VERTEXSIZE)
        {       
            qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, v[3], v[4]);
            qglMultiTexCoord3fvARB(GL_TEXTURE1_ARB,&ins->tslights[count+j][0]);
            qglMultiTexCoord3fvARB(GL_TEXTURE2_ARB,&ins->tshalfangles[count+j][0]);
            glVertex3fv(v);
        }
        glEnd();
        count+=surf->numedges;
    }   
}


void R_DrawAliasFrameRadeonDiffuseSpecular (aliashdr_t *paliashdr, aliasframeinstant_t *instant)
{
    mtriangle_t *tris;
    fstvert_t   *texcoords;
    int anim;
    int                 *indecies;
    aliaslightinstant_t *linstant = instant->lightinstant;

    tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
    texcoords = (fstvert_t *)((byte *)paliashdr + paliashdr->texcoords);

    //bind normal map
    anim = (int)(cl.time*10) & 3;

    GL_SelectTexture(GL_TEXTURE0_ARB);
    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]+1);
    GL_SelectTexture(GL_TEXTURE3_ARB);
    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);
        
    indecies = (int *)((byte *)paliashdr + paliashdr->indecies);

    glVertexPointer(3, GL_FLOAT, 0, instant->vertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glNormalPointer(GL_FLOAT, 0, instant->normals);
    glEnableClientState(GL_NORMAL_ARRAY);

    qglClientActiveTextureARB(GL_TEXTURE0_ARB);
    glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    qglClientActiveTextureARB(GL_TEXTURE1_ARB);
    glTexCoordPointer(3, GL_FLOAT, 0, linstant->tslights);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    qglClientActiveTextureARB(GL_TEXTURE2_ARB);
    glTexCoordPointer(3, GL_FLOAT, 0, linstant->tshalfangles);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    //glDrawElements(GL_TRIANGLES,paliashdr->numtris*3,GL_UNSIGNED_INT,indecies);
    glDrawElements(GL_TRIANGLES,linstant->numtris*3,GL_UNSIGNED_INT,&linstant->indecies[0]);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    qglClientActiveTextureARB(GL_TEXTURE0_ARB);
    GL_SelectTexture(GL_TEXTURE0_ARB);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

void R_DrawWorldBumpedRadeon()
{
    if (!currentshadowlight->visible)
        return;

    glDepthMask (0);
    glShadeModel (GL_SMOOTH);
    GL_AddColor();
    glColor3fv(&currentshadowlight->color[0]);

    GL_EnableDiffuseSpecularShaderRadeon(true,currentshadowlight->origin);
    R_DrawWorldRadeonDiffuseSpecular(currentshadowlight->lightCmds);
    GL_DisableDiffuseShaderRadeon();

    glColor3f (1,1,1);
    glDisable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDepthMask (1);
}

void R_DrawBrushBumpedRadeon(entity_t *e)
{
    GL_AddColor();
    glColor3fv(&currentshadowlight->color[0]);


    GL_EnableDiffuseSpecularShaderRadeon(false,((brushlightinstant_t *)e->brushlightinstant)->lightpos);
    R_DrawBrushRadeonDiffuseSpecular(e);
    GL_DisableDiffuseShaderRadeon();
}

void R_DrawAliasBumpedRadeon(aliashdr_t *paliashdr, aliasframeinstant_t *instant)
{
    if ( gl_truform.value )
    {
        glEnable(GL_PN_TRIANGLES_ATI);
	qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI);
	qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI);
	qglPNTrianglesiATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_truform_tesselation.value);
    }

    GL_AddColor();
    glColor3fv(&currentshadowlight->color[0]);

    GL_EnableDiffuseSpecularShaderRadeon(false,instant->lightinstant->lightpos);
    R_DrawAliasFrameRadeonDiffuseSpecular(paliashdr,instant);
    GL_DisableDiffuseShaderRadeon();

    if ( gl_truform.value )
    {
        glDisable(GL_PN_TRIANGLES_ATI);
    }
}