/*
 * Copyright 2009 Canonical Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of either or both of the following licenses:
 *
 * 1) the GNU Lesser General Public License version 3, as published by the
 * Free Software Foundation; and/or
 * 2) the GNU Lesser General Public License version 2.1, 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 warranties of
 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the applicable version of the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of both the GNU Lesser General Public
 * License version 3 and version 2.1 along with this program.  If not, see
 * <http://www.gnu.org/licenses/>
 *
 * Authored by: Jay Taoko <jay.taoko@canonical.com>
 *
 */
/** 
 * SECTION:ctk-utils
 * @short_description: Utility functions
 *
 * Utility functions
 */

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <string.h>

#include <GL/glew.h>
#include <GL/glxew.h>

#include <clutter/clutter.h>
#include "ctk-utils.h"
#include "ctk-arb-asm-private.h"
#include <gio/gio.h>

ShaderProgramASM* ctk_create_shader_asm_program_from_source(const char* vstxt, const char* fstxt)
{
  ShaderProgramASM* sh = 0;

  if( vstxt == 0 || fstxt == 0)
    {
      return NULL;
    }

  sh = (ShaderProgramASM*) g_malloc0(sizeof(ShaderProgramASM));
  CHECKGL ( glGenProgramsARB(1, &sh->shvert) );
  CHECKGL ( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, sh->shvert) );
  glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen (vstxt), vstxt);
 
  if ( GL_INVALID_OPERATION == glGetError() )
    {
      const unsigned char *errString;
      /* Find the error position */
      GLint errPos;
      glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
      /* Print implementation-dependent program */
      /* errors and warnings string. */
      errString = (const unsigned char*) glGetString (GL_PROGRAM_ERROR_STRING_ARB);
      g_warning ("Error in shader at (%d): %s %s \n", errPos, errString, vstxt);

      CHECKGL ( glDeleteProgramsARB(1, &sh->shvert) );
      g_free (sh);
      return 0;
    }

  CHECKGL ( glGenProgramsARB(1, &sh->shfrag) );
  CHECKGL ( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, sh->shfrag) );
  glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen (fstxt), fstxt);
 
  if ( GL_INVALID_OPERATION == glGetError() )
    {
      const unsigned char *errString;
      /* Find the error position */
      GLint errPos;
      glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
      /* Print implementation-dependent program */
      /* errors and warnings string. */

      errString = (const unsigned char*) glGetString (GL_PROGRAM_ERROR_STRING_ARB);
      g_warning ("Error in shader at (%d): %s %s \n", errPos, errString, fstxt);
      CHECKGL ( glDeleteProgramsARB(1, &sh->shvert) );
      CHECKGL ( glDeleteProgramsARB(1, &sh->shfrag) );
      g_free (sh);
      return 0;
    }

  return sh;
}

void ctk_delete_shader_asm_program(ShaderProgramASM *sh)
{
  if (sh)
    {
      glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0);
      glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);

      if (sh->shvert)
        glDeleteProgramsARB(1, &sh->shvert);
      if (sh->shfrag)
        glDeleteProgramsARB(1, &sh->shfrag);
    }
}

void ctk_render_quad_rt_asm(CtkRenderTarget* rt, ShaderProgramASM *shader, int window_w, int window_h, int x, int y, int w, int h,
                            gfloat red, gfloat green, gfloat blue,
                            gfloat Opacity)
{
  guint texid = ctk_render_target_get_color_buffer_ogl_id(rt);
  guint texwidth = ctk_render_target_get_width(rt);
  guint texheight = ctk_render_target_get_height(rt);
  ctk_render_quad_asm(texid, texwidth, texheight, shader, window_w, window_h, x, y, w, h, red, green, blue, Opacity);
}

void ctk_render_quad_asm(guint texid, guint texwidth, guint texheight, ShaderProgramASM *shader,
                         int window_w, int window_h, int x, int y, int w, int h,
                         gfloat red, gfloat green, gfloat blue,
                         gfloat Opacity)
{
  ClutterVertex vtx[4];

  vtx[0].x = x;
  vtx[0].y = y;
  vtx[1].x = x;
  vtx[1].y = y+h;
  vtx[2].x = x+w;
  vtx[2].y = y+h;
  vtx[3].x = x+w;
  vtx[3].y = y;

  ctk_render_custom_quad_asm(texid, texwidth, texheight, shader, window_w, window_h, vtx, red, green, blue, Opacity);
}

