/***************************************************************************
                          shader.cpp  -  description
                             -------------------
    begin                : Don Apr 27 2006
    copyright            : (C) 2006 by Krippel Harald
    email                : neuro.harald@surfeu.at
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

// glslang
#include "GLee.h"

#include "shader.h"
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

shader::shader(){

  if (GLEE_ARB_vertex_shader && GLEE_ARB_fragment_shader) {
		fprintf(stderr,"Ready for GLSL\n");
    glslok=1;
  } else {
		fprintf(stderr,"No GLSL support\n");
    glslok=0;
	}
  p=0;
  v=0;
  f=0;
  VerFileName[0]=0;
  FraFileName[0]=0;
}

shader::~shader()
{
   TurnOff();
   Release();
}

void shader::initShaders(const char * strVertex,const char * strFragment){

  // This function actually loads and starts our shaders.  Basically,
	// we create some pointers for shaders, then load in text files for
	// each shader, then compile the shader.  We also need to create a
	// program object that represents all of our shaders.  We link the
	// loaded shaders to our program object and then turn our shader on.
  
 char *vs,*fs;

  strncpy(VerFileName,strVertex,255);
  strncpy(FraFileName,strFragment,255);

  if(glslok == 1)
  {
	  v = glCreateShader(GL_VERTEX_SHADER);
	  f = glCreateShader(GL_FRAGMENT_SHADER);

	  vs = FileRead(strVertex);
	  fs = FileRead(strFragment);

    const char * ff = fs;
    const char * vv = vs;

	  glShaderSource(v, 1, &vv,NULL);
	  glShaderSource(f, 1, &ff,NULL);

	  free(vs);
    free(fs);

	  glCompileShader(v);
    GetInfoLog(v);     // if error
	  glCompileShader(f);
    GetInfoLog(f);     // if error

	  p = glCreateProgram();
	  glAttachShader(p,f);
	  glAttachShader(p,v);

	  glLinkProgram(p);
//	  glUseProgram(p);
   }
}

void shader::compile()
{
    TurnOff();
    Release();
    initShaders(VerFileName,FraFileName);
}


GLint shader::GetVariable(char * strVariable)
{
	// If we don't have an active program object, let's return -1
	// This returns the variable ID for a variable that is used to find
	// the address of that variable in memory.

  if(!p)
		return -1;

	return glGetUniformLocationARB(p, strVariable);
}


void shader::TurnOn()
{
     glUseProgram(p);
}

void shader::TurnOff()
{
     glUseProgram(0); 
}
   
void shader::Release()
{
  // To free a shader we need to detach the vertex and fragment
	// shader pointers from the program object, then free each one.
	// Once that is done we can finally delete the program object.
	// If our vertex shader pointer is valid, free it
	// If our fragment shader pointer is valid, free it
  // If our program object pointer is valid, free it

  if(v)
	{
		glDetachObjectARB(p, v);
		glDeleteObjectARB(v);
		v = 0;
	}

	if(f)
	{
		glDetachObjectARB(p, f);
		glDeleteObjectARB(f);
		f = 0;
	}
	if(p)
	{
		glDeleteObjectARB(p);
		p = 0;
	}
}

char * shader::GetInfoLog(GLuint handle)                     // beta status
{
	GLint blen = 0;	// length of buffer to allocate
	GLint slen = 0;	// strlen GL actually wrote to buffer
  char filename[256];
  filename[0]=0;
  if(handle == v) strncpy(filename,VerFileName,255);
  if(handle == v) strncpy(filename,FraFileName,255);
  glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB , &blen);
	if (blen > 1)
	{
	    GLcharARB* infoLog = new GLcharARB[blen];       
	    glGetInfoLogARB( handle, blen, &slen, infoLog );
      fprintf(stderr,"Shader: %s\n%s\n",filename,infoLog);
      fflush(NULL);
	    delete [] infoLog;
//        return(infoLog);
	}
  return(NULL);
}

char * shader::FileRead(const char *fn) {


// pleas rewrite this c source to c++ code !!!!!!!!!!!!!

  FILE *fp;
	char *content = NULL;

	int f,count;
	f = open(fn, O_RDONLY);

	count = lseek(f, 0, SEEK_END);

	close(f);

	if (fn != NULL) {
		fp = fopen(fn,"rt");

		if (fp != NULL) {


			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);
		}
	}
	return content;
}
