| 1 | /* | 
| 2 | *  darwinView | 
| 3 | *  Written by Marissa Weichman June-July 2007 | 
| 4 | *  Contact: mweichman@gmail.com | 
| 5 | * | 
| 6 | *  See the darwinView Guide for instructions on using this program. | 
| 7 | * | 
| 8 | *  The program begins running at main(), at the bottom of this file. The function | 
| 9 | *  readjet() reads in the rgb for the color scale, while readnames() fills the array | 
| 10 | *  fns[][][] with the appropriate filenames to read data from. The functions that | 
| 11 | *  do the reading in are readxy(), readxz() and readyz() depending upon which plane | 
| 12 | *  is being viewed (xy, xz and yz, respectively). The functions global() and local() | 
| 13 | *  calculate the global and local maximum and minimum of the data sets. The key() | 
| 14 | *  and specialkey() functions handle keyboard input from the user. Everytime a key | 
| 15 | *  push changes any information, the display() function is called, which redisplays | 
| 16 | *  the plots with the new values. Finally, TimerFunction() is called when the | 
| 17 | *  autoplay feature is set, and an arrow key is pushed. TimerFunction() calls itself | 
| 18 | *  recursively, and redisplays every 10th of a second as it scrolls through time, | 
| 19 | *  depth levels, etc. | 
| 20 | */ | 
| 21 |  | 
| 22 | #include <GL/glut.h> | 
| 23 | #include <stdlib.h> | 
| 24 | #include <stdio.h> | 
| 25 | #include <string.h> | 
| 26 | #include <math.h> | 
| 27 | #define WINDOW "image" | 
| 28 | #define UP 101 | 
| 29 | #define DOWN 103 | 
| 30 | #define RIGHT 102 | 
| 31 | #define LEFT 100 | 
| 32 | #define MAX 100 | 
| 33 | #define SCALE .06 | 
| 34 |  | 
| 35 | int NX, NY, NZ; | 
| 36 |  | 
| 37 | void do_byteswap_f32( float arr[], int nel ), global(), local( int, int, int ); | 
| 38 | void TimerFunction( int ), stroke( char[], int, int ); | 
| 39 | void readxy( float[], char[], int), readxz( float[], char[] ), readyz( float[], char[] ); | 
| 40 | void readnames( char[] ), readjet(), readdepths( char[] ); | 
| 41 |  | 
| 42 | float data[MAX][MAX*MAX], mxval, mnval, jet[64][3], globalmx=0, globalmn=100; | 
| 43 | int glo=0, usr=0, anim=0, endian=1, logscale=0, xz=0, yz=0, nonegs=1, scaledepth=0; | 
| 44 | int win[MAX], depths[MAX], ilev=1, howmany, sets, count=0, xmax, ymax, yoffset=0, xoffset=0; | 
| 45 | int totaldepth=0, scalecount=0; | 
| 46 | char initfns[MAX][MAX], fns[MAX][MAX][MAX]; | 
| 47 |  | 
| 48 | void menu( int value ){         // called when menu is opened on right click | 
| 49 |  | 
| 50 | switch( value ){ | 
| 51 | case 1: usr=glo=0;            // unset glo & usr, sets local max/min | 
| 52 | break; | 
| 53 | case 2: glo=1;                // enables global max/min | 
| 54 | usr=0;                // unsets usr | 
| 55 | mxval=globalmx;       // sets max to globalmx | 
| 56 | mnval=globalmn;       // sets min to globalmn | 
| 57 | break; | 
| 58 | case 3: usr=1;                // switch to user-set max/min | 
| 59 | glo=0;                // unset glo | 
| 60 | printf( "Max = " );  scanf( "%f", &mxval );  // prompt user for new max | 
| 61 | printf( "Min = " );  scanf( "%f", &mnval );  // prompt user for new min | 
| 62 | break; | 
| 63 | case 4: logscale=( logscale+1 )%2;  // toggle log scale | 
| 64 | break; | 
| 65 | case 5: nonegs=( nonegs+1 )%2;      // toggle allowance of negatives | 
| 66 | break; | 
| 67 | case 6: endian=( endian+1 )%2;      // toggle big/little endian | 
| 68 | break; | 
| 69 | } | 
| 70 | glutPostRedisplay();                 // redisplay with new values | 
| 71 | } | 
| 72 |  | 
| 73 | void display(){                       // called on glutPostRedisplay | 
| 74 | int i, h, ioff, q; | 
| 75 | float r, g, b, k, y, j, tmp; | 
| 76 | double num, logmx, logmn; | 
| 77 | char str[MAX]; | 
| 78 |  | 
| 79 |  | 
| 80 | for( q=0; q<sets; q++ ){             // runs display func for each subwindow | 
| 81 | glutSetWindow( win[q] );            // sets which subwindow to display to | 
| 82 | glClear( GL_COLOR_BUFFER_BIT );     // background to black | 
| 83 |  | 
| 84 | if( xz ) {  xmax=NX;  ymax=NZ;  }   // if in xz view, set y-axis to depth | 
| 85 | else{ | 
| 86 | if( yz ){  xmax=NY;  ymax=NZ;  }   // if in yz view, set x-axis to y, y-axis to depth | 
| 87 | else    {  xmax=NX;  ymax=NY;  }   // otherwise, x-axis = x, y-axis = y | 
| 88 | } | 
| 89 |  | 
| 90 | if( glo || usr ){                   // if global or user-set max/min | 
| 91 | if( xz )                           // if in xz view | 
| 92 | readxz( data[q], fns[q][count] ); // read new xz values w/o calculcating local max/min | 
| 93 | else{ | 
| 94 | if( yz )                          // if in yz view | 
| 95 | readyz( data[q], fns[q][count] );// read new yz values w/o calculating local max/min | 
| 96 | else                                         // if in xy view | 
| 97 | readxy( data[q], fns[q][count], ilev );  // read new xy values w/o calculating local max/min | 
| 98 | } | 
| 99 | } | 
| 100 | else                              // if local max/min is set | 
| 101 | local( q, count, ilev );         // read new array and calculate local max/min | 
| 102 |  | 
| 103 | if( logscale ){                   // if log scale is set | 
| 104 | if( usr ){                       // and values are user-set | 
| 105 | logmx=(double)mxval;            // assume the log has already been taken of max/min | 
| 106 | logmn=(double)mnval; | 
| 107 | } | 
| 108 | else{                            // otherwise | 
| 109 | logmx=log10( mxval );           // take the log of max/min | 
| 110 | logmn=log10( mnval ); | 
| 111 | } | 
| 112 | } | 
| 113 |  | 
| 114 | if( scaledepth && xz || scaledepth && yz ){ // if scale-depth is set | 
| 115 | ymax=NY;                                   // scale z values to ymax | 
| 116 | tmp=(float)ymax/totaldepth;                // calculate ratio between z and ymax | 
| 117 | } | 
| 118 |  | 
| 119 | j=0;                   // counts through y-values | 
| 120 | ioff=0;                // counts through i&j values, because data is 1 dimensional | 
| 121 | h=0;                   // h counts depth levels if scaledepth is set | 
| 122 |  | 
| 123 | while ( j<ymax ){                   // cycles through y values | 
| 124 | for( i=0; i<xmax; i++ ){           // cycles through x values | 
| 125 | r=g=b=0;                          // set color values to black | 
| 126 | if( data[q][ioff]==0 );           // if data=0, values stay black | 
| 127 | else{ | 
| 128 | if( logscale ){                  // if logscale is set | 
| 129 | num=(double)data[q][ioff]; | 
| 130 | num=log10( num );               // calculate log of data | 
| 131 | if( num<logmn ) num=0;          // set data less than min to min | 
| 132 | else{ | 
| 133 | if( num>logmx ) num=63;        // set data more than max to max | 
| 134 | else | 
| 135 | num=63*( num-logmn )/( logmx-logmn ); // scale all others | 
| 136 | } | 
| 137 | } | 
| 138 | else{                                // if not logscale | 
| 139 | if( data[q][ioff]<mnval )  num=0;   // set data less than min to min | 
| 140 | else{ | 
| 141 | if( data[q][ioff]>mxval )  num=63; // set data more than max to max | 
| 142 | else | 
| 143 | num=63*( data[q][ioff]-mnval )/( mxval-mnval );  // scale all others | 
| 144 | } | 
| 145 | } | 
| 146 | r=jet[(int)num][0];                  // set red value | 
| 147 | g=jet[(int)num][1];                  // set green value | 
| 148 | b=jet[(int)num][2];                  // set blue value | 
| 149 | } | 
| 150 |  | 
| 151 | glColor3f( r, g, b );                 // put r, g, b into effect | 
| 152 | if( scaledepth && xz || scaledepth && yz )  // if scaledepth is set | 
| 153 | glRectf( i, j, i+1, j+(depths[h]*tmp) );   // draw box appropriate to width of level | 
| 154 | else                                        // otherwise | 
| 155 | glRectf( i, j, i+1, j+1 );                 // draw a square | 
| 156 | ioff++; | 
| 157 | }                                            // leave x loop | 
| 158 | if( scaledepth && xz || scaledepth && yz ){  // if scaledepth is set | 
| 159 | j+=(depths[h]*tmp);                         // scale j by width of current depth level | 
| 160 | h++;                                        // increment h (counts through depth levels) | 
| 161 | } | 
| 162 | else j++;                                    // otherwise, increment j by 1 | 
| 163 | }                                             // leave y loop | 
| 164 |  | 
| 165 | glColor3f( 1, 1, 1 );                         // set color to white | 
| 166 | glRectf( xmax, 0, xmax+1, ymax+1 );           // draw a border right of plot | 
| 167 | glRectf( 0, ymax, xmax, ymax+1 );             // draw a border on top of plot | 
| 168 |  | 
| 169 | for( i=0; i<64; i++ ){                        // draw color bar | 
| 170 | glColor3f( jet[i][0], jet[i][1], jet[i][2]); // sets color | 
| 171 | k=(float)i;                                  // turns i into a float | 
| 172 | y=(float)ymax/64;                            // scales rectangles to fit in ymax | 
| 173 | glRectf( xmax+10, y*k, xmax+20, (k+1)*y );   // draws rectangle | 
| 174 | } | 
| 175 |  | 
| 176 | glColor3f( 1, 1, 1 );                         // color to white | 
| 177 |  | 
| 178 | if( logscale ) | 
| 179 | sprintf( str, "%.2f", logmx ); | 
| 180 | else | 
| 181 | sprintf( str, "%.1e", mxval );               // labels color bar with max val | 
| 182 | stroke( str, xmax+2, ymax-1 ); | 
| 183 |  | 
| 184 | if( logscale ) | 
| 185 | sprintf( str, "%.2f", logmn ); | 
| 186 | else | 
| 187 | sprintf( str, "%.1e", mnval );               // labels color bar with min val | 
| 188 | stroke( str, xmax+2, 1 ); | 
| 189 |  | 
| 190 | if( xz )                                      // in xz view | 
| 191 | sprintf( str, "N-S slice %d", yoffset+1);    // labels NS slice | 
| 192 | else{ | 
| 193 | if( yz )                                     // in yz view | 
| 194 | sprintf( str, "E-W slice %d", xoffset+1);   // labels EW slice | 
| 195 | else                                         // in xy view | 
| 196 | sprintf( str, "Level %d", ilev );           // labels current level | 
| 197 | } | 
| 198 | stroke( str, 1, ymax+5 ); | 
| 199 |  | 
| 200 | sprintf( str, "Time %d", count+1 );           // labels current time step | 
| 201 | stroke( str, xmax/2, ymax+5 ); | 
| 202 |  | 
| 203 | if( glo )                                     // labels how max/min have been set | 
| 204 | sprintf( str, "Global" );                    // if glo is set, display Global | 
| 205 | if( usr ) | 
| 206 | sprintf( str, "User-set" );                  // if usr is set, display User-set | 
| 207 | if( !usr && !glo ) | 
| 208 | sprintf( str, "Local" );                     // else display Local | 
| 209 | stroke( str, xmax+8, ymax+8 ); | 
| 210 |  | 
| 211 | if( anim ){                                   // tell user if autoplay is on | 
| 212 | sprintf( str, "Autoplay" ); | 
| 213 | stroke( str, xmax-35, ymax+8 ); | 
| 214 | } | 
| 215 |  | 
| 216 | if( logscale ){ | 
| 217 | sprintf( str, "Log Scale" );                 // tell user if log scale is on | 
| 218 | stroke( str, xmax-25, ymax+15); | 
| 219 | } | 
| 220 |  | 
| 221 | stroke( fns[q][count], 1, ymax+15 );          // labels current file | 
| 222 |  | 
| 223 | glutSwapBuffers();                            // double buffering set to animate smoothly | 
| 224 | glFlush(); | 
| 225 | } | 
| 226 | } | 
| 227 |  | 
| 228 | void stroke( char str[], int x, int y ){        // called to display text onscreen | 
| 229 | int i; | 
| 230 |  | 
| 231 | glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );  // sets blending mode | 
| 232 | glEnable( GL_BLEND );                                 // enables blending | 
| 233 | glEnable( GL_LINE_SMOOTH );                           // enables smooth lines | 
| 234 | glMatrixMode( GL_MODELVIEW );                         // sets matrix mode | 
| 235 |  | 
| 236 | glPushMatrix();                                       // push matrix | 
| 237 |  | 
| 238 | glScalef( SCALE, SCALE, SCALE );                      // scales stroked text | 
| 239 | glTranslatef( (1/SCALE)*x, (1/SCALE)*y, 0 );          // determines location of text | 
| 240 |  | 
| 241 | for( i=0; i<strlen( str ); i++)                       // stroke each character of str | 
| 242 | glutStrokeCharacter( GLUT_STROKE_ROMAN, str[i] ); | 
| 243 |  | 
| 244 | glPopMatrix();                                        // pop matrix | 
| 245 | } | 
| 246 |  | 
| 247 | void key( unsigned char key, int x, int y ){   // called on key press | 
| 248 | int i, tmp; | 
| 249 | char fn[MAX]; | 
| 250 |  | 
| 251 | switch(key){ | 
| 252 | case 'q':   exit(0);              // close window | 
| 253 | break; | 
| 254 | case 'r':   count=0;              // reset back to first time | 
| 255 | ilev=1;               // and first level | 
| 256 | xz=yz=0;              // and xy view | 
| 257 | break; | 
| 258 | case 'a':   anim=(anim+1)%2;      // toggle autoplay | 
| 259 | break; | 
| 260 | case 'x':   xz=(xz+1)%2;          // toggle xz/xy view | 
| 261 | yz=0;                 // unset yz view, just in case | 
| 262 | break; | 
| 263 | case 'y':   yz=(yz+1)%2;          // toggle yz/xy view | 
| 264 | xz=0;                 // uset xz view, just in case | 
| 265 | break; | 
| 266 | case 'z':   if( xz || yz ){                   // if xz or yz view is set | 
| 267 | scaledepth=( scaledepth+1 )%2;   // enable depth scaling | 
| 268 | scalecount++; | 
| 269 | if( scalecount==1 ){             // read in filename the first time z is pressed | 
| 270 | printf( "Please enter filename containing depth data: " ); | 
| 271 | scanf( "%s", fn ); | 
| 272 | readdepths( fn );               // read in depth data | 
| 273 | } | 
| 274 | } | 
| 275 | break; | 
| 276 | } | 
| 277 | glutPostRedisplay();                           // redisplay with new values | 
| 278 | } | 
| 279 |  | 
| 280 | void TimerFunction( int value ){    // called when autoplay is set and arrow key is pressed | 
| 281 | int i; | 
| 282 |  | 
| 283 | switch(value){                     // increments in the correct direction | 
| 284 | case DOWN : if( xz && yoffset>0 ) // if down arrow key is pressed | 
| 285 | yoffset--;           // in xz view, move south | 
| 286 | else{ | 
| 287 | if( yz && xoffset<NX-1 ) | 
| 288 | xoffset++;          // in yz view, move east | 
| 289 | else | 
| 290 | if( ilev<NZ && !xz && !yz ) | 
| 291 | ilev++;            // in xy view, move down a depth level | 
| 292 | } | 
| 293 | break; | 
| 294 | case UP   : if( xz && yoffset<NY-1 ) // if up arrow key is ressed | 
| 295 | yoffset++;           // in xz view, move north | 
| 296 | else{ | 
| 297 | if( yz && xoffset>0 ) | 
| 298 | xoffset--;          // in yz view, move west | 
| 299 | else | 
| 300 | if( ilev>1 && !xz && !yz ) | 
| 301 | ilev--;            // in xy view, move up a depth level | 
| 302 | } | 
| 303 | break; | 
| 304 | case LEFT : if( count>0 ) | 
| 305 | count--;             // if left arrow is pressed, move back one time step | 
| 306 | break; | 
| 307 | case RIGHT: if( count<howmany-1 ) | 
| 308 | count++;             // if right arrow is pressed, move forward one time step | 
| 309 | break; | 
| 310 | } | 
| 311 |  | 
| 312 | glutPostRedisplay();               // redisplay with new values | 
| 313 |  | 
| 314 | if ( anim )                        // if autoplay is still set | 
| 315 | switch( value ){ | 
| 316 | case DOWN : if( xz && yoffset==0 ) // if furthest south is reached in xz view | 
| 317 | yoffset=NY-1;         // start at the top again | 
| 318 | else{ | 
| 319 | if( yz && xoffset==NX-1 ) // if furthest east is reached in yz view | 
| 320 | xoffset=0;               // start in the west again | 
| 321 | else | 
| 322 | if( ilev==NZ && !xz && !yz )  // if bottom level is reached in xy view | 
| 323 | ilev=1;                      // start at the surface again | 
| 324 | } | 
| 325 | glutTimerFunc( 100, TimerFunction, value ); // recall timer func | 
| 326 | break; | 
| 327 | case UP   : if( xz && yoffset==NY-1 )  // if furthest north is reached in xz view | 
| 328 | yoffset=0;                // start at the bottom again | 
| 329 | else{ | 
| 330 | if( yz && xoffset==0 )    // if furthest west is reached in yz view | 
| 331 | xoffset=NX-1;            // start in the east again | 
| 332 | else | 
| 333 | if( ilev==1 && !xz && !yz ) // if top level is reached in xy view | 
| 334 | ilev=NZ;                   // start at the bottom again | 
| 335 | } | 
| 336 | glutTimerFunc( 100, TimerFunction, value ); // recall timer func | 
| 337 | break; | 
| 338 | case LEFT : if( count==0 ) count=howmany-1;             // if first time reached, start at last | 
| 339 | glutTimerFunc( 100, TimerFunction, value ); // recall timer func | 
| 340 | break; | 
| 341 | case RIGHT: if( count==howmany-1 ) count=0;             // if last time reached, start at first | 
| 342 | glutTimerFunc( 100, TimerFunction, value ); // recall timer func | 
| 343 | break; | 
| 344 | } | 
| 345 | } | 
| 346 |  | 
| 347 | void specialkey( int key, int x, int y ){  // called on arrow key press | 
| 348 | int i; | 
| 349 |  | 
| 350 | if( anim )                                // if autoplay is set, call the timer function | 
| 351 | glutTimerFunc( 100, TimerFunction, key); // to scroll automatically | 
| 352 |  | 
| 353 | switch(key){ | 
| 354 | case DOWN   :  if( xz && yoffset>0 )     // if you haven't reached the bottom in xz view | 
| 355 | yoffset--;               // go down one NS slice | 
| 356 | else{ | 
| 357 | if( yz && xoffset<NY-1 ) // if you haven't reached the edge in yz view | 
| 358 | xoffset++;              // go east one EW slice | 
| 359 | else | 
| 360 | if( ilev<NZ && !xz && !yz ) // if you haven't reached the bottom in xy view | 
| 361 | ilev++;              // go down one level | 
| 362 | } | 
| 363 | break; | 
| 364 | case UP     :  if( xz && yoffset<NY-1 )  // if you haven't reached the top in xz view | 
| 365 | yoffset++;               // go up one NS slice | 
| 366 | else{ | 
| 367 | if( yz && xoffset>0 )    // if you haven't reached the edge in yz view | 
| 368 | xoffset--;              // go west one EW slice | 
| 369 | else | 
| 370 | if( ilev>1 && !xz && !yz ) // if you haven't reached the top in xy view | 
| 371 | ilev--;                // go up one level | 
| 372 | } | 
| 373 | break; | 
| 374 | case RIGHT  :  if( count<howmany-1 ) // if you haven't reached the last time step | 
| 375 | count++;             // go forward one time step | 
| 376 | break; | 
| 377 | case LEFT   :  if( count>0 )         // if you haven't reached the first time step | 
| 378 | count--;             // go back one time step | 
| 379 | break; | 
| 380 | } | 
| 381 | glutPostRedisplay();                  // redisplay with new values | 
| 382 | } | 
| 383 |  | 
| 384 | void global(){                         // calculates the max/min for the total data set | 
| 385 | FILE* fp; | 
| 386 | int h, i, j; | 
| 387 | for( h=0; h<sets; h++)                // cycles through each window | 
| 388 | for( i=0; i<howmany; i++ )           // cycles through each time | 
| 389 | for( j=0; j<NZ; j++ ){              // cycles through each depth level | 
| 390 | local( h, i, j );                  // calculates local max/min for specific data set | 
| 391 | if( mxval > globalmx ) globalmx = mxval;   // sets highest value to globalmx | 
| 392 | if( mnval < globalmn ) globalmn = mnval;   // sets lowest value to globalmn | 
| 393 | } | 
| 394 | } | 
| 395 |  | 
| 396 | void local( int i, int time, int lev ){        // calculates local max/min | 
| 397 | int j; | 
| 398 |  | 
| 399 | mxval=0; | 
| 400 | mnval=100; | 
| 401 | if( xz ) | 
| 402 | readxz( data[i], fns[i][time]);              // if xz view, reads new array of xz vals | 
| 403 | else{ | 
| 404 | if( yz ) | 
| 405 | readyz( data[i], fns[i][time]);             // if yz view, reads new array of yz vals | 
| 406 | else | 
| 407 | readxy( data[i], fns[i][time], lev );    // if xy view, reads new array of xy vals | 
| 408 | } | 
| 409 | for( j=0; j<xmax*ymax; j++ ){                 // cycles through all values in the array | 
| 410 | if( data[i][j] > mxval ) | 
| 411 | mxval=data[i][j];                           // set largest val to mxval | 
| 412 | if( data[i][j] < mnval && data[i][j]!=0 ) | 
| 413 | mnval=data[i][j];                           // set smallest nonzero val to mnval | 
| 414 | } | 
| 415 | } | 
| 416 |  | 
| 417 | void readnames( char filename[] ){             // reads in list of filenames | 
| 418 | FILE* fp; | 
| 419 | int i=0, j=0; | 
| 420 |  | 
| 421 | fp=fopen( filename, "r" );                    // opens list of filenames | 
| 422 | while( !feof(fp) ){                           // reads until the end of the file | 
| 423 | fscanf( fp, "%s", initfns[i] );              // places filename into an array of strings | 
| 424 | i++;                                         // counts how many filenames there are | 
| 425 | } | 
| 426 | fclose( fp );                                 // close file | 
| 427 | sets=i-1;                                     // saves number of initial filenames | 
| 428 |  | 
| 429 | for(i=0; i<sets; i++){                        // goes through each filename just read in | 
| 430 | fp=fopen( initfns[i], "r" );                 // opens each filename | 
| 431 | j=0; | 
| 432 | while( !feof(fp) ){                          // reads in filenames from each filename | 
| 433 | fscanf( fp, "%s", fns[i][j]); | 
| 434 | j++; | 
| 435 | } | 
| 436 | fclose(fp);                                  // close file | 
| 437 | } | 
| 438 | howmany=j-1;                                  // saves number of time steps | 
| 439 | } | 
| 440 |  | 
| 441 | void readdepths( char filename[] ){            // called when the scale depth feature is enabled | 
| 442 | int i; | 
| 443 | FILE* fp; | 
| 444 |  | 
| 445 | fp=fopen( filename, "r" );                    // open depth data file | 
| 446 |  | 
| 447 | for( i=NZ-1; i>=0; i-- ){                     // read in data backwards, starting at the lowest depth | 
| 448 | fscanf( fp, "%d ", &depths[i] ); | 
| 449 | totaldepth+=depths[i];                       // calculate total depth | 
| 450 | } | 
| 451 |  | 
| 452 | fclose( fp );                                 // close file | 
| 453 | } | 
| 454 |  | 
| 455 | void readjet(){               // read in color scale values | 
| 456 | FILE* fp; | 
| 457 | int i, j; | 
| 458 |  | 
| 459 | fp=fopen( "jet.dat", "r" );  // open file containing values | 
| 460 | for( i=0; i<64; i++ )        // read in 64 sets of rgb values | 
| 461 | for( j=0; j<3; j++ ) | 
| 462 | fscanf( fp, "%f", &jet[i][j] ); | 
| 463 | fclose( fp );                // close file | 
| 464 | } | 
| 465 |  | 
| 466 | void readxz( float arr[], char filename[] ){  // reads in xz values | 
| 467 | int i, j; | 
| 468 | float tmp[MAX][MAX]; | 
| 469 | FILE* fp; | 
| 470 |  | 
| 471 | fp=fopen( filename, "rb" );                         // open data file | 
| 472 | for( i=0; i<NZ; i++ ){                              // run through each depth level | 
| 473 | fseek( fp, (NX*yoffset*4)+(i*NX*NY*4), SEEK_SET ); // seek to correct place in the file | 
| 474 | fread( &arr[NX*i], sizeof( arr[0] ), NX, fp );     // reads in one row of x-values | 
| 475 | } | 
| 476 | fclose( fp );                                       // close file | 
| 477 |  | 
| 478 | for( i=0; i<NZ; i++ ) // the array should start at the ocean floor and move upwards | 
| 479 | for( j=0; j<NX; j++) // so it has been read in backwards | 
| 480 | tmp[i][j]=arr[i*NX+j]; // put each row of x-values into a 2d array | 
| 481 |  | 
| 482 | for( i=0; i<NZ; i++ ) | 
| 483 | for( j=0; j<NX; j++) | 
| 484 | arr[i*NX+j]=tmp[NZ-i-1][j];  // flip the order of the rows, and store in the data array | 
| 485 |  | 
| 486 | if( nonegs ) | 
| 487 | for( i=0; i<NX*NZ; i++ ) | 
| 488 | if( arr[i] < 0 ) | 
| 489 | arr[i] = pow(10, -20);      // sets negative values to 10^-20 | 
| 490 |  | 
| 491 | if( endian ) | 
| 492 | do_byteswap_f32( arr, NX*NZ );            // switches endian | 
| 493 | } | 
| 494 |  | 
| 495 | void readyz( float arr[], char filename[] ){  // reads in yz values | 
| 496 | int i, j; | 
| 497 | float tmp[MAX][MAX]; | 
| 498 | FILE* fp; | 
| 499 |  | 
| 500 | fp=fopen( filename, "rb" );                         // open data file | 
| 501 | for( i=0; i<NY*NZ; i++ ){                           // run through each line in the file | 
| 502 | fseek( fp, (xoffset*4)+(i*NX*4), SEEK_SET );       // seek to the correct place in the file | 
| 503 | fread( &arr[i], sizeof( arr[0] ), 1, fp );         // reads in one y-value at the correct x | 
| 504 | } | 
| 505 | fclose(fp);                                         // close file | 
| 506 |  | 
| 507 | for( i=0; i<NZ; i++ ) // the array should start at the ocean floor and move upwards | 
| 508 | for( j=0; j<NY; j++) // so it has been read in backwards | 
| 509 | tmp[i][j]=arr[i*NY+j]; // put each row of x-values into a 2d array | 
| 510 |  | 
| 511 | for( i=0; i<NZ; i++ ) | 
| 512 | for( j=0; j<NY; j++) | 
| 513 | arr[i*NY+j]=tmp[NZ-i-1][j];  // flip the order of the rows, and store in the data array | 
| 514 |  | 
| 515 | if( nonegs ) | 
| 516 | for( i=0; i<NY*NZ; i++ ) | 
| 517 | if( arr[i] < 0 ) | 
| 518 | arr[i] = pow(10, -20);   // sets negative values to 10^-20 | 
| 519 |  | 
| 520 | if( endian ) | 
| 521 | do_byteswap_f32( arr, NY*NZ );            // switches endian | 
| 522 |  | 
| 523 | } | 
| 524 |  | 
| 525 | void readxy( float arr[], char filename[], int il ){   // reads in xy values | 
| 526 | FILE* fp; | 
| 527 | int i; | 
| 528 |  | 
| 529 | fp=fopen( filename, "rb" );                 // opens the file containing data | 
| 530 | fseek( fp, (il-1)*NX*NY*4, SEEK_SET );      // seeks to the correct place | 
| 531 | fread( arr, sizeof( arr[0] ), NX*NY, fp );  // reads in data to fill one level | 
| 532 | fclose( fp );                               // close file | 
| 533 |  | 
| 534 | if( nonegs ) | 
| 535 | for( i=0; i<NX*NY; i++ ) | 
| 536 | if( arr[i] < 0 ) | 
| 537 | arr[i] = pow(10, -20);   // sets negative values to 10^-20 | 
| 538 |  | 
| 539 | if( endian ) | 
| 540 | do_byteswap_f32( arr, NX*NY );            // switches endian | 
| 541 | } | 
| 542 |  | 
| 543 | void do_byteswap_f32( float arr[], int nel ){ // switches endian | 
| 544 |  | 
| 545 | int i; | 
| 546 | char src[4], trg[4]; | 
| 547 |  | 
| 548 | for( i=0; i<nel; i++ ){ | 
| 549 | memcpy( src, &(arr[i]), 4 ); | 
| 550 | trg[0]=src[3]; | 
| 551 | trg[1]=src[2]; | 
| 552 | trg[2]=src[1]; | 
| 553 | trg[3]=src[0]; | 
| 554 | memcpy( &(arr[i]), trg, 4 ); | 
| 555 | } | 
| 556 | } | 
| 557 |  | 
| 558 | void black( ){                   // display func for extra windows | 
| 559 | glClear( GL_COLOR_BUFFER_BIT ); | 
| 560 | glutSwapBuffers(); | 
| 561 | glFlush(); | 
| 562 | } | 
| 563 |  | 
| 564 |  | 
| 565 | int main( int argc, char *argv[] ){ | 
| 566 | int i, setsx, setsy, tmpx, tmpy, winx, winy, parent; | 
| 567 | char str[MAX], filename[MAX]; | 
| 568 | FILE* fp; | 
| 569 |  | 
| 570 | printf("Hello 1\n"); | 
| 571 | if( strcmp(argv[1], "binary") == 0 )       // if data files are binary open binconfig | 
| 572 | fp=fopen( ".darwinview/binconfig", "r" ); | 
| 573 | else | 
| 574 | if( strcmp(argv[1],"netcdf") == 0 )       // if data files are netcdf open ncconfig | 
| 575 | fp=fopen( ".darwinview/ncconfig", "r" ); | 
| 576 | printf("Hello 2\n"); | 
| 577 |  | 
| 578 | fscanf( fp, "%dx%d ", &winx, &winy );      // read in screen resolution | 
| 579 | printf("Hello 3\n"); | 
| 580 | winy-=60;  winx-=20;                       // adjust resolution so edges won't get cut off | 
| 581 | fscanf( fp, "%d %d %d ", &NX, &NY, &NZ );  // read in dimensions of data | 
| 582 | fscanf( fp, "%dx%d ", &setsx, &setsy );    // read in dimensions of subwindows | 
| 583 | fscanf( fp, "%s", filename );              // read in name of file containing data filenames | 
| 584 |  | 
| 585 | fclose( fp );                              // close file | 
| 586 |  | 
| 587 | xmax=NX; ymax=NY;                          // default to xy | 
| 588 | printf("Hello 4\n"); | 
| 589 |  | 
| 590 | readjet();                                 // stores color values | 
| 591 | printf("Hello 5\n"); | 
| 592 | readnames( filename );                     // gets list of filenames to read from | 
| 593 | printf("Hello 6\n"); | 
| 594 | global();                                  // calculates max and min for all data | 
| 595 | printf("Hello 7\n"); | 
| 596 |  | 
| 597 | glutInit( &argc, argv ); | 
| 598 | glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );   // set rgb mode and double buffering | 
| 599 | glutInitWindowSize( winx, winy );                // parent window will cover screen | 
| 600 | glutInitWindowPosition( 10, 10 );                // set location of parent window | 
| 601 | parent=glutCreateWindow( WINDOW );               // create parent window | 
| 602 |  | 
| 603 | glClearColor( 0, 0, 0, 0 );                      // set clear color to black | 
| 604 | gluOrtho2D( 0, winx , winy, 0 );                 // set (0,0) as top left corner | 
| 605 | glutDisplayFunc( display );                      // declares display func | 
| 606 | glutKeyboardFunc( key );                         // called on key press | 
| 607 | glutSpecialFunc( specialkey );                   // called on special key press (arrow keys) | 
| 608 |  | 
| 609 |  | 
| 610 | for( i=0; i<setsx*setsy; i++ ){                  // for each subwindow | 
| 611 | tmpx = (i%setsx)*(winx/setsx);                  // x coordinate of top left corner of subwindow | 
| 612 | tmpy = (i/setsx)*(winy/setsy);                  // y coordinate of top left corner of subwindow | 
| 613 |  | 
| 614 | win[i]=glutCreateSubWindow( parent, tmpx, tmpy, winx/setsx, winy/setsy ); // creates subwindow | 
| 615 | gluOrtho2D( 0, NX+35, 0, NY+25 );               // sets how data is mapped to subwindow | 
| 616 | glutKeyboardFunc( key );                        // called on key press | 
| 617 | glutSpecialFunc( specialkey );                  // called on special key press (arrow keys) | 
| 618 | if( i >= sets )                                 // if there are more subwindows than data sets | 
| 619 | glutDisplayFunc( black );                      // color those windows black | 
| 620 | else                                            // otherwise | 
| 621 | glutDisplayFunc( display );                    // sets display func for subwindow | 
| 622 |  | 
| 623 |  | 
| 624 | glutCreateMenu( menu );                                // adds a menu | 
| 625 | glutAddMenuEntry( "Local Color Scale", 1 );           // adds a menu entry | 
| 626 | glutAddMenuEntry( "Global Color Scale", 2 );          // adds a menu entry | 
| 627 | glutAddMenuEntry( "User-Set Color Scale", 3 );        // adds a menu entry | 
| 628 | glutAddMenuEntry( "Log Scale (on/off)", 4 );          // adds a menu entry | 
| 629 | glutAddMenuEntry( "Allow Negatives (on/off)", 5 );    // adds a menu entry | 
| 630 | glutAddMenuEntry( "Switch Endian (big/little) ", 6);  // adds a menu entry | 
| 631 | glutAttachMenu( GLUT_RIGHT_BUTTON );                   // menu called on right click | 
| 632 | } | 
| 633 |  | 
| 634 | glutMainLoop();                                  // begin processing events | 
| 635 | return 0; | 
| 636 | } | 
| 637 |  |