/* 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 #include #include #include #include #include "Light.h" #ifdef _WITH_OPENGL #include #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;itemp > 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;itemp < 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;igrav > 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;igrav < 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;if_[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;if_[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;iCosGamma > 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;iCosGamma > 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 */