/* This file contains C functions to be called by prolog OpenGL predicates */

#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glu.h>
/*#include "/usr/lib/pl-5.0.4/include/SWI-Prolog.h"*/
#include "/usr/lib/pl-5.1.3/include/SWI-Prolog.h"


void c_glut_display(void);
void c_glut_reshape(void);
foreign_t c_glutDisplayFunc(void);
foreign_t c_glutReshapeFunc(void);
foreign_t c_glViewport(term_t X, term_t Y, term_t W, term_t H);
foreign_t c_glCallList(term_t Index);
foreign_t c_glClear(term_t Apply_options);
foreign_t c_glEnable(term_t Option);
foreign_t c_glLightfv(term_t Light,term_t ParamName,term_t A,term_t B,term_t C,term_t D);
foreign_t c_glMatrixMode(term_t Mode);
foreign_t c_glNewList(term_t DisplayListIndex,term_t OptionList);
foreign_t c_glTranslatef(term_t X,term_t Y,term_t Z);
foreign_t c_gluLookAt(term_t EyeX,term_t EyeY,term_t EyeZ,
		      term_t CenterX,term_t CenterY,term_t CenterZ,
		      term_t UpX,term_t UpY,term_t Upz);
foreign_t c_gluPerspective(term_t FovY,term_t Aspect,term_t zNear,term_t zFar);
foreign_t c_gluNewQuadric(term_t PL_gluQuadricPtr);
foreign_t c_gluQuadricDrawStyle(term_t gluQuadricPtr,term_t OptionList);
foreign_t c_gluSphere(term_t GLUquadricPtr,term_t Radius,term_t Slices,term_t Stacks);
foreign_t c_glutCreateWindow(term_t String);
foreign_t c_glutInit(void);
foreign_t c_glutInitDisplayMode(term_t AppliedList);
foreign_t c_glutSwapBuffers(void);
foreign_t c_glutMainLoop(void);
foreign_t c_glEndList(void);
foreign_t c_glLoadIdentity(void);
foreign_t c_glOrtho(term_t PL_Left,term_t PL_Right,term_t PL_Bottom,term_t PL_Top,term_t PL_Near,term_t PL_Far);
foreign_t c_glScalef(term_t XScale, term_t YScale, term_t ZScale);
foreign_t c_glBegin(term_t Mode);
foreign_t c_glEnd(void);
foreign_t c_glColor3f(term_t PL_Red, term_t PL_Green, term_t PL_Blue);
foreign_t c_glVertex2i(term_t PL_X, term_t PL_Y);
foreign_t c_glFlush(void);
foreign_t dl(void);

install_t install()
{
  PL_register_foreign("c_glCallList",1,c_glCallList,PL_FA_NOTRACE);
  PL_register_foreign("c_glClear",1,c_glClear,PL_FA_NOTRACE);
    PL_register_foreign("c_glEnable",1,c_glEnable,PL_FA_NOTRACE);
    PL_register_foreign("c_glLightfv",6,c_glLightfv,PL_FA_NOTRACE);
    PL_register_foreign("c_glMatrixMode",1,c_glMatrixMode,PL_FA_NOTRACE);
    PL_register_foreign("c_glNewList",2,c_glNewList,PL_FA_NOTRACE);
    PL_register_foreign("c_glTranslatef",3,c_glTranslatef,PL_FA_NOTRACE);
    PL_register_foreign("c_gluLookAt",9,c_gluLookAt,PL_FA_NOTRACE);
    PL_register_foreign("c_gluPerspective",4,c_gluPerspective,PL_FA_NOTRACE);
    PL_register_foreign("c_gluNewQuadric",1,c_gluNewQuadric,PL_FA_NOTRACE);
    PL_register_foreign("c_gluQuadricDrawStyle",2,c_gluQuadricDrawStyle,PL_FA_NOTRACE);
    PL_register_foreign("c_gluSphere",4,c_gluSphere,PL_FA_NOTRACE);
    PL_register_foreign("c_glutCreateWindow",1,c_glutCreateWindow,PL_FA_NOTRACE);
    PL_register_foreign("c_glutDisplayFunc",0,c_glutDisplayFunc,PL_FA_NOTRACE);
    PL_register_foreign("c_glutReshapeFunc",0,c_glutReshapeFunc,PL_FA_NOTRACE);
    PL_register_foreign("c_glutInit",0,c_glutInit,PL_FA_NOTRACE);
    PL_register_foreign("c_glutInitDisplayMode",1,c_glutInitDisplayMode,PL_FA_NOTRACE);
    PL_register_foreign("c_glutSwapBuffers",0,c_glutSwapBuffers,PL_FA_NOTRACE);
    PL_register_foreign("c_glutMainLoop",0,c_glutMainLoop,PL_FA_NOTRACE);
    PL_register_foreign("c_glEndList",0,c_glEndList,PL_FA_NOTRACE);
    PL_register_foreign("c_glViewport",4,c_glViewport,PL_FA_NOTRACE);
    PL_register_foreign("c_glLoadIdentity",0,c_glLoadIdentity,PL_FA_NOTRACE);
    PL_register_foreign("c_glOrtho",6,c_glOrtho,PL_FA_NOTRACE);
    PL_register_foreign("c_glScalef",3,c_glScalef,PL_FA_NOTRACE);
    PL_register_foreign("c_glBegin",1,c_glBegin,PL_FA_NOTRACE);
    PL_register_foreign("c_glEnd",0,c_glEnd,PL_FA_NOTRACE);
    PL_register_foreign("c_glColor3f",3,c_glColor3f,PL_FA_NOTRACE);
    PL_register_foreign("c_glVertex2i",2,c_glVertex2i,PL_FA_NOTRACE);
    PL_register_foreign("c_glFlush",0,c_glFlush,PL_FA_NOTRACE);
    PL_register_foreign("dl",0,dl,PL_FA_NOTRACE);
}

foreign_t dl(void)
{
  GLUquadricObj *qobj;
  qobj = gluNewQuadric();
  gluQuadricDrawStyle(qobj, GLU_FILL);
  glNewList(1, GL_COMPILE);  /* create sphere display list */
  gluSphere(qobj, /* radius */ 1.0, /* slices */ 20,
  /* stacks */ 20);
  //glEndList();
  PL_succeed;
}

/* OpenGL / libGL calls */

foreign_t c_glFlush(void) { printf("call to c_glFlush\n"); glFlush(); PL_succeed; }

foreign_t c_glVertex2i(term_t PL_X, term_t PL_Y)
{
  GLint x, y;
  
  PL_get_integer(PL_X,&x);
  PL_get_integer(PL_Y,&y);
  printf("call to glVertex2i(%d,%d)\n",x,y);
  glVertex2i(x,y);
  PL_succeed;
}

foreign_t c_glColor3f(term_t PL_Red, term_t PL_Green, term_t PL_Blue)
{
  GLdouble GLr, GLg, GLb;

  PL_get_float(PL_Red,&GLr);
  PL_get_float(PL_Green,&GLg);
  PL_get_float(PL_Blue,&GLb);
  printf("call to glColor3f(%f,%f,%f)\n",(float)GLr,(float)GLg,(float)GLb);
  glColor3f((float)GLr,(float)GLg,(float)GLb);
  PL_succeed;
}

foreign_t c_glBegin(term_t PL_Mode)
{
  GLenum mode;
  int i_mode;
  
  PL_get_integer(PL_Mode,&i_mode);
  mode = (GLenum)i_mode;
  printf("call to glBegin(%d)\n",mode);
  glBegin(mode);
  PL_succeed;
}

foreign_t c_glEnd(void)
{
  printf("call to glEnd()\n");
  glEnd();
  PL_succeed;
}

