/* $Id: stereo.c,v 1.1 2003/02/14 20:18:20 mcfletch Exp $ */

/*
 * Togl - a Tk OpenGL widget
 * Copyright (C) 1996-1997  Brian Paul and Ben Bederson
 * See the LICENSE file for copyright details.
 */


/*
 * $Log: stereo.c,v $
 * Revision 1.1  2003/02/14 20:18:20  mcfletch
 * Switch to TOGL 1.6 (from CVS) which should support Tk 8.4 (and earlier versions as well)
 *
 * Revision 1.3  2001/12/20 13:59:31  beskow
 * Improved error-handling in togl.c in case of window creation failure
 * Added pkgIndex target to makefile
 * Updated documentation to reflect stubs-interface (Togl.html + new README.stubs)
 * Added tk8.4a3 headers
 * Removed obsolete Tk internal headers
 *
 * Revision 1.1.1.1  2001/02/15 16:32:28  beskow
 * imported sources
 *
 * Revision 1.1  1997/10/01 02:52:37  brianp
 * Initial revision
 *
 *
 * Revision 1.1  1997/9/28 21:23:50 Ben Evans
 * Initial revision based on double.c
 *
 */

#include "togl.h"
#include <stdlib.h>
#include <string.h>
#include <tcl.h>
#include <tk.h>

/*
 * The following variable is a special hack that is needed in order for
 * Sun shared libraries to be used for Tcl.
 */
#ifdef SUN
extern int matherr();
int *tclDummyMathPtr = (int *) matherr;
#endif


static GLuint FontBase;
static float xAngle = 0.0, yAngle = 0.0, zAngle = 0.0;
static GLfloat CornerX, CornerY, CornerZ;  /* where to print strings */
static GLfloat scale = 1.0;



/*
 * Togl widget create callback.  This is called by Tcl/Tk when the widget has
 * been realized.  Here's where one may do some one-time context setup or
 * initializations.
 */
void create_cb( struct Togl *togl )
{
   FontBase = Togl_LoadBitmapFont( togl, TOGL_BITMAP_8_BY_13 );
   if (!FontBase) {
      printf("Couldn't load font!\n");
      exit(1);
   }
}


/*
 * Togl widget reshape callback.  This is called by Tcl/Tk when the widget
 * has been resized.  Typically, we call glViewport and perhaps setup the
 * projection matrix.
 */
void reshape_cb( struct Togl *togl )
{
   int width = Togl_Width( togl );
   int height = Togl_Height( togl );
   float aspect = (float) width / (float) height;

   glViewport( 0, 0, width, height );

   /* Set up projection transform */
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glFrustum(-aspect, aspect, -1.0, 1.0, 1.0, 10.0);

   CornerX = -aspect;
   CornerY = -1.0;
   CornerZ = -1.1;

   /* Change back to model view transform for rendering */
   glMatrixMode(GL_MODELVIEW);
}



/*static void print_string( const char *s )*/
static void print_string( char *s)
{
   glCallLists( strlen(s), GL_UNSIGNED_BYTE, s );
}


/*
 * Togl widget display callback.  This is called by Tcl/Tk when the widget's
 * contents have to be redrawn.  Typically, we clear the color and depth
 * buffers, render our objects, then swap the front/back color buffers.
 */
void display_cb( struct Togl *togl )
{
   char *ident;
   GLfloat eyeDist = 2.0;
   GLfloat eyeOffset = 0.05;

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glLoadIdentity();	/* Reset modelview matrix to the identity matrix */
   glTranslatef(0.0, 0.0, -3.0);      /* Move the camera back three units */
   glScalef( scale, scale, scale );   /* Zoom in and out */
   glRotatef(xAngle, 1.0, 0.0, 0.0);  /* Rotate by X, Y, and Z angles */
   glRotatef(yAngle, 0.0, 1.0, 0.0);
   glRotatef(zAngle, 0.0, 0.0, 1.0);
    
   glEnable( GL_DEPTH_TEST );

   /* stereo right eye */
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   Togl_StereoFrustum(-1, 1, -1, 1, 1, 10, eyeDist, eyeOffset);
   glMatrixMode(GL_MODELVIEW);
   Togl_StereoDrawBuffer(GL_BACK_RIGHT);
   Togl_StereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   /* Front face */
   glBegin(GL_QUADS);
   glColor3f(0.0, 0.7, 0.1);	/* Green */
   glVertex3f(-1.0, 1.0, 1.0);
   glVertex3f(1.0, 1.0, 1.0);
   glVertex3f(1.0, -1.0, 1.0);
   glVertex3f(-1.0, -1.0, 1.0);
   /* Back face */
   glColor3f(0.9, 1.0, 0.0);   /* Yellow */
   glVertex3f(-1.0, 1.0, -1.0);
   glVertex3f(1.0, 1.0, -1.0);
   glVertex3f(1.0, -1.0, -1.0);
   glVertex3f(-1.0, -1.0, -1.0);
   /* Top side face */
   glColor3f(0.2, 0.2, 1.0);   /* Blue */
   glVertex3f(-1.0, 1.0, 1.0);
   glVertex3f(1.0, 1.0, 1.0);
   glVertex3f(1.0, 1.0, -1.0);
   glVertex3f(-1.0, 1.0, -1.0);
   /* Bottom side face */
   glColor3f(0.7, 0.0, 0.1);   /* Red */
   glVertex3f(-1.0, -1.0, 1.0);
   glVertex3f(1.0, -1.0, 1.0);
   glVertex3f(1.0, -1.0, -1.0);
   glVertex3f(-1.0, -1.0, -1.0);
   glEnd();

/* stereo left eye */
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   Togl_StereoFrustum(-1, 1, -1, 1, 1, 10, eyeDist, -eyeOffset);
   glMatrixMode(GL_MODELVIEW);
 
   Togl_StereoDrawBuffer(GL_BACK_LEFT);
   Togl_StereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   /* Front face */
   glBegin(GL_QUADS);
   glColor3f(0.0, 0.7, 0.1);	/* Green */
   glVertex3f(-1.0, 1.0, 1.0);
   glVertex3f(1.0, 1.0, 1.0);
   glVertex3f(1.0, -1.0, 1.0);
   glVertex3f(-1.0, -1.0, 1.0);
   /* Back face */
   glColor3f(0.9, 1.0, 0.0);   /* Yellow */
   glVertex3f(-1.0, 1.0, -1.0);
   glVertex3f(1.0, 1.0, -1.0);
   glVertex3f(1.0, -1.0, -1.0);
   glVertex3f(-1.0, -1.0, -1.0);
   /* Top side face */
   glColor3f(0.2, 0.2, 1.0);   /* Blue */
   glVertex3f(-1.0, 1.0, 1.0);
   glVertex3f(1.0, 1.0, 1.0);
   glVertex3f(1.0, 1.0, -1.0);
   glVertex3f(-1.0, 1.0, -1.0);
   /* Bottom side face */
   glColor3f(0.7, 0.0, 0.1);   /* Red */
   glVertex3f(-1.0, -1.0, 1.0);
   glVertex3f(1.0, -1.0, 1.0);
   glVertex3f(1.0, -1.0, -1.0);
   glVertex3f(-1.0, -1.0, -1.0);
   glEnd();

   
   glDisable( GL_DEPTH_TEST );
   glLoadIdentity();
   glColor3f( 1.0, 1.0, 1.0 );
   glRasterPos3f( CornerX, CornerY, CornerZ );
   glListBase( FontBase );
   /*ident = Togl_Ident( togl );
     if (strcmp(ident,"Single")==0) {
     print_string( "Single buffered" );
     }
     else {
     print_string( "Double buffered" );
   }*/
   print_string( Togl_Ident( togl) );
   Togl_SwapBuffers( togl );
}