void ctk_render_custom_quad_asm(guint texid, guint texwidth, guint texheight, ShaderProgramASM *shader, int window_w, int window_h,
                                ClutterVertex vtx[4],
                                gfloat red, gfloat green, gfloat blue,
                                gfloat Opacity)
{
  /* Set texture 0 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );

    CHECKGL( glBindTexture(GL_TEXTURE_2D, texid) );
  }

  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shader->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader->shfrag) );  

  /*
  int VertexLocation          = ATTRIB_POSITION;
  int TextureCoord0Location   = ATTRIB_COLOR_TEXCOORD0;
  int VertexColorLocation     = ATTRIB_COLOR;*/

  /* Save the blending states */
  glEnable(GL_BLEND);

  /* Preserve model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glBegin(GL_QUADS);
  {
    glColor4f(Opacity*red, Opacity*green, Opacity*blue, Opacity);
    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f);
    glVertex4f(vtx[0].x, vtx[0].y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f);
    glVertex4f(vtx[1].x, vtx[1].y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f);
    glVertex4f(vtx[2].x, vtx[2].y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f);
    glVertex4f(vtx[3].x, vtx[3].y, 0, 1.0f);

  }
  glEnd();

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void
ctk_render_masked_texture_asm (guint             tex_id,
                               guint             tex_mask_id,
                               guint             texwidth,
                               guint             texheight,
                               ShaderProgramASM* shader,
                               gint              window_w,
                               gint              window_h,
                               gint              x,
                               gint              y,
                               gint              w,
                               gint              h,
                               gfloat            opacity)
{
  gint blend;
  gint blend_src;
  gint blend_dst;
  gfloat VtxBuffer[] = { 
     // X    Y     Z     W     U0    V0    U1    V1    R     G     B     A
     x,      y,    0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, opacity,
     x,      y+h,  0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, opacity,
     x+w,    y+h,  0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, opacity,
     x+w,    y,    0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, opacity,
  };

  gint VertexLocation        = ATTRIB_POSITION;
  gint TextureCoord0Location = ATTRIB_COLOR_TEXCOORD0;
  gint TextureCoord1Location = ATTRIB_COLOR_TEXCOORD1;
  gint VertexColorLocation   = ATTRIB_COLOR;

  // Use the shader
  { 
    CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
    CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shader->shvert) );  
    CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
    CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader->shfrag) ); 
  }

  CHECKGL(glBindBuffer(GL_ARRAY_BUFFER_ARB, 0));
  CHECKGL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));

  CHECKGL( glEnableVertexAttribArrayARB (VertexLocation) );
  CHECKGL( glVertexAttribPointerARB ((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer) );

  if(TextureCoord0Location != -1)
  {
    //glClientActiveTexture(GL_TEXTURE0);
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glEnable (GL_TEXTURE_2D) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, tex_id) );

    CHECKGL( glEnableVertexAttribArrayARB (TextureCoord0Location) );
    CHECKGL( glVertexAttribPointerARB ((GLuint)TextureCoord0Location, 2, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 4) );
  }

  if(TextureCoord1Location != -1)
  {
    //glClientActiveTexture(GL_TEXTURE0);
    CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
    CHECKGL( glEnable (GL_TEXTURE_2D) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, tex_mask_id) );

    CHECKGL( glEnableVertexAttribArrayARB (TextureCoord1Location) );
    CHECKGL( glVertexAttribPointerARB ((GLuint)TextureCoord1Location, 2, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 6) );
  }

  if(VertexColorLocation != -1)
  { 
    CHECKGL( glEnableVertexAttribArrayARB (VertexColorLocation) );
    CHECKGL( glVertexAttribPointerARB ((GLuint)VertexColorLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 8) );
  }

  // Preserve model-view and projection matrices
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );

    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glGetIntegerv(GL_BLEND, &blend);
  glGetIntegerv(GL_BLEND_SRC, &blend_src);
  glGetIntegerv(GL_BLEND_DST, &blend_dst);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  CHECKGL( glDrawArrays(GL_QUADS, 0, 4) );

  // Restore model-view and projection matrices
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  //glBlendFunc(blend_src, blend_dst);

  CHECKGL( glDisableVertexAttribArrayARB(VertexLocation) );
  if(TextureCoord0Location != -1)
    CHECKGL( glDisableVertexAttribArrayARB(TextureCoord0Location) );
  if(TextureCoord1Location != -1)
    CHECKGL( glDisableVertexAttribArrayARB(TextureCoord1Location) );
  if(VertexColorLocation != -1)
    CHECKGL( glDisableVertexAttribArrayARB(VertexColorLocation) );

  glBlendFunc(blend_src, blend_dst);

  // disable texture unit 1 so clutter can resume normally
  CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
  CHECKGL( glDisable (GL_TEXTURE_2D) );

  // Stop using the shader program
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void
ctk_render_masked2_texture_asm (guint            tex_id,
                               guint             tex_mask_id,
                               guint             texwidth,
                               guint             texheight,
                               ShaderProgramASM* shader,
                               gint              window_w,
                               gint              window_h,
                               gint              x,
                               gint              y,
                               gint              w,
                               gint              h,
                               gfloat            Opacity)
{
  gint blend;
  gint blend_src;
  gint blend_dst;

  /* Set texture 0 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable  (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );

    CHECKGL( glBindTexture(GL_TEXTURE_2D, tex_id) );
  }

  /*  Set texture 1 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, 0) )
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable  (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );

    CHECKGL( glBindTexture(GL_TEXTURE_2D, tex_mask_id) );
  }

  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shader->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader->shfrag) );  

  /* Preserve model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glGetIntegerv(GL_BLEND, &blend);
  glGetIntegerv(GL_BLEND_SRC, &blend_src);
  glGetIntegerv(GL_BLEND_DST, &blend_dst);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glBegin(GL_QUADS);
  {
    glColor4f(1.0, 1.0, 1.0, Opacity);

    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE1, 0.0f, 1.0f);
    glVertex4f(x, y, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE1, 1.0f, 1.0f);
    glVertex4f(x+w, y, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f);
    glMultiTexCoord2f(GL_TEXTURE1, 1.0f, 0.0f);
    glVertex4f(x+w, y+h, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f);
    glMultiTexCoord2f(GL_TEXTURE1, 0.0f, 0.0f);
    glVertex4f(x, y+h, 0, 1.0f);
  }
  glEnd();

  glBlendFunc(blend_src, blend_dst);

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );

  /*  Set texture 1 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, 0) )
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glDisable  (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, 0) );
  }
}

void
ctk_render_texture_exponent_asm (guint              tex_id,
                                  guint             texwidth,
                                  guint             texheight,
                                  gint              window_w,
                                  gint              window_h,
                                  gint              x,
                                  gint              y,
                                  gint              w,
                                  gint              h,
                                  gfloat            exponent)
{
  gint blend;
  gint blend_src;
  gint blend_dst;
  gfloat VtxBuffer[] = { 
     // X    Y     Z     W     U0    V0    R     G     B     A
     x,      y,    0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, exponent,
     x,      y+h,  0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, exponent,
     x+w,    y+h,  0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, exponent,
     x+w,    y,    0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, exponent,
  };

  gint VertexLocation        = ATTRIB_POSITION;
  gint TextureCoord0Location = ATTRIB_COLOR_TEXCOORD0;
  gint VertexColorLocation   = ATTRIB_COLOR;

  // Use the shader
  { 
    CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
    CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, g_shExp_asm->shvert) );  
    CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
    CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_shExp_asm->shfrag) ); 
  }

  	CHECKGL (glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB,
				      0,
				      exponent,
				      exponent,
				      exponent,
				      exponent));
  
  CHECKGL(glBindBuffer(GL_ARRAY_BUFFER_ARB, 0));
  CHECKGL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));

  CHECKGL( glEnableVertexAttribArrayARB (VertexLocation) );
  CHECKGL( glVertexAttribPointerARB ((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 40, VtxBuffer) );

  if(TextureCoord0Location != -1)
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glEnable (GL_TEXTURE_2D) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, tex_id) );

    CHECKGL( glEnableVertexAttribArrayARB (TextureCoord0Location) );
    CHECKGL( glVertexAttribPointerARB ((GLuint)TextureCoord0Location, 2, GL_FLOAT, GL_FALSE, 40, VtxBuffer + 4) );
  }

  if(VertexColorLocation != -1)
  { 
    CHECKGL( glEnableVertexAttribArrayARB (VertexColorLocation) );
    CHECKGL( glVertexAttribPointerARB ((GLuint)VertexColorLocation, 4, GL_FLOAT, GL_FALSE, 40, VtxBuffer + 6) );
  }

  // Preserve model-view and projection matrices
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );

    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glGetIntegerv(GL_BLEND, &blend);
  glGetIntegerv(GL_BLEND_SRC, &blend_src);
  glGetIntegerv(GL_BLEND_DST, &blend_dst);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  CHECKGL( glDrawArrays(GL_QUADS, 0, 4) );

  // Restore model-view and projection matrices
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  CHECKGL( glDisableVertexAttribArrayARB(VertexLocation) );
  if(TextureCoord0Location != -1)
    CHECKGL( glDisableVertexAttribArrayARB(TextureCoord0Location) );
  if(VertexColorLocation != -1)
    CHECKGL( glDisableVertexAttribArrayARB(VertexColorLocation) );

  glBlendFunc(blend_src, blend_dst);

  // Stop using the shader program
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void ctk_render_quad_alpha_mask_asm(
      unsigned int texid,
      unsigned int texture_width,
      unsigned int texture_height,
      gfloat red, gfloat green, gfloat blue, gfloat alpha,
      int window_w, int window_h, int x, int y, int w, int h)
{
  /* Set texture 0 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );

    CHECKGL( glBindTexture(GL_TEXTURE_2D, texid) );
  }

  /*  Set texture 1 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, 0) )
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glDisable (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
  }

  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, g_shTextureAlpha_asm->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_shTextureAlpha_asm->shfrag) );  

  /* Preserve model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glBegin(GL_QUADS);
  {
    glColor4f( 
        (gfloat)red,
        (gfloat)green,
        (gfloat)blue,
        (gfloat)alpha);

    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f);
    glVertex4f(x, y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f);
    glVertex4f(x+w, y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f);
    glVertex4f(x+w, y+h, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f);
    glVertex4f(x, y+h, 0, 1.0f);
  }
  glEnd();

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void custom_render_quad_gaussian_blur_separable_asm(CtkRenderTarget* rt,
                                    gboolean horizontal, gfloat sigma,
                                    int window_w, int window_h, int x, int y, int w, int h)
{
  guint num_tap = 3; /* must be odd number */
  gfloat W[3];
  gfloat sum = 0.0f;
  guint c = 0;
  guint half = (num_tap-1)/2;

  sigma = 1.0f/3.0f;

  W[half] = (1.0f/(sqrt(2.0f*3.14159265358f)*sigma)) * exp(-0.0f/(2.0f*sigma*sigma));
  sum += W[half];
  for(c = 0; c < half; c++)
  {
    float X = (c + 1)*(c + 1);
    W[half - c - 1] = W[half + c + 1] = (1.0f/(sqrt(2.0f*3.14159265358f)*sigma)) * exp(-X/(2.0f*sigma*sigma));
    sum += 2.0f * W[half - c - 1];
  }

  /* normalization */
  for(c = 0; c < num_tap; c++)
  {
    W[c] = W[c] / sum;
  }

  /* Set texture 0 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );

    CHECKGL( glBindTexture(GL_TEXTURE_2D, ctk_render_target_get_color_buffer_ogl_id(rt)) );
  }

  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, g_shBlur_asm->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_shBlur_asm->shfrag) );  

  /*int VertexLocation          = ATTRIB_POSITION;
  int TextureCoord0Location   = ATTRIB_COLOR_TEXCOORD0;
  int VertexColorLocation     = ATTRIB_COLOR;*/

  // Set the Gaussian weights
  if (horizontal)
    {
      float delta = 1.0f/(float)ctk_render_target_get_width(rt);
      float ucoord = -((num_tap-1)/2.0f)/ctk_render_target_get_width(rt);
      int ii = 0;
      for(ii = 0; ii < num_tap; ii++)
        {
          CHECKGL( glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, ii, ucoord, 0, 0, 0) );
          CHECKGL( glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, ii+num_tap, W[ii], W[ii], W[ii], 1.0f) );
          ucoord += delta;
        }
    }
  else
    {
      float delta = 1.0f/(float)ctk_render_target_get_height(rt);
      float vcoord = -((num_tap-1)/2.0f)/(float)ctk_render_target_get_height(rt);
      int ii = 0;
      for(ii = 0; ii < num_tap; ii++)
      {
          CHECKGL( glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, ii,   0,  vcoord, 0, 0) );
          CHECKGL( glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, ii+num_tap, W[ii], W[ii], W[ii], 1.0f) );
          vcoord += delta;
      }
    }


  /*int blend;
  int blend_src;
  int blend_dst;

  glGetIntegerv(GL_BLEND, &blend);
  glGetIntegerv(GL_BLEND_SRC, &blend_src);
  glGetIntegerv(GL_BLEND_DST, &blend_dst);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/

  /* Preserve model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  glBegin(GL_QUADS);
  {
    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f);
    glVertex4f(x, y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f);
    glVertex4f(x+w, y, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f);
    glVertex4f(x+w, y+h, 0, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f);
    glVertex4f(x, y+h, 0, 1.0f);
  }
  glEnd();

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }
  /*glBlendFunc(blend_src, blend_dst);*/

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void custom_render_quad_texture_mask_asm(unsigned int base_texid,
      unsigned int texid,
      unsigned int texture_width,
      unsigned int texture_height,
      ShaderProgramASM *shader,
      int window_w,
      int window_h,
      int x,
      int y,
      int w,
      int h,
      float Opacity)
{
  float tile_u;
  float tile_v;
  /*int blend;
  int blend_src;
  int blend_dst;*/

  /* To be used with the Exponent.frag shader for the honeycomb blend texture effect */
  
  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shader->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader->shfrag) );  

  /*int VertexLocation          = ATTRIB_POSITION;
  int TextureCoord0Location   = ATTRIB_COLOR_TEXCOORD0;
  int VertexColorLocation     = ATTRIB_COLOR;*/

  /* Set texture 0 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable  (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, base_texid) );
  }

  /*  Set texture 1 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable  (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, texid) );
  }

  /* Preserve model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, window_w, window_h, 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  /*glGetIntegerv(GL_BLEND, &blend);
  glGetIntegerv(GL_BLEND_SRC, &blend_src);
  glGetIntegerv(GL_BLEND_DST, &blend_dst);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  //glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);*/

  tile_u = (float)w/texture_width;
  tile_v = (float)h/texture_height;

  glColor4f(Opacity, Opacity, Opacity, Opacity);
  glBegin(GL_QUADS);
  {
    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE1, 0.0f, tile_v);
    glVertex4f(x, y, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f);
    glMultiTexCoord2f(GL_TEXTURE1, tile_u, tile_v);
    glVertex4f(x+w, y, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f);
    glMultiTexCoord2f(GL_TEXTURE1, tile_u, 0.0f);
    glVertex4f(x+w, y+h, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f);
    glMultiTexCoord2f(GL_TEXTURE1, 0.0f, 0.0f);
    glVertex4f(x, y+h, 0, 1.0f);
  }
  glEnd();

  //glBlendFunc(blend_src, blend_dst);

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  /*  Disable texture 1 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE1) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glDisable (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, 0) );
  }

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void ctk_copy_rendertarget_to_rendertarget_asm(CtkRenderTarget* rt_src, float u0, float v0, float u1, float v1,
                    CtkRenderTarget* rt_dst, int x_dst, int y_dst, int w_dst, int h_dst)
{
  ctk_render_target_bind(rt_dst);

  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, g_shTexture_asm->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_shTexture_asm->shfrag) );  

  /*int VertexLocation          = ATTRIB_POSITION;
  int TextureCoord0Location   = ATTRIB_COLOR_TEXCOORD0;
  int VertexColorLocation     = ATTRIB_COLOR;*/

  /* Set texture 0 environment mode */
  {
    CHECKGL( glActiveTextureARB(GL_TEXTURE0) );
    CHECKGL( glDisable (GL_TEXTURE_1D) );
    CHECKGL( glEnable  (GL_TEXTURE_2D) );
    CHECKGL( glDisable (GL_TEXTURE_3D) );
    CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
    CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
    CHECKGL( glBindTexture(GL_TEXTURE_2D, ctk_render_target_get_color_buffer_ogl_id(rt_src)) );
  }

  /* Preserve model-view and projection matrices */
  {
    CHECKGL( glViewport(0, 0, ctk_render_target_get_width(rt_dst), ctk_render_target_get_height(rt_dst)) );
    CHECKGL( glScissor(0, 0, ctk_render_target_get_width(rt_dst), ctk_render_target_get_height(rt_dst)) );
    CHECKGL( glDisable(GL_SCISSOR_TEST) );
  
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, ctk_render_target_get_width(rt_dst), ctk_render_target_get_height(rt_dst), 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  glBegin(GL_QUADS);
  {
    glMultiTexCoord2f(GL_TEXTURE0, u0, v0);
    glVertex4f(x_dst, y_dst, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, u0, v1);
    glVertex4f(x_dst, y_dst+h_dst, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, u1, v1);
    glVertex4f(x_dst+w_dst, y_dst+h_dst, 0, 1.0f);

    glMultiTexCoord2f(GL_TEXTURE0, u1, v0);
    glVertex4f(x_dst+w_dst, y_dst, 0, 1.0f);
  }
  glEnd();

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );
}

