/* NIGHTFALL OpenGL Interface                                              */
/* Copyright (C) 2001 Rainer Wichmann & Markus Kuster                      */
/*                                                                         */
/*  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., 675 Mass Ave, Cambridge, MA 02139, USA.              */

/* ANSI C forbids an empty source file, so put this outside                */
/* do nothing here if we don't have OpenGL                                 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "Light.h"

#ifdef  _WITH_OPENGL
#include <setjmp.h>
#include "LightGLPrefs.h"

/* Display lists                                                           */
GLint PrimaryList, SecondaryList, DiskList, PlotList[2];

TextureType Texture[3];

/* Parameters for coordinate systems                                       */
CoordType CoordSys[2];

/* structure keeping all eight spot lights                                 */
LightType Lights[MAX_LIGHT_NUM];
GLfloat lightpos[4];

/* Color is RGBA where A is the alpha channel                              */
/* color and emission properties of the stars                              */
/* primary                                                                 */
GLfloat primary_colour[]          = {0.92, 0.057, 0.0, 1.0 };
GLfloat primary_mat_specular[]    = { 0.0, 0.0  , 0.0, 1.0 };
GLfloat primary_mat_diffuse[]     = { 1.0, 0.60 , 0.0, 1.0 };
GLfloat primary_mat_shininess[]   = { 0.0 };
/* secondary                                                               */
GLfloat secondary_colour[]        = {0.066, 0.6666, 1.0, 1.0 };
GLfloat secondary_mat_specular[]  = { 0.0 , 0.0   , 0.0, 1.0 };
GLfloat secondary_mat_diffuse[]   = { 1.0 , 0.40  , 0.0, 1.0 };
GLfloat secondary_mat_shininess[] = { 0.0 };

#ifdef HAVE_DISK
/* color and emission properties of the disk                               */
GLfloat disk_colour[]             = { 0.6, 0.047, 0.0, 1.0};
GLfloat disk_mat_specular[]       = { 0.0,   0.0, 0.0, 1.0};
GLfloat disk_mat_diffuse[]        = { 1.0,  0.40, 0.0, 1.0};
GLfloat disk_mat_shininess[]      = { 0.0 };
#endif 

/* spot definition for the primary                                         */
GLfloat primary_spot1_direction[] = {0.0, 0.0, -1.0};
GLfloat primary_spot2_direction[] = {0.0, 0.0, -1.0};

/* spot definition for the secondary                                       */
GLfloat secondary_spot1_direction[] = {0.0, 0.0, -1.0};
GLfloat secondary_spot2_direction[] = {0.0, 0.0, -1.0};

/* the background color                                                    */
GLfloat bgd_colour[]              = {0.0,0.0,0.0,1.0};

/* OpenGL window opened                                                    */
int GLWindowOpened = OFF;                 /* OpenGL window opened          */
int GLWindowHidden = OFF;                 /* OpenGL window opened          */
int phaseind=0;

GtkWidget  *glArea = NULL;
GtkWidget  *glPlot = NULL;
GtkWidget  *glVelo = NULL;
GtkWidget  *glWindow = NULL;              /* Scene and plot window         */
static char movfile[256];                 /* file name of the movie files  */

GLvoid *GLDrawFont = GLUT_BITMAP_TIMES_ROMAN_10;