foreign_t c_glScalef(term_t XScale, term_t YScale, term_t ZScale)
{
  GLdouble x,y,z;

  PL_get_float(XScale,&x);
  PL_get_float(YScale,&y);
  PL_get_float(ZScale,&z);
  printf("call to glScalef(%f,%f,%f)\n",(float)x,(float)y,(float)z);
  glScalef((float)x,(float)y,(float)z);
  PL_succeed;
}
foreign_t c_glOrtho(term_t PL_Left,term_t PL_Right,term_t PL_Bottom,term_t PL_Top,term_t PL_Near,term_t PL_Far)
{
  GLdouble left,right,bottom,top,near,far;

  PL_get_float(PL_Left,&left);
  PL_get_float(PL_Right,&right);
  PL_get_float(PL_Bottom,&bottom);
  PL_get_float(PL_Top,&top);
  PL_get_float(PL_Near,&near);
  PL_get_float(PL_Far,&far);
  printf("call to glOrtho(%f,%f,%f,%f,%f,%f)\n",left,right,bottom,top,near,far);
  glOrtho(left,right,bottom,top,near,far);
  PL_succeed;
}

foreign_t c_glLoadIdentity(void) 
{ 
  printf("call to glLoadIdentity()\n"); 
  glLoadIdentity(); 
  PL_succeed;} 

foreign_t c_glViewport(term_t PL_X, term_t PL_Y, term_t PL_W, term_t PL_H)
{
  GLint x,y;
  GLsizei w,h;
  GLint test=2;

  PL_get_integer(PL_X,&x);
  PL_get_integer(PL_Y,&y);
  PL_get_integer(PL_W,&w);
  PL_get_integer(PL_H,&h);
  printf("call to glViewport(%d,%d,%d,%d,%d)\n",x,y,w,h,test);
  glViewport(x,y,w,h);

  PL_succeed;
}


foreign_t c_glEndList(void) { 
  printf("call to glEndList()\n"); 
  glEndList(); 
  PL_succeed; }

foreign_t c_glCallList(term_t PL_index)
{
  GLuint display_list_id;
  
  PL_get_integer(PL_index,&display_list_id);
  printf("call to glCallList(%d)\n",(GLuint)display_list_id);
  glCallList((GLuint)display_list_id);
  PL_succeed;
  
}

foreign_t c_glClear(term_t options)
{
  GLbitfield mask;
  int options_int;
  
  PL_get_integer(options,&options_int);
  mask = (GLbitfield)options_int;
  printf("call to glClear(%d)\n",(int)mask);
  glClear(mask);
  PL_succeed;

}

foreign_t c_glEnable(term_t option)
{
  GLenum capability;
  int option_int;
  
  PL_get_integer(option,&option_int);
  capability = (GLenum)option_int;
  printf("call to glEnable(%d)\n",capability);
  glEnable(capability);
  PL_succeed;

}
foreign_t c_glLightfv(term_t PL_Light,term_t PL_ParamName,term_t PL_A,term_t PL_B,term_t PL_C,term_t PL_D)
{

  GLfloat parameters[]= {0.0,0.0,0.0,0.0};

  GLenum light,
    paramname;

  double temp_a,temp_b,temp_c,temp_d;

  PL_get_float(PL_A,&temp_a);
  PL_get_float(PL_B,&temp_b);
  PL_get_float(PL_C,&temp_c);
  PL_get_float(PL_D,&temp_d);

  parameters[0]= (GLfloat)temp_a;
  parameters[1]= (GLfloat)temp_b;
  parameters[2]= (GLfloat)temp_c;
  parameters[3]= (GLfloat)temp_d;

  PL_get_integer(PL_Light,&light);
  PL_get_integer(PL_ParamName,&paramname);

  printf("call to glLightfc(%d,%d,[%f,%f,%f,%f])\n",(GLenum)light,(GLenum)paramname,parameters[0],parameters[1],parameters[2],parameters[3]);
  glLightfv((GLenum)light,(GLenum)paramname,parameters);
  PL_succeed;

}

foreign_t c_glMatrixMode(term_t PL_Mode)
{
  GLenum mode;

  PL_get_integer(PL_Mode,&mode);
  printf("call to glMatrixMode(%d)\n",(GLenum)mode);
  glMatrixMode((GLenum)mode);
  PL_succeed;

}

foreign_t c_glNewList(term_t PL_DisplayListIndex,term_t PL_OptionList)
{

  GLuint list;
  GLenum mode;

  PL_get_integer(PL_DisplayListIndex,&list);
  PL_get_integer(PL_OptionList,&mode);
  printf("call to glNewList(%d,%d)\n",(GLuint)list,(GLenum)mode);
  glNewList((GLuint)list,(GLenum)mode);
  PL_succeed;

}
foreign_t c_glTranslatef(term_t PL_X,term_t PL_Y,term_t PL_Z)
{
  double tempX,tempY,tempZ;

  GLfloat X, Y, Z;
  PL_get_float(PL_X,&tempX);
  PL_get_float(PL_Y,&tempY);
  PL_get_float(PL_Z,&tempZ);
  X = (GLfloat)tempX;
  Y = (GLfloat)tempY;
  Z = (GLfloat)tempZ;
  printf("call to glTranslatef(%f,%f,%f)\n",X,Y,Z);
  glTranslatef(X,Y,Z);
  PL_succeed;

}
/* GLU Interaction */

foreign_t c_gluLookAt(term_t PL_EyeX,term_t PL_EyeY,term_t PL_EyeZ,
		      term_t PL_CenterX,term_t PL_CenterY,term_t PL_CenterZ,
		      term_t PL_UpX,term_t PL_UpY,term_t PL_UpZ)

{

  GLdouble iX,iY,iZ,cX,cY,cZ,uX,uY,uZ;

  PL_get_float(PL_EyeX,&iX);
  PL_get_float(PL_EyeY,&iY);
  PL_get_float(PL_EyeZ,&iZ);
  PL_get_float(PL_CenterX,&cX);
  PL_get_float(PL_CenterY,&cY);
  PL_get_float(PL_CenterZ,&cZ);
  PL_get_float(PL_UpX,&uX);
  PL_get_float(PL_UpY,&uY);
  PL_get_float(PL_UpZ,&uZ);

  printf("call to gluLookAt(%f,%f,%f,%f,%f,%f,%f,%f,%f)\n",
	 (GLdouble)iX,(GLdouble)iY,(GLdouble)iZ,
	 (GLdouble)cX,(GLdouble)cY,(GLdouble)cZ,
	 (GLdouble)uX,(GLdouble)uY,(GLdouble)uZ);
  gluLookAt((GLdouble)iX,(GLdouble)iY,(GLdouble)iZ,
	    (GLdouble)cX,(GLdouble)cY,(GLdouble)cZ,
	    (GLdouble)uX,(GLdouble)uY,(GLdouble)uZ);
  PL_succeed;
}

foreign_t c_gluPerspective(term_t PL_FovY,term_t PL_Aspect,term_t PL_zNear,term_t PL_zFar)
{
  GLdouble fovy,aspect,zNear,zFar;
  PL_get_float(PL_FovY,&fovy);
  PL_get_float(PL_Aspect,&aspect);
  PL_get_float(PL_zNear,&zNear);
  PL_get_float(PL_zFar,&zFar);
  printf("call to gluPerspective(%f,%f,%f,%f)\n",(GLdouble)fovy,(GLdouble)aspect,(GLdouble)zNear,(GLdouble)zFar);
  gluPerspective((GLdouble)fovy,(GLdouble)aspect,(GLdouble)zNear,(GLdouble)zFar);
  PL_succeed;
}

foreign_t c_gluNewQuadric(term_t PL_gluQuadricPtr)
{
  GLUquadricObj *gluQuadricPtr;
  
  gluQuadricPtr = gluNewQuadric();
  printf("call to gluNewQuadric()\n");
  printf("Address of object is %d\n",gluQuadricPtr);
  PL_unify_pointer(PL_gluQuadricPtr,gluQuadricPtr);
  PL_succeed;
}