void ctk_copy_render_target_to_cached_texture_asm(CtkEffectContext *fxctx, CtkRenderTarget* rt_src, guint texid)
{
  CtkRenderTarget *rt_cache = ctk_effect_context_get_utility_render_target(fxctx);
  guint dest_fbo = ctk_render_target_get_frame_buffer_ogl_id (rt_cache);
  //guint src_fbo = 0;

  guint rt_width = ctk_render_target_get_width(rt_src);
  guint rt_height = ctk_render_target_get_height(rt_src);
  
  ctk_render_target_resize(rt_cache, rt_width, rt_height);
  CHECKGL (glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest_fbo));

//CHECKGL (glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, priv->cached_renderbuffer_texture));
//CHECKGL (glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT,
//                                   GL_DEPTH_COMPONENT,
//                                   actor_screen_width,
//                                   actor_screen_height));
//CHECKGL (glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
//                                       GL_DEPTH_ATTACHMENT_EXT,
//                                       GL_RENDERBUFFER_EXT,
//                                       priv->cached_renderbuffer_texture));

  CHECKGL (glActiveTextureARB(GL_TEXTURE0) );
  CHECKGL (glBindTexture (GL_TEXTURE_2D, texid) );
  CHECKGL (glTexImage2D (GL_TEXTURE_2D,
                             0,
                             GL_RGBA8,
                             rt_width,
                             rt_height,
                             0,
                             GL_RGBA,
                             GL_UNSIGNED_BYTE,
                             NULL));
      
  CHECKGL (glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
                                      GL_COLOR_ATTACHMENT0_EXT,
                                      GL_TEXTURE_2D,
                                      texid,
                                      0));
  
    ctk_copy_rendertarget_to_rendertarget_asm(rt_src, 0.0f, 0.0f, 1.0f, 1.0f, rt_cache, 0, 0, rt_width, rt_height);