int setXrot_cb( struct Togl *togl, int argc, char *argv[] )
{
   Tcl_Interp *interp = Togl_Interp(togl);

   /* error checking */
   if (argc != 3) {
      Tcl_SetResult( interp,
                     "wrong # args: should be \"pathName setXrot ?angle?\"",
                     TCL_STATIC );
      return TCL_ERROR;
   }

   xAngle = atof( argv[2] );
   
/* printf( "before %f ", xAngle ); */

   if ( xAngle < 0.0 ) {
     xAngle += 360.0;
   } else if ( xAngle > 360.0 ) {
     xAngle -= 360.0;
   }

/* printf( "after %f \n", xAngle ); */

   Togl_PostRedisplay( togl );

   /* Let result string equal value */
   strcpy( interp->result, argv[2] );
   return TCL_OK;
}



int setYrot_cb( struct Togl *togl, int argc, char *argv[] )
{
   Tcl_Interp *interp = Togl_Interp(togl);

   /* error checking */
   if (argc != 3) {
      Tcl_SetResult( interp,
                     "wrong # args: should be \"pathName setYrot ?angle?\"",
                     TCL_STATIC );
      return TCL_ERROR;
   }

   yAngle = atof( argv[2] );
   
   if ( yAngle < 0.0 ) {
     yAngle += 360.0;
   } else if ( yAngle > 360.0 ) {
     yAngle -= 360.0;
   }

   Togl_PostRedisplay(togl);

   /* Let result string equal value */
   strcpy( interp->result, argv[2] );
   return TCL_OK;
}

int getXrot_cb( ClientData clientData, Tcl_Interp *interp,
		int argc, char *argv[])
{
  sprintf( interp->result, "%d", (int)xAngle );
  return TCL_OK;
}

int getYrot_cb( ClientData clientData, Tcl_Interp *interp,
		int argc, char *argv[])
{
  sprintf( interp->result, "%d", (int)yAngle );
  return TCL_OK;
}

int scale_cb( struct Togl *togl, int argc, char *argv[] )
{
   Tcl_Interp *interp = Togl_Interp(togl);

   /* error checking */
   if (argc != 3) {
      Tcl_SetResult( interp,
                     "wrong # args: should be \"pathName scale ?value?\"",
                     TCL_STATIC );
      return TCL_ERROR;
   }

   scale = atof( argv[2] );

   Togl_PostRedisplay(togl);

   /* Let result string equal value */
   strcpy( interp->result, argv[2] );
   return TCL_OK;
}

EXPORT(int,Stereo_Init)(Tcl_Interp *interp)
{
   /*
    * Initialize Tcl, Tk, and the Togl widget module.
    */
#ifdef USE_TCL_STUBS
  if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {return TCL_ERROR;}
#endif
#ifdef USE_TK_STUBS
  if (Tk_InitStubs(interp, "8.1", 0) == NULL) {return TCL_ERROR;}
#endif

   if (Togl_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
   }

   /*
    * Specify the C callback functions for widget creation, display,
    * and reshape.
    */
   Togl_CreateFunc( create_cb );
   Togl_DisplayFunc( display_cb );
   Togl_ReshapeFunc( reshape_cb );

   /*
    * Make a new Togl widget command so the Tcl code can set a C variable.
    */
   
   Togl_CreateCommand( "setXrot", setXrot_cb );
   Togl_CreateCommand( "setYrot", setYrot_cb );
   Togl_CreateCommand( "scale", scale_cb );

   /*
    * Call Tcl_CreateCommand for application-specific commands, if
    * they weren't already created by the init procedures called above.
    */
   
   Tcl_CreateCommand( interp, "getXrot", getXrot_cb, (ClientData)NULL,
                                                     (Tcl_CmdDeleteProc *)NULL );
   Tcl_CreateCommand( interp, "getYrot", getYrot_cb, (ClientData)NULL,
                                                     (Tcl_CmdDeleteProc *)NULL );

   return TCL_OK;
}