foreign_t c_gluQuadricDrawStyle(term_t PL_gluQuadricPtr,term_t PL_OptionList)
{
  // GLUquadricObj
  void *gluQuadricPtr;
  GLenum draw;
  long g;
  printf("1:ENTERING QUADRICDRAWSTYLE\n\n\n");
  PL_get_pointer(PL_gluQuadricPtr,&gluQuadricPtr);
  printf("2:Pointer Address is %d\n",gluQuadricPtr);
  PL_get_integer(PL_OptionList,&draw);
  printf("3:ENTERING QUADRICDRAWSTYLE\n\n\n");
  gluQuadricDrawStyle(gluQuadricPtr,(GLenum)draw);
  printf("call to gluQuadricDrawStyle(%d,%d)\n",gluQuadricPtr,(GLenum)draw);
  PL_succeed;

}
foreign_t c_gluSphere(term_t PL_gluQuadricPtr,term_t PL_Radius,term_t PL_Slices,term_t PL_Stacks)
{

  void *gluQuadricPtr;
  GLdouble radius;
  GLint slices, stacks;

  PL_get_pointer(PL_gluQuadricPtr,&gluQuadricPtr);
  PL_get_float(PL_Radius,&radius);
  PL_get_integer(PL_Slices,&slices);
  PL_get_integer(PL_Stacks,&stacks);

  gluSphere(gluQuadricPtr,(GLdouble)radius,(GLint)slices,(GLint)stacks);
  printf("call to gluSphere(%d,%f,%d,%d)\n",gluQuadricPtr,(GLdouble)radius,(GLint)slices,(GLint)stacks);
  PL_succeed;
}
/* GLU Interaction */

foreign_t c_glutCreateWindow(term_t PL_String)
{
  char *string;

  PL_get_atom_chars(PL_String,&string);
  printf("call to glutCreateWindow(%s)\n",string);
  glutCreateWindow(string);
  PL_succeed;

}

void c_glut_reshape(void)
{
  qid_t query_handle;
  static predicate_t p;
  static term_t reshape_predicate;
  if(!reshape_predicate)
    reshape_predicate= PL_new_term_refs(1);

  if(!p)
    p = PL_predicate("glut_reshape_function",0,"user");

  query_handle = PL_open_query(NULL,PL_Q_NORMAL,p,reshape_predicate);
  PL_next_solution(query_handle);
  PL_cut_query(query_handle);    
}

foreign_t c_glutReshapeFunc(void)
{glutDisplayFunc(c_glut_reshape);
 PL_succeed;
}

void c_glut_display(void) 
{
  qid_t query_handle;
  static predicate_t p;
  static term_t display_predicate;

  if(!display_predicate)
    display_predicate= PL_new_term_refs(1);

  if(!p)
    p = PL_predicate("glut_display_function",0,"user");

  query_handle = PL_open_query(NULL,PL_Q_NORMAL,p,display_predicate);
  PL_next_solution(query_handle);
  PL_cut_query(query_handle);    
      
}

foreign_t c_glutDisplayFunc(void)
{glutDisplayFunc(c_glut_display);
 PL_succeed;
}

foreign_t c_glutInit(void)
{
  int i,j;
  int argc=0;
  char **argv ;

  argc = PL_query(PL_QUERY_ARGC);
  *argv = "-noop"; //PL_query(PL_QUERY_ARGV);
  glutInit(&argc,argv);
  printf("call to glutInit(%d)\n",argc);
  PL_succeed;
  
}

foreign_t c_glutInitDisplayMode(term_t PL_AppliedList)
{
  int mode_temp;
  unsigned int mode;

  PL_get_integer(PL_AppliedList,&mode_temp);
  mode = (unsigned int)mode_temp;
  glutInitDisplayMode(mode);
  printf("call to glutInitDisplayMode(%d)\n",mode);
  PL_succeed;

}
foreign_t c_glutSwapBuffers(void)
{
  glutSwapBuffers();
  printf("call tp glutSwapBuffers()\n");
  PL_succeed;
}

foreign_t c_glutMainLoop(void)
{

  printf("forking call to glutMainLoop()\n");
  
  glutMainLoop();

}