//   /*ctk_copy_rendertarget_to_rendertarget_asm (src_fbo, 
//       0, 0, 1.0f, 1.0f,
//       rt_src,
//       0, 0, rt_width, rt_height);*/
// 
//   src_fbo = ctk_render_target_get_frame_buffer_ogl_id (rt_src);
// 
//   CHECKGL (glViewport (0, 0, rt_width, rt_height));
// 
//   CHECKGL (glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, src_fbo));
//   CHECKGL (glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dest_fbo));
// 
//   CHECKGL( glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT) );  
// 
//   CHECKGL (glBlitFramebufferEXT(0, 0, rt_width, rt_height,
//                         0, 0, rt_width, rt_height,
//                         GL_COLOR_BUFFER_BIT, GL_NEAREST));
// 
//   CHECKGL (glBindFramebufferEXT (GL_READ_FRAMEBUFFER_EXT, 0));
//   CHECKGL (glBindFramebufferEXT (GL_DRAW_FRAMEBUFFER_EXT, 0));
// 
//   CHECKGL (glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, dest_fbo));
// 
//   // remove the texture attached to the render target
//   CHECKGL (glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
//                                       GL_COLOR_ATTACHMENT0_EXT,
//                                       GL_TEXTURE_2D,
//                                       0,
//                                       0));
// 
//   CHECKGL (glActiveTextureARB(GL_TEXTURE0) );
//   CHECKGL (glBindTexture (GL_TEXTURE_2D, 0) );
// 
//   CHECKGL (glBindFramebufferEXT (GL_READ_FRAMEBUFFER_EXT, 0));
//   CHECKGL (glBindFramebufferEXT (GL_DRAW_FRAMEBUFFER_EXT, 0));
//   CHECKGL (glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0));
}

void
compute_gaussian_kernel (gint	   iRadius,    /* radius of kernel                  */
		   gfloat  fDeviation, /* deviation to use, 0.0f for auto   */
		   gfloat* W    /* pointer to array for coefficients */)
{
  guint num_tap = 7; /* must be odd number */

  gfloat sum = 0.0f;
  guint i = 0;

  float sigma = 1.0f;
  guint half = (num_tap-1)/2;

  W[half] = (1.0f/(sqrt(2.0f*3.14159265358f)*sigma)) * exp(0.0f/(2.0f*sigma*sigma));
  sum += W[half];
  for(i = 0; i < half; i++)
  {
    float X = (i + 1)*(i + 1);
    W[half - i - 1] = W[half + i + 1] = (1.0f/(sqrt(2.0f*3.14159265358f)*sigma)) * exp(-X/(2.0f*sigma*sigma));
    sum += 2.0f * W[half - i - 1];
  }

  /* normalization */
  for(i = 0; i < num_tap; i++)
  {
    W[i] = W[i] / sum;
  }
}

void
opengl_blur_pass (guint pSrcTexture,      /* texture to read from      */
      guint     src_width,
      guint     src_height,
		  GLfloat	  fDeviation,	              /* std. deviation to use     */
		  gboolean	HorizontalDirection,	    /* do which pass of the blur */
		  GLint		  iWindowWidth,	            /* width of window/context   */
		  GLint		  iWindowHeight,            /* height of window/context  */
      gboolean  invertTexCoord)
{
  gfloat hdelta = 0;
  gfloat vdelta = 0;
	static GLfloat afKernel[12];

	static GLfloat aafVertices[4][3];

  /* Use the shader */
  CHECKGL( glEnable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_VERTEX_PROGRAM_ARB, g_shMultipassBlur_asm->shvert) );  

  CHECKGL( glEnable(GL_FRAGMENT_PROGRAM_ARB) );
  CHECKGL( glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_shMultipassBlur_asm->shfrag) );  

	CHECKGL (glActiveTextureARB (GL_TEXTURE0));
  CHECKGL( glDisable (GL_TEXTURE_1D) );
  CHECKGL( glEnable (GL_TEXTURE_2D) );
  CHECKGL( glDisable (GL_TEXTURE_3D) );
  CHECKGL( glDisable (GL_TEXTURE_CUBE_MAP_EXT) );
  CHECKGL( glDisable (GL_TEXTURE_RECTANGLE_ARB) );
	CHECKGL (glBindTexture (GL_TEXTURE_2D, pSrcTexture));
  CHECKGL (glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
  CHECKGL (glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
  CHECKGL (glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
  CHECKGL (glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));

	compute_gaussian_kernel (5, fDeviation, afKernel);

	if (HorizontalDirection == FALSE)
	{
    /* Vertical blur */
    hdelta = 0.0f;
    vdelta = 1.0f / src_height;
	}
	else
	{
    /* Horizontal blur */
    hdelta = 1.0f / src_width;
    vdelta = 0.0f;
  }

  aafVertices[0][0] = 0.0f;
	aafVertices[0][1] = invertTexCoord?src_height:0.0;
	aafVertices[0][2] = 0.0f;

	aafVertices[1][0] = 0.0f;
	aafVertices[1][1] = invertTexCoord?0.0f:src_height;
	aafVertices[1][2] = 0.0f;

	aafVertices[2][0] = src_width;
	aafVertices[2][1] = invertTexCoord?0.0f:src_height;
	aafVertices[2][2] = 0.0f;

	aafVertices[3][0] = src_width;
	aafVertices[3][1] = invertTexCoord?src_height:0.0;
	aafVertices[3][2] = 0.0f;

	CHECKGL (glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB,
				      0,
				      afKernel[0],
				      afKernel[1],
				      afKernel[2],
				      afKernel[3]));
	CHECKGL (glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB,
				      1,
				      afKernel[4],
				      afKernel[5],
				      afKernel[6],
				      afKernel[7]));
	CHECKGL (glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB,
				      2,
				      afKernel[8],
				      afKernel[9],
				      afKernel[10],
				      afKernel[11]));

  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
    CHECKGL( glOrtho(0, iWindowWidth, iWindowHeight, 0, -1, 1) );
    
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPushMatrix() );
    CHECKGL( glLoadIdentity() );
  }

	glBegin (GL_QUADS);
	glColor4f (1.0f, 1.0f, 1.0f, 1.0f);

	glMultiTexCoord2fARB (GL_TEXTURE0, 0.0f + hdelta * -3.0f, 1.0f + vdelta * -3.0f);
	glMultiTexCoord2fARB (GL_TEXTURE1, 0.0f + hdelta * -2.0f, 1.0f + vdelta * -2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE2, 0.0f + hdelta * -1.0f, 1.0f + vdelta * -1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE3, 0.0f + hdelta *  0.0f, 1.0f + vdelta * -0.0f);
	glMultiTexCoord2fARB (GL_TEXTURE4, 0.0f + hdelta *  1.0f, 1.0f + vdelta *  1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE5, 0.0f + hdelta *  2.0f, 1.0f + vdelta *  2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE6, 0.0f + hdelta *  3.0f, 1.0f + vdelta *  3.0f);
	//glMultiTexCoord2fARB (GL_TEXTURE7, 0.0f + hdelta *  4.0f, 1.0f + vdelta *  4.0f);
	glVertex3f (aafVertices[0][0], aafVertices[0][1], aafVertices[0][2]);

	glMultiTexCoord2fARB (GL_TEXTURE0, 0.0f + hdelta * -3.0f, 0.0f + vdelta * -3.0f);
	glMultiTexCoord2fARB (GL_TEXTURE1, 0.0f + hdelta * -2.0f, 0.0f + vdelta * -2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE2, 0.0f + hdelta * -1.0f, 0.0f + vdelta * -1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE3, 0.0f + hdelta *  0.0f, 0.0f + vdelta * -0.0f);
	glMultiTexCoord2fARB (GL_TEXTURE4, 0.0f + hdelta *  1.0f, 0.0f + vdelta *  1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE5, 0.0f + hdelta *  2.0f, 0.0f + vdelta *  2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE6, 0.0f + hdelta *  3.0f, 0.0f + vdelta *  3.0f);
	//glMultiTexCoord2fARB (GL_TEXTURE7, 0.0f + hdelta *  4.0f, 0.0f + vdelta *  4.0f);
	glVertex3f (aafVertices[1][0], aafVertices[1][1], aafVertices[1][2]);

	glMultiTexCoord2fARB (GL_TEXTURE0, 1.0f + hdelta * -3.0f, 0.0f + vdelta * -3.0f);
	glMultiTexCoord2fARB (GL_TEXTURE1, 1.0f + hdelta * -2.0f, 0.0f + vdelta * -2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE2, 1.0f + hdelta * -1.0f, 0.0f + vdelta * -1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE3, 1.0f + hdelta *  0.0f, 0.0f + vdelta *  0.0f);
	glMultiTexCoord2fARB (GL_TEXTURE4, 1.0f + hdelta *  1.0f, 0.0f + vdelta *  1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE5, 1.0f + hdelta *  2.0f, 0.0f + vdelta *  2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE6, 1.0f + hdelta *  3.0f, 0.0f + vdelta *  3.0f);
	//glMultiTexCoord2fARB (GL_TEXTURE7, 1.0f + hdelta *  4.0f, 0.0f + vdelta *  4.0f);
	glVertex3f (aafVertices[2][0], aafVertices[2][1], aafVertices[2][2]);

	glMultiTexCoord2fARB (GL_TEXTURE0, 1.0f + hdelta * -3.0f, 1.0f + vdelta * -3.0f);
	glMultiTexCoord2fARB (GL_TEXTURE1, 1.0f + hdelta * -2.0f, 1.0f + vdelta * -2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE2, 1.0f + hdelta * -1.0f, 1.0f + vdelta * -1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE3, 1.0f + hdelta *  0.0f, 1.0f + vdelta *  0.0f);
	glMultiTexCoord2fARB (GL_TEXTURE4, 1.0f + hdelta *  1.0f, 1.0f + vdelta *  1.0f);
	glMultiTexCoord2fARB (GL_TEXTURE5, 1.0f + hdelta *  2.0f, 1.0f + vdelta *  2.0f);
	glMultiTexCoord2fARB (GL_TEXTURE6, 1.0f + hdelta *  3.0f, 1.0f + vdelta *  3.0f);
	//glMultiTexCoord2fARB (GL_TEXTURE7, 1.0f + hdelta *  4.0f, 1.0f + vdelta *  4.0f);
	glVertex3f (aafVertices[3][0], aafVertices[3][1], aafVertices[3][2]);

	glEnd ();

  /* Stop using the shader program */
  CHECKGL( glDisable(GL_VERTEX_PROGRAM_ARB) );
  CHECKGL( glDisable(GL_FRAGMENT_PROGRAM_ARB) );

  /* Restore model-view and projection matrices */
  {
    CHECKGL( glMatrixMode(GL_PROJECTION) );
    CHECKGL( glPopMatrix() );
    CHECKGL( glMatrixMode(GL_MODELVIEW) );
    CHECKGL( glPopMatrix() );
  }
}