GLuint screen;

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     The main drawing code 
 @param     (GtkWidget)  *widget  discarded
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLDisplayAll( void )
{
  DispInfo *DispInfoPtr;

  DispInfoPtr = (DispInfo*)gtk_object_get_data(GTK_OBJECT(glArea), "DispInfo");

  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      /* clear colour buffer                                               */
      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
      /* define 3d window viewport                                         */
      glViewport(VP_3D_X0, VP_3D_Y0, VP_3D_WIDTH, VP_3D_HEIGHT);
      /* render 3D view                                                    */
      GLDisplay3d(glArea);
      
      /* define light curve viewport                                       */
      glViewport(VP_LC_X0, VP_LC_Y0, VP_LC_WIDTH, VP_LC_HEIGHT);
      /* render light curve                                                */
      GLDisplayPlot(glArea,LIGHTCURVE);
      
      /* define radial velocity viewport                                   */
      glViewport(VP_RV_X0, VP_RV_Y0, VP_RV_WIDTH, VP_RV_HEIGHT);
      /* render radial velocity plot                                       */
      GLDisplayPlot(glArea,RADVELOCITY);

      if (Flags.texture == ON && Flags.textype != IMAGE)
	{ 
	  /* define wedge primary viewport                                 */
	  glViewport(VP_WP_X0, VP_WP_Y0, VP_WP_WIDTH, VP_WP_HEIGHT);
	  GLDisplayWedge( Primary );
	  /* define wedge secondary viewport                               */
	  glViewport(VP_WS_X0, VP_WS_Y0, VP_WS_WIDTH, VP_WS_HEIGHT);
	  GLDisplayWedge( Secondary );
#ifdef HAVE_DISK
	  if (Flags.disk == ON) {
	    /* define wedge disk viewport                                  */
	    glViewport(VP_WD_X0, VP_WD_Y0, VP_WD_WIDTH, VP_WD_HEIGHT);
	    GLDisplayWedge( Disk );
	  }
#endif
	}

      /* finally swap display buffers, we are in DoubleBuffering mode      */
      gtk_gl_area_swap_buffers(GTK_GL_AREA(glArea));
    }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Update all display lists
 @param     (void)  *widget  discarded
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLUpdateAll( void )
{
  /* OpenGL functions can be called only if make_current returns true      */
  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      /* Update display lists for 3D main window                           */
      GLUpdate3d(glArea);
      /* Update top plot window                                            */
      GLUpdatePlot(5,LIGHTCURVE);
      /* Update bottom plot window                                         */
      GLUpdatePlot(6,RADVELOCITY);
    }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Update the primary/secondary geometry
 @param     (GtkWidget) *widget discarded
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLUpdate3d( GtkWidget *widget )
{
  /* OpenGL functions can be called only if make_current returns true      */
  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      if ( PrimaryList ) {
	/* delete the old display list to save memory                      */
	glDeleteLists(PrimaryList,1);
      }
      /* Create the primary list                                           */
      PrimaryList=glGenLists(1);

      glNewList(PrimaryList, GL_COMPILE);
      if (Flags.points == TRUE) {
	GLMakeVolumeEclipsed(Primary);
      } else {
	GLMakeVolumeEclipsed(Primary);
      }
      glEndList();
      
      if ( SecondaryList ) {
	/* delete the old display list to save memory                      */
	glDeleteLists(SecondaryList,1);
      }

      /* Create the secondary list                                         */
      SecondaryList=glGenLists(2);

      glNewList(SecondaryList, GL_COMPILE);
      if (Flags.points == TRUE) {
	GLMakeVolumeEclipsed(Secondary);
      } else {
	GLMakeVolumeEclipsed(Secondary);
      }	
      glEndList();

#ifdef HAVE_DISK
      /* Create the disk display list                                      */
      if ( Flags.disk == ON ) {
	if ( DiskList ) {
	  /* delete the old display list to save memory                    */
	  glDeleteLists(DiskList,1);
	}
	DiskList=glGenLists(3);

	glNewList(DiskList, GL_COMPILE);
	if (Flags.points == TRUE) {
	  GLMakeVolumeEclipsed(Disk);
	} else {
	  GLMakeVolumeEclipsed(Disk);
	}
	glEndList();
      }
#endif 
    }
  return;
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Update a plot viewport
 @param     (int)  viewport number of viewport 
 @param     (int)  type     type of plot (light curve / rad. vel.)
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLUpdatePlot( int viewport, int type )
{
  /* OpenGL functions can be called only if make_current returns true      */
  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      if ( PlotList[type] ) {
	/* delete the old display list to save memory                      */
	glDeleteLists(PlotList[type],1);
      }
      PlotList[type]=glGenLists(viewport);
      glNewList(PlotList[type], GL_COMPILE);

      switch (type) 
	{
	case LIGHTCURVE:
	  GLMakeLCPlot();
	  break;
	case RADVELOCITY:
	  GLMakeRVPlot();
	  break;
	default:
	  break;
	}
      glEndList();
    }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Select font
 @param     (int)    style font name
 @param     (int)    size  font size
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLSetFont(int style, int size)
{
  switch (style) {
    
  case HELVETICA:
    if (size == 12) 
      GLDrawFont = GLUT_BITMAP_HELVETICA_12;
    else if (size == 18)
      GLDrawFont = GLUT_BITMAP_HELVETICA_18;
    break;
    
  case TIMESROMAN:
    GLDrawFont = GLUT_BITMAP_TIMES_ROMAN_10;
    if (size == 24)
      GLDrawFont = GLUT_BITMAP_TIMES_ROMAN_24;
    break;

  default:
    GLDrawFont = GLUT_BITMAP_HELVETICA_10;
    break;
  }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Display given string at position x,y
 @param     (GLint) x      x coordinate
 @param     (GLint) y      y coordinate
 @param     (GLint) z      z coordinate
 @param     (char)  format string to draw
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLDrawStr(GLfloat x, GLfloat y, GLfloat z, char* format, ...)
{
  int string_width;
  float string_off;

  va_list args;
  char buffer[256], *s;
    
  va_start(args, format);
  vsnprintf(buffer, 256, format, args);
  va_end(args);

  string_width = 0;
  for (s = buffer; *s; s++)
    string_width += glutBitmapWidth(GLDrawFont, *s);

  string_off = string_width/2.;

  glRasterPos3f(x, y, z);
  for (s = buffer; *s; s++) {
    glutBitmapCharacter(GLDrawFont, *s);
  }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Draw labels for 3D plot
 @param     (GLfloat) length  length of the axes
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLDrawLabels(GtkWidget *widget)
{
  double RLag1;
  float  com;                         /* center of mass                    */

  /* the x coordinate of the center of mass                                */
  com = (((float)(Binary[Primary].Mq))/( 1.0 + (float)(Binary[Primary].Mq)));

  /* x-coordinate of lagrange point one                                    */
  RLag1 = Binary[Primary].RLag1;

  if (gtk_gl_area_make_current(GTK_GL_AREA(widget)))
    {
      /* disable lighting, we don't want ligthing with                     */
      /* markers                                                           */
      glDisable(GL_LIGHTING);

      /* draw axes with thick lines                                        */
      glLineWidth(2);
      /* select font                                                       */
      GLSetFont(HELVETICA, 12);

      glColor3f(0.0, 0.0, 1.0);
      GLDrawStr(RLag1,0.0,0.6,"L1");

      glColor3f(1.0, 1.0, 1.0);
      GLDrawStr(0.0,0.0,0.7,"Primary");

      glColor3f(1.0, 1.0, 1.0);
      GLDrawStr(0.9,0.0,0.7,"Secondary");

      /* translate to display coordinates with com      
	 at (0,0,0) */
      glBegin(GL_LINES);
      
      /* blue; lagrange point one                                          */
      glColor3f(0.0, 0.0, 1.0);
      glVertex3f(RLag1, 0.0, 0.4);
      glVertex3f(RLag1, 0.0, 0.5);

      /* white; primary                                                    */
      glColor3f(1.0, 1.0, 1.0);
      glVertex3f(0.0, 0.0, 0.5);
      glVertex3f(0.0, 0.0, 0.6);
      
      /* white; secondary                                                  */
      glColor3f(1.0, 1.0, 1.0);
      glVertex3f(1.0, 0.0, 0.5);
      glVertex3f(1.0, 0.0, 0.6);
      
      glEnd();
      
      /* switch on lighing                                                 */
      glEnable(GL_LIGHTING);
      /* set line width back to one                                        */
      glLineWidth(1);
    }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Resize the GL window and update the viewport
 @param     (GtkWidget)          discarded
            (GdkEventConfigure)  event pointer to the event structure
 @return    (gint)      status   the exit status  
 @heading   Open GL Animation
****************************************************************************/
gint GLReshape( GtkWidget *widget, GdkEventConfigure *event )
{
  GLfloat h;
  DispInfo *DispInfoPtr;
  
  DispInfoPtr = (DispInfo*)gtk_object_get_data(GTK_OBJECT(glArea), "DispInfo");
  /* OpenGL functions can be called only if make_current returns true      */
  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      /* get the dimension of the GTK window                               */
      h= (GLfloat) glArea->allocation.height / (GLfloat) glArea->allocation.width;
      
      /* set the glViewport to the full size of                            */
      /* all Viewports                                                     */
      glViewport(0,0, GLAREA_WIDTH, GLAREA_HEIGHT);
      return(TRUE);
    } else {
      return(FALSE);
    }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Motion event handling 
 @param     (GtkWidget)   *widget pointer to the GL area widget
            (GdkEventKey) *event  the motion event
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
gint GLMotionNotify(GtkWidget *widget, GdkEventMotion *event)
{
  int x, y;
  uint BUTTON12_MASK;

  float spin_quat[4];
  GdkRectangle area;
  GdkModifierType state;
  DispInfo *DispInfoPtr;

  DispInfoPtr = (DispInfo*)gtk_object_get_data(GTK_OBJECT(glArea), "DispInfo");

  if (event->is_hint) {
    gdk_window_get_pointer(event->window, &x, &y, &state);
  } else {
    x = event->x;
    y = event->y;
    state = event->state;
  }
  
  area.x = 0;
  area.y = 0;
  area.width  = glArea->allocation.width;
  area.height = glArea->allocation.height;
  
  BUTTON12_MASK = (1 << 8) + (1 << 9);

  if (state & GDK_BUTTON1_MASK) {
    /* drag in progress, simulate trackball                                */
    trackball(spin_quat,
	      (2.0*DispInfoPtr->mousex -              area.width) / area.width,
	      (            area.height - 2.0*DispInfoPtr->mousey) / area.height,
	      (                  2.0*x -              area.width) / area.width,
	      (            area.height -                   2.0*y) / area.height);
    add_quats(spin_quat, DispInfoPtr->quat, DispInfoPtr->quat);
    /* orientation has changed, redraw all                                 */
    gtk_widget_draw(glArea, &area);
  }
  
  if (state & GDK_BUTTON2_MASK) {
    /* zooming drag                                                        */
    DispInfoPtr->zoom += ((y - DispInfoPtr->mousey) / area.height) * 1.0;
    if (DispInfoPtr->zoom < 0.1) DispInfoPtr->zoom = 0.1;
    if (DispInfoPtr->zoom > 20)  DispInfoPtr->zoom = 20;
    /* zoom has changed, redraw mesh                                       */
    gtk_widget_draw(glArea, &area);
  }
  
  if (state & GDK_BUTTON3_MASK) {
    /* left/right drag                                                     */
      DispInfoPtr->xpos += ((x - DispInfoPtr->mousex) / area.height) * 1.0;
      if (DispInfoPtr->xpos < -3.0) DispInfoPtr->xpos = -3.0;
      if (DispInfoPtr->xpos >  3.0) DispInfoPtr->xpos =  3.0;
      gtk_widget_draw(glArea, &area);
  }

  DispInfoPtr->mousex = x;
  DispInfoPtr->mousey = y;

  return(TRUE);
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Mouse event handling 
 @param     (GtkWidget)   *widget pointer to the GL area widget
            (GdkEventKey) *event  the mouse event
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
gint GLButtonPress(GtkWidget *widget, GdkEventButton *event)
{
  DispInfo *DispInfoPtr;

  DispInfoPtr= (DispInfo*)gtk_object_get_data(GTK_OBJECT(widget), "DispInfo");

  if (event->button == 1) {
    /* beginning of drag, reset mouse position                             */
    DispInfoPtr->mousex = event->x;
    DispInfoPtr->mousey = event->y;
    
    return(TRUE);
  }
  
  return(FALSE);
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Grab GL viewport and write as JPEG coded image file
 @param     (char) *filename  the name of the image file 
            (int)  x0         x0 position rel. to glViewport
            (int)  x0         x0 position rel. to glViewport
            (int)  width      width of the area to grab
                      	      0 < width <= GLAREA_WIDTH
            (int)  height     height of the area to grab
                      	      0 < height <= GLAREA_HEIGHT 
	    (int)  quality    the compression factor 
	                      (0 < quality < 100)
 @return    (int)  TRUE if successful else FALSE 
 @heading   Read a GL viewport, compress the image and save it as a
            jpeg-file. This code is based on the example code
            'example.c' included in the jpeg-library libjpeg-6.2.0.
****************************************************************************/
int GLGrabScreen(char *filename, int x0, int y0, 
		 int width, int height, int quality)
{
  JSAMPLE *imgbuff;             /* array of R,G,B - order data for image   */
  int imgwidth, imgheight;      /* width and height of the area to grab    */
  int success;                  /* return status                           */
  char ErrMsg[256];             /* error message                           */ 

#ifdef USING_GTK2
  gdk_drawable_get_size(glWindow->window, &imgwidth, &imgheight);
#else
  gdk_window_get_size(glWindow->window, &imgwidth, &imgheight);
#endif
  
  imgwidth  = width;
  imgheight = height;
 
  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      /* allocate an image storage buffer                                  */
      imgbuff=(unsigned char *)malloc(imgheight*imgwidth*3);
      if (!imgbuff) {
	sprintf(ErrMsg,_("Can't allocate memory for the image buffer\n"));
	WARNING (ErrMsg);
	return(FALSE);
      }
      
      /* grab image from the viewport                                      */
      glReadPixels(x0,y0,imgwidth,imgheight,GL_RGB,GL_UNSIGNED_BYTE,
		   imgbuff);
      
      /* write image to jpeg file                                          */
      success=WriteJPEGFile(imgbuff, filename, imgwidth, imgheight,
			    3, quality);

      if (!success) {
	sprintf(ErrMsg,_("Failed to write mage file !\n"));
	WARNING (ErrMsg);
	return(FALSE);
      }
      /* free memory of the image buffer                                   */
      if (imgbuff) {
	free(imgbuff);
      }
    }
  return(TRUE);
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Init lighting model 
 @param     (GtkWidget) *widget   pointer to the GL area widget
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLInitLighting( GtkWidget *widget )
{
  GLdouble a=2.90;
  GLfloat com;
  GLfloat qa=1.0/a/a;

  /* the x coordinate of the center of mass                                */
  com = (((GLfloat)(Binary[Primary].Mq))/( 1.0 + (GLfloat)(Binary[Primary].Mq)));

  /* set position of lights                                                */
  Lights[SCENE_LIGHT].Pos[0] = 1.0; 
  Lights[SCENE_LIGHT].Pos[1] = 0.0;
  Lights[SCENE_LIGHT].Pos[2] = 0.0;
  Lights[SCENE_LIGHT].Pos[3] = 1.0;

  Lights[DISK_SPOT].Pos[0]   = 1.0;
  Lights[DISK_SPOT].Pos[1]   = 0.0;
  Lights[DISK_SPOT].Pos[2]   = 0.0;
  Lights[DISK_SPOT].Pos[3]   = 1.0;

  Lights[PRIMARY_ONE].Pos[0] = 0.0;
  Lights[PRIMARY_ONE].Pos[1] = 0.0;
  Lights[PRIMARY_ONE].Pos[2] = 0.0;
  Lights[PRIMARY_ONE].Pos[3] = 1.0;

  Lights[PRIMARY_TWO].Pos[0] = 0.0;
  Lights[PRIMARY_TWO].Pos[1] = 0.0;
  Lights[PRIMARY_TWO].Pos[2] = 0.0;
  Lights[PRIMARY_TWO].Pos[3] = 1.0;

  glLightfv(SCENE_LIGHT, GL_DIFFUSE, primary_colour);
  glLightfv(SCENE_LIGHT, GL_SPECULAR, primary_colour);
  glLightf(SCENE_LIGHT, GL_CONSTANT_ATTENUATION, 0.0);
  glLightf(SCENE_LIGHT, GL_LINEAR_ATTENUATION, 0.0);
  glLightf(SCENE_LIGHT, GL_QUADRATIC_ATTENUATION, qa*0.95);
  
  glLightfv(DISK_SPOT, GL_DIFFUSE, primary_colour);
  glLightfv(DISK_SPOT, GL_SPECULAR, primary_colour);
  glLightf(DISK_SPOT, GL_CONSTANT_ATTENUATION, 0.0);
  glLightf(DISK_SPOT, GL_LINEAR_ATTENUATION, 0.0);
  glLightf(DISK_SPOT, GL_QUADRATIC_ATTENUATION, qa*0.95);
  
  glLightfv(PRIMARY_ONE, GL_DIFFUSE, primary_colour);
  glLightfv(PRIMARY_ONE, GL_SPECULAR, primary_colour);
  glLightf(PRIMARY_ONE, GL_CONSTANT_ATTENUATION, 0.0);
  glLightf(PRIMARY_ONE, GL_LINEAR_ATTENUATION, 0.0);
  glLightf(PRIMARY_ONE, GL_QUADRATIC_ATTENUATION, qa);
  
  glEnable(GL_LIGHTING);
  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   0.1
 @short     Visualize spots
 @param     (int)       Comp      The stellar component
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLMakeSpots( int Comp, float xpos )
{
  int    nspot;                              /* index of current spot      */
  int    N_Spot = 0;                         /* # of spots on star         */
  /*long   i; */                             /* loop counter               */
  /*double LatS;  */                         /* spot latitude              */
  /*double LongS;*/                          /* spot longitude             */
  /*double RadSpot;*/                        /* spot radius                */

  if (Comp == Primary) {
    xpos   = 0.0;
    N_Spot = Flags.Spots1;
  } 
  else if (Comp == Secondary) {
    xpos   = 1.0;
    N_Spot = Flags.Spots2;
  }

  /* show only the first two spots per component in GL animation, which are*/
  /* the spots defined in the GUI                                          */  
  if (N_Spot > 1) {
    N_Spot = 1;
  }

  lightpos[0]=xpos;
  lightpos[1]=0.0;
  lightpos[2]=0.0;
  lightpos[3]=1.0;

  /* set spot position                                                     */
  if (Comp == Primary) {
    glLightfv(PRIMARY_ONE, GL_POSITION, lightpos);
    glLightfv(PRIMARY_TWO, GL_POSITION, lightpos);
  } else {
    glLightfv(SECONDARY_ONE, GL_POSITION, lightpos);
    glLightfv(SECONDARY_TWO, GL_POSITION, lightpos);
  }

  /* ----------------- loop over spots ----------------------------------  */

  for (nspot = 0; nspot < N_Spot; ++nspot) {
    /* latitude of the spot in radians                                     */
    /*LatS     = DTOR * Spot[Comp][nspot].latitude;
      LongS    = DTOR * Spot[Comp][nspot].longitude;*/

    /* Must be != NULL, else spot is incorrectly placed
     */
    /*LatS     = ( fabs(LatS) >= DBL_EPSILON) ? LatS : DBL_EPSILON;
      LongS    = ( fabs(LongS) >= DBL_EPSILON) ? LongS : DBL_EPSILON;*/

    /* -------------  spot size      ------------------------------------- */
    /* RadSpot  = DTOR * Spot[Comp][nspot].radius;*/
    
    
    /* set spot direction                                                  */
    /*    glLightfv(DISK_SPOT, GL_SPOT_DIRECTION, primary_spot1_direction);
	  glLightfv(PRIMARY_ONE, GL_SPOT_DIRECTION, primary_spot2_direction);*/

  }
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Init geometry display
 @param     (GtkWidget) *widget   discarded
 @return    (gint)      status    the exit status 
 @heading   Open GL Animation
****************************************************************************/
gint GLInit3d(GtkWidget *widget )
{
  SurfaceElement  *SurfPtr;        /* pointer to surface elements          */
  
  SurfPtr=Surface[Primary];
  
  /* OpenGL functions can be called only if make_current                   */
  /* returns true                                                          */
  if (gtk_gl_area_make_current(GTK_GL_AREA(glArea)))
    {
      /* set background color to black                                     */
      glClearColor (bgd_colour[0], bgd_colour[1], bgd_colour[2], bgd_colour[3]);
    
      /* glEnable(GL_DITHER); */
      /* use smooth Gouraud shading                                        */
      glShadeModel (GL_SMOOTH);

      glEnable(GL_CULL_FACE);
      glFrontFace(GL_CCW);

      /*glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
	glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);*/

      /* enable hidden line removal                                        */
      glEnable(GL_DEPTH_TEST);
      glDepthFunc(GL_LESS);

      /* activate depth mask                                               */
      glDepthMask(GL_TRUE);

      /* clear colour buffer and depth buffer                              */
      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      /* set draw color to white                                           */
      glColor3f (1.0, 1.0, 1.0);

      /* define lights                                                     */
      GLInitLighting(glArea);

      /* Initialize texturing                                              */
      GLInitTextureParams(Primary);
      if (GLInitTexture(Primary, Flags.textype)) {
	Texture[Primary].IsOn   = ON;
      }  else {
	Texture[Primary].IsOn   = OFF;
      }

      GLInitTextureParams(Secondary);
      if (GLInitTexture(Secondary, Flags.textype)) {
	Texture[Secondary].IsOn = ON;
      } else {
	Texture[Secondary].IsOn = OFF;
      }

#ifdef HAVE_DISK
      /* texture for disk has to be initialzed in any case                 */
      GLInitTextureParams(Disk);
      if (GLInitTexture(Disk, Flags.textype)) { // CORRECT?
	Texture[Disk].IsOn = ON;
      } else {
	Texture[Disk].IsOn = OFF;
      }
#endif 

      /* switch on the lights                                              */
      /*glEnable(SCENE_LIGHT);*/
      /*glEnable(DISK_SPOT);*/
      /*glEnable(PRIMARY_ONE);*/

      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

      GLUpdateAll();
      return(TRUE);
    } else {
      return(FALSE);
    }
}

/****************************************************************************
 @package   nightfall
 @author    Rainer Wichmann (rwichman@lsw.uni-heidelberg.de)
 @version   1.0
 @short     Callback function for GLWindow delete
 @param     (GtkWidget) *widget     Discarded
 @param     (gpointer)  *data       Discarded
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void GLDelete (GtkWidget *widget, gpointer *data)
{
  if (GLPrefWinOpened == TRUE) {
    if (glPrefsWindow != NULL)
      gtk_widget_destroy (glPrefsWindow);
    glPrefsWindow = NULL;
    GLPrefWinOpened = OFF;
  }

  gtk_widget_hide (glWindow);
  GLWindowHidden = ON;
  /*
  if (glArea != NULL)
    gtk_widget_destroy (glArea);
  glArea = NULL;
  if (glWindow != NULL)
    gtk_widget_destroy (glWindow);
  glWindow = NULL;
  GLWindowOpened = OFF;
  */
  return;
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Init texture parameters
 @param     (int)       Comp      The stellar component
 @return    (int)       status    The exit status 
 @heading   Open GL Animation
****************************************************************************/
int GLInitTextureParams(int Comp)
{
  TextureType *TexPtr=NULL;               /* Pointer to texture            */
  char  texture_file[MAX_CFG_INLINE+1] = "\0";        /* Texture image file            */
  FILE        *txtFile;
  int          len;

  TexPtr=&Texture[Comp];
  
  strncpy(texture_file, data_pix_fls(), sizeof(texture_file)-1);
  texture_file[sizeof(texture_file)-1] = '\0';
  len = strlen(texture_file);

  /* set default values (filenames should be stored in preferences TBD MK) */
  if ( Comp == Primary) {
    strncat(texture_file, "/starp_256.jpg", sizeof(texture_file) - len -1);
  } else if ( Comp == Secondary ) {
    strncat(texture_file, "/stars_256.jpg", sizeof(texture_file) - len -1);
  }
#ifdef HAVE_DISK
  else {
    strncat(texture_file, "/disk_256.jpg", sizeof(texture_file) - len -1);
  }    
#endif 
  /* not found in default directory -> try local directory                  */
  if ((txtFile = fopen (texture_file, "r")) == NULL) {
    texture_file[0]='.';
    texture_file[1]='\0';

    strcat(texture_file, "/pixmaps");
    
    if ( Comp == Primary) {
      strcat(texture_file, "/starp_256.jpg");
    } else if ( Comp == Secondary ) {
      strcat(texture_file, "/stars_256.jpg");
    }
#ifdef HAVE_DISK
    else {
      strcat(texture_file, "/disk_256.jpg");
    }   
#endif
  } else {
    fclose(txtFile);
  }
  strncpy(TexPtr->TextFile, texture_file, 
	  strlen(texture_file) + 1);
  TexPtr->TextFile[MAX_CFG_INLINE] = '\0';

  /* Set Texture type to default = IMAGE                                   */
  TexPtr->Type = IMAGE;

  return(TRUE);
}

double maxtemp(SurfaceElement *surface, double num) {
  double maxvalue=0;
  SurfaceElement *ptr;
  double i; 

  ptr=surface;
  for (i=0;i<num;i++) {
    if (ptr->temp > maxvalue) maxvalue = ptr->temp;
    ptr++;
  } 
  return(maxvalue);
}

double mintemp(SurfaceElement *surface, double num) {
  double minvalue = 3.0e+38;
  SurfaceElement *ptr;
  double i; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    if (ptr->temp < minvalue) minvalue = ptr->temp;
    ptr++;
  } 
  return(minvalue);
}

double maxgrav(SurfaceElement *surface, double num) {
  double maxvalue=0;
  SurfaceElement *ptr;
  double i; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    if (ptr->grav > maxvalue) maxvalue = ptr->grav;
    ptr++;
  } 
  return(maxvalue);
}

double mingrav(SurfaceElement *surface, double num) {
  double minvalue =  3.0e+38;
  SurfaceElement *ptr;
  double i; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    if (ptr->grav < minvalue) minvalue = ptr->grav;
    ptr++;
  } 
  return(minvalue);
}

double maxflux(SurfaceElement *surface, double num, int Comp) {
  double maxvalue=0;
  SurfaceElement *ptr;
  double i, flux; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    flux = (ptr->f_[0]/ ptr->area)
      /* * ptr->visibility */ 
      /* * (1.0 - Limb[Comp][0][0] * (1.0 - ptr->CosGamma)) */ 
      ;
    if (flux > maxvalue) 
      maxvalue = flux;
    ptr++;
  } 
  return(maxvalue);
}
double minflux(SurfaceElement *surface, double num, int Comp) {
  double minvalue = 3.0e38;
  SurfaceElement *ptr;
  double i, flux; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    flux = (ptr->f_[0]/ ptr->area) 
      /* * ptr->visibility */
      * fabs(1.0 - Limb[Comp][0][0] /* * (1.0 - ptr->CosGamma) */);
    if (flux < minvalue) {
      minvalue = flux;
    }
    ptr++;
  }
  minvalue = minvalue * 0.9;
  return(minvalue);
}

double maxvel(SurfaceElement *surface, double num) {
  double maxvalue=0;
  SurfaceElement *ptr;
  double i; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    if (ptr->CosGamma > 0) {
      if (ptr->Velocity > maxvalue) 
	maxvalue = ptr->Velocity;
    }
    ptr++;
  } 
  return(maxvalue);
}
double minvel(SurfaceElement *surface, double num) {
  double minvalue = 3.0e38;
  SurfaceElement *ptr;
  double i; 
  
  ptr=surface;
  for (i=0;i<num;i++) {
    if (ptr->CosGamma > 0) {
      if (ptr->Velocity < minvalue) 
	minvalue = ptr->Velocity;
    }
    ptr++;
  } 
  return(minvalue);
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   0.5
 @short     Generate a texture image from binary data, e.g. temperature 
            distribution
 @param     (SurfaceElement *) SurfPtr The data of the stellar component
 @param     (GLubyte *) textimage Pointer to the texture image
 @param     (int)       datatype  The type of the texture (LINEAR, COLORMODEL,
                                  ...)
 @heading   Open GL Animation
****************************************************************************/
void GLDatatoTexture(SurfaceElement *SurfPtr, GLubyte *textimage,
		     double num, int datatype, int Comp)
{
  GLubyte        *imgptr=NULL;
  int            intensity;
  SurfaceElement *ptr;
  double         i, minval=3.0e+38,maxval=0x0, tscale, flux;

#if 0
  double         bscale;
  double         x=0,y=0,z=0;
  double         R=0,G=0,B=0;
  struct GLColorSystem NTSC = {0.64, 0.33, 0.29, 0.60, 0.15, 0.06, CWP}; 
  struct GLColorSystem *cs; 
#endif
  char * name;

  if (Comp == Primary)
    name = _("Primary");
  else if (Comp == Secondary)
    name = _("Secondary");
  else
    name = _("Disk");

  /* pointer to the texture image memory                                   */
  imgptr = textimage;
  
  switch (datatype) {
  case TEMP:

    minval = mintemp(SurfPtr, num);
    maxval = maxtemp(SurfPtr, num);

    /* linear scaling factor                                                 */
    tscale = 256 / (maxval-minval); 

    if (Flags.debug[VERBOSE] == ON) {
      printf(_("%s: Minimum temperature %8.1f Kelvin\n"), name, minval);
      printf(_("%s: Maximum temperature %8.1f Kelvin\n"), name, maxval); 
    }
    
    /* init linear grey-scale LUT                                            */
    ptr    = SurfPtr;
    for (i=0; i < num; i++) {
      intensity = (ptr->temp-minval)*tscale;
      /* assign R-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      /* assign G-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      /* assign B-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      ptr++;
    }
    break;
  case GRAV:

    minval = mingrav(SurfPtr, num);
    maxval = maxgrav(SurfPtr, num);

    /* linear scaling factor                                                 */
    tscale = 256 / (maxval-minval); 

    if (Flags.debug[VERBOSE] == ON) {
      printf(_("%s: Minimum surface gravitation %8.4g\n"), name, minval);
      printf(_("%s: Maximum surface gravitation %8.4g\n"), name, maxval); 
    }
    
    /* init linear grey-scale LUT                                            */
    ptr    = SurfPtr;
    for (i=0; i < num; i++) {
      intensity = (ptr->grav-minval)*tscale;
      /* assign R-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      /* assign G-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      /* assign B-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      ptr++;
    }
    break;
  case FLUX:

    maxval = log(maxflux(SurfPtr, num, Comp));
    minval = log(minflux(SurfPtr, num, Comp));

    /* linear scaling factor                                                 */
    tscale = 256 / (maxval-minval); 

    if (Flags.debug[VERBOSE] == ON) {
      printf(_("%s: Minimum flux %8.4g\n"), name, minval);
      printf(_("%s: Maximum flux %8.4g\n"), name, maxval); 
    }
    
    /* init linear grey-scale LUT                                            */
    ptr    = SurfPtr;
    for (i=0; i < num; i++) {

      if (ptr->CosGamma > 0) {
	flux = (ptr->f_[0]/ ptr->area) * ptr->visibility * 
	  (1.0 - Limb[Comp][0][0]*(1.0 - ptr->CosGamma));
	flux = (flux < minval) ? minval : flux;
      } else {
	flux = minval;
      }

      flux = log(flux);
      intensity = (flux-minval)*tscale;
      if      (intensity > 255) intensity = 255;
      else if (intensity <   0) intensity =   0;

      /* assign R-value                                                     */
      *imgptr = (GLubyte) intensity;
      imgptr++;
      /* assign G-value                                                     */
      *imgptr = (GLubyte) intensity;
      imgptr++;
      /* assign B-value                                                     */
      *imgptr = (GLubyte) intensity;
      imgptr++;
      ptr++;
    }
    break;
  case VELOCITY:

    minval = minvel(SurfPtr, num);
    maxval = maxvel(SurfPtr, num);

    /* linear scaling factor                                                 */
    tscale = 255 / (maxval-minval); 

    if (Flags.debug[VERBOSE] == ON) {
      printf(_("%s: Minimum velocity %8.4g\n"), name, minval);
      printf(_("%s: Maximum velocity %8.4g\n"), name, maxval); 
    }
    
    /* init linear grey-scale LUT                                            */
    ptr    = SurfPtr;
    for (i=0; i < num; i++) {
      if (ptr->CosGamma > 0) {
	flux = ptr->Velocity;
      } else {
	flux = minval;
      }
      intensity = (flux-minval)*tscale;
      /* assign R-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      /* assign G-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      /* assign B-value                                                     */
      *imgptr = (GLubyte) (intensity);
      imgptr++;
      ptr++;
    }
    break;
#if 0
  case BBCOLOR:
    ptr    = SurfPtr;
    cs     = &NTSC;
    for (i=0; i < num; i++) {
      GLBBtoxyz(ptr->temp,&x,&y,&z);
      //if (i == 0) printf("Temp %f: x %f y %f z %f  \n",ptr->temp,x,y,z);
      GLxyztoRGB(cs,x,y,z,&R,&G,&B);
      //if (i == 0) printf("         R %f G %f B %f  \n",R,G,B);
      
      /* scale R,G,B to byte size                                           */
      
      R = R * 255; 
      B = B * 255; 
      G = G * 255;
      
      /* scale brightness to maximum   R.W. 23.12.2002                      */

      bscale = (B > R) ? B : R;
      bscale = (G > bscale) ? G : bscale;

      R = (255 / bscale) * R;
      B = (255 / bscale) * B;
      G = (255 / bscale) * G;
      
      /* assign R-value                                                     */
      *imgptr = (GLubyte) R;
      imgptr++;
      /* assign G-value                                                     */
      *imgptr = (GLubyte) G;
      imgptr++;
      /* assign B-value                                                     */
      *imgptr = (GLubyte) B;

      imgptr++;
      ptr++;
    }

    break;
#endif
  default:
    break;
  }

  /* save to global variables                                              */
  texture_minval[Comp] = minval;
  texture_maxval[Comp] = maxval;

  return;
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.1
 @short     Init texture images for the stars and the disk
 @param     (int)       Comp      The stellar component
 @param     (int)       type      The type of the texture (IMAGE, TEMP, ...)
 @return    (gint)      status    The exit status
 @heading   Open GL Animation
****************************************************************************/
int GLInitTexture(int Comp, int type)
{
  GLubyte         *textimage=NULL;
  TextureType     *TexPtr=NULL;
  SurfaceElement  *SurfPtr;        /* pointer to surface elements          */
  BinaryComponent *BinPtr;         /* pointer to binary                    */
  
  double          numpoints;
  long            n_phi;           /* # of steps in phi                    */
  long            n_eta;           /* # of steps in eta                    */
  char            ErrMsg[4096];    /* error message                        */  
  
  /* pointer to the texture image of the component                         */
  TexPtr  = &Texture[Comp];
  /* pointer to first surface element                                      */
  SurfPtr = Surface[Comp];
  /* pointer to the binary parameters                                      */
  BinPtr  = &Binary[Comp];
  
  n_eta   = StepsPerPi;
  n_phi   = BinPtr->N_PhiStep[0];
  
  /* be sure that texture does not already exist                           */
  /* sould be done more carefully !!! TBD MK                               */
  glDeleteTextures( 1, &TexPtr->TexName);
  
  /* create a new texture for this component                               */
  glGenTextures( 1, &TexPtr->TexName);
  
  switch (type) {
  case IMAGE: 
    /* use a jpeg coded image file as texture                              */
    /* read the texture image from file                                    */
    textimage = ReadJPEGFile(TexPtr->TextFile, &TexPtr->Width, &TexPtr->Height,
			     &TexPtr->Components);
    
    /* on error switch off texture for this component and return to caller */
    if(!textimage) {
      sprintf(ErrMsg,_("Could not read texture file %s "), TexPtr->TextFile);
      WARNING (ErrMsg);
      sprintf(ErrMsg,_("Texturing not enabled for component %d\n"),Comp);
      WARNING (ErrMsg);
      TexPtr->Type = NONE;
      return(FALSE);
    }
    else {
      if (Flags.debug[VERBOSE] == ON) {  
	printf(_("Reading Texture: %s: %d x %d  %d component \n"),
	       TexPtr->TextFile,TexPtr->Width,
	       TexPtr->Height,TexPtr->Components);
      }
      TexPtr->Type = IMAGE;
    }
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    break;
    
  case TEMP:
  case GRAV: 
  case FLUX:
  case VELOCITY:
    /* build a texture image from physical data                           */
    /* allocate memory for texture image                                  */
    if (Comp < Disk)
      numpoints = n_eta * n_phi;
    else
      numpoints = BinPtr->NumElem;

    textimage = (GLubyte *) malloc(numpoints * TEXTURE_COMPONENTS);
    
    if (!textimage) {
      sprintf(ErrMsg,_("Can't allocate memory for texture image buffer !\n"));
      WARNING (ErrMsg);
      return(FALSE);
    }
    
    GLDatatoTexture(SurfPtr, textimage, numpoints, type, Comp);
    /*
    TexPtr->Width      = n_eta;
    TexPtr->Height     = n_phi;
    */
    /* exchange width and height R.W. 23.12.2002  */
    TexPtr->Width      = n_phi;
    if (Comp < Disk)
      TexPtr->Height     = n_eta;
    else
      TexPtr->Height     = numpoints / n_phi;
    TexPtr->Components = TEXTURE_COMPONENTS;
    break;
    
  default:
    /* we failed to initialize texturing -> turn off texture              */ 
    TexPtr->Type = NONE;
    return(FALSE);
    break; 
  }
  
  glBindTexture(GL_TEXTURE_2D, TexPtr->TexName);
  
  /* repetitively wrap texture on object                                 */
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  
  /* modulate colour of component with texture colour                    */
  if (Flags.textype != BBCOLOR)
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  
  /* replace colour of component with texture colour                     */
  else
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);           
  
  /* apply a linear approximation for texturing                          */
  /* GL_LINEAR is bad, produces a stripe                                 */
  //    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  //    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
  
  /* build texture map                                                   */
  gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, TexPtr->Width, 
		    TexPtr->Height, GL_RGB, GL_UNSIGNED_BYTE, 
		    textimage);
  free(textimage);
  
  return(TRUE);
}

/****************************************************************************
 @package   nightfall
 @author    Markus Kuster (kuster@astro.uni-tuebingen.de)
 @version   1.0
 @short     Real-time animation of the binary system
 @param     (int)  j  The phase index
 @return    (void)   
 @heading   Open GL Animation
****************************************************************************/
void AnimateGL(int j)
{
  char        top_title[MAX_CFG_INLINE+1];    /* window title string       */
  GtkWidget   *GLvbox,*GLhbox,*GLLightvbox;
  GtkWidget   *GLmenu_bar;
  GtkWidget   *GL3dFrame;
  DispInfo    *DispInfoPtr;
  static int  noentry = 0;
  static int  glut_initialized = 0;

  int attrlist[] = {
    GDK_GL_RGBA,
    GDK_GL_DEPTH_SIZE, 1,
    GDK_GL_RED_SIZE,   1,
    GDK_GL_GREEN_SIZE, 1,
    GDK_GL_BLUE_SIZE,  1, 
    GDK_GL_DOUBLEBUFFER,
    GDK_GL_NONE
  };

  int     argc = 1;
  char  * argv = "nightfall";

  if (noentry == 1)
    return;

  if (!glut_initialized)
    {
      glutInit(&argc, &argv);
      glut_initialized = 1;
    }

  phaseind = j;

  if (GLWindowHidden == ON) {
    gtk_widget_show (glWindow);
    GLWindowHidden = OFF;
  }

  if (GLWindowOpened == OFF) {
    /* >>>>>>>>>>>  Initialize Window  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
    if (Flags.debug[VERBOSE] == ON) {  
      { printf("\n");   printf(_("\n Initializing GLX Animation\n\n") );}
    }

    /* create new toplevel window                                          */
    glWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);

    /* set window title                                                    */
    sprintf(top_title, "%10s %5s", PACKAGE, VERSION);
    gtk_window_set_title(GTK_WINDOW(glWindow), top_title);

    /* set window size                                                     */
    gtk_widget_set_usize (glWindow, GLWIN_WIDTH, GLWIN_HEIGHT);    
    gtk_widget_realize(glWindow);
    gtk_quit_add_destroy(1, GTK_OBJECT(glWindow));

    /* ----------- connect the exit handler ------------------------------ */

    gtk_signal_connect (GTK_OBJECT (glWindow), "delete_event",
			GTK_SIGNAL_FUNC (GLDelete), NULL);

    gtk_widget_show(GTK_WIDGET(glWindow));

    /* new vertical box for menu and GLArea                                */
    GLvbox = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (glWindow), GLvbox);
    gtk_widget_show(GLvbox); 
    
    /* >>>>>>>>>>>  the menu bar  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
    GLmenu_bar = gtk_menu_bar_new(); 
    GLMakeMenu(GLmenu_bar);
    gtk_box_pack_start (GTK_BOX (GLvbox), GLmenu_bar, FALSE, FALSE, 0);

    /* new horizontal box for scene and plot area                          */
    GLhbox = gtk_hbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (GLvbox), GLhbox);
    gtk_widget_show(GLhbox);
    
    /* ---------------- 3D System Window --------------------------------- */
    /* frame for 3d scene                                                  */
    GL3dFrame = gtk_frame_new (_("Binary System") );
    gtk_container_add (GTK_CONTAINER (GLhbox), GL3dFrame);
    gtk_container_set_border_width(GTK_CONTAINER(GL3dFrame), 2);
    gtk_widget_show (GL3dFrame);
    
    /* create new OpenGL scene area                                        */

    glArea = gtk_gl_area_new(attrlist);
    if (NULL == glArea) 
      {
	char command[256];

	noentry = 1;
	if (0 == system("which xmessage > /dev/null")) 
	  {
	    sprintf(command,
		    _("xmessage  \"ERROR: OpenGL not working\" "));
	    system(command);
	  }
	GLDelete(NULL, NULL);
	return;
      }
    gtk_widget_show(glArea);


    /* set event mask for widget                                           */
    gtk_widget_set_events(glArea,
			  GDK_EXPOSURE_MASK|
			  GDK_BUTTON_PRESS_MASK|
			  GDK_BUTTON_RELEASE_MASK|
			  GDK_KEY_PRESS_MASK|
			  GDK_KEY_RELEASE_MASK|
			  GDK_POINTER_MOTION_MASK|
			  GDK_POINTER_MOTION_HINT_MASK);

    gtk_gl_area_size(GTK_GL_AREA(glArea), GLAREA_WIDTH, GLAREA_HEIGHT);

    /* do initialization when widget has been realized                     */
    gtk_signal_connect(GTK_OBJECT(glArea), "realize",
		       GTK_SIGNAL_FUNC(GLInit3d), NULL);
 
    gtk_signal_connect(GTK_OBJECT(glArea), "button_press_event",
		       GTK_SIGNAL_FUNC(GLButtonPress), NULL);
     
    /* redraw image when exposed                                           */
    gtk_signal_connect(GTK_OBJECT(glArea), "expose_event",
    		       GTK_SIGNAL_FUNC(GLDisplayAll), NULL);

    /* rotate and translate objects on mouse movement                      */
    gtk_signal_connect (GTK_OBJECT(glArea), "motion_notify_event",
			GTK_SIGNAL_FUNC(GLMotionNotify), NULL);

    /* capture keypress events                                             */
    gtk_signal_connect(GTK_OBJECT(glArea), "key_press_event", 
		       GTK_SIGNAL_FUNC(GLKeyboard), NULL);

    /* when window is resized viewport needs to be resized, too            */
    gtk_signal_connect(GTK_OBJECT(glArea), "configure_event",
		       GTK_SIGNAL_FUNC(GLReshape), NULL);

    /* initialize display info structure                                   */
    DispInfoPtr = (DispInfo*)g_malloc(sizeof(DispInfo));
    DispInfoPtr->mousex = 0;
    DispInfoPtr->mousey = 0;
    DispInfoPtr->xpos   = 0;
    DispInfoPtr->zoom   = 1.;

    /* init trackball                                                      */
    trackball(DispInfoPtr->quat , 0.0, 0.0, 0.0, 0.0);

    /* Add DispInfo to glArea object                                       */
    gtk_object_set_data(GTK_OBJECT(glArea), "DispInfo", DispInfoPtr);

    /* add glArea to frame
     */
    gtk_container_add (GTK_CONTAINER(GL3dFrame), glArea);

    /* set event mask for widget                                           */
    /* enable focus for glarea widget                                      */
    GTK_WIDGET_SET_FLAGS(glArea, GTK_CAN_FOCUS);
    gtk_widget_grab_focus(glArea);

    /* ------------------------------------------------------------------- */


    /* new vertical box for lightcurve and radial vel. plot                */
    GLLightvbox = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (GLhbox), GLLightvbox);
    gtk_widget_show(GLLightvbox);

    glutInitDisplayMode(GLUT_DEPTH);

    /* Render all Viewports                                                */
    GLDisplayAll();

    /* Set window status to open                                           */
    GLWindowOpened = ON;
  } 
  else 
    {
    /* update all geometries                                               */
    GLUpdateAll();
    /* update texture if active and new animation run R.W. 23.12.2002      */
    if (j == 0 && Flags.texture == ON && Flags.textype != IMAGE)
      {
	GLInitTexture(Primary, Flags.textype);
	GLInitTexture(Secondary, Flags.textype);
#ifdef HAVE_DISK
	GLInitTexture(Disk, Flags.textype);
#endif
      }
    else if (Flags.texture == ON && 
	     (Flags.textype == FLUX || Flags.textype == VELOCITY))
      {
	GLInitTexture(Primary, Flags.textype);
	GLInitTexture(Secondary, Flags.textype);
#ifdef HAVE_DISK
	GLInitTexture(Disk, Flags.textype);
#endif
      }
    /* Render all Viewports                                                */
    GLDisplayAll();
  }

  /* write animation frames                                                */
  if (Flags.movie == ON) {
    strcpy(movfile,"");
    sprintf(movfile,"frame%.3d.jpg",Flags.frame);
    /* grab 3D Viewport only and save as max. quality jpeg file            */
    GLGrabScreen(movfile,0,0,VP_3D_WIDTH,VP_3D_HEIGHT,100);
    /* increase frame number                                               */
    Flags.frame++;
  }

  return;
}

#endif /* OpenGL end */





syntax highlighted by Code2HTML, v. 0.9.1