sunlight.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:13k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* sunlight.c
  2.  * 
  3.  * To compile:
  4.  * cc -o sunlight sunlight.c -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm
  5.  *
  6.  * Usage: sunlight
  7.  *
  8.  * Requires: globe.raw
  9.  *
  10.  * This program demonstrates the sun lighting the earth, displayed
  11.  * either as a globe or a flat map.  The time of day and day of year
  12.  * can be adjusted interactively, and the globe can be viewed from
  13.  * any angle.
  14.  *
  15.  * The lighting is done using OpenGL's lighting.  The flat map is
  16.  * lighted by using the normals of globe.  This is a rather unique
  17.  * use of normals, making a flat surface lit as if it were round.
  18.  *
  19.  * The left mouse adjusts the globe orientation, the time of day, or
  20.  * the time of year.  The right mouse activates a menu.
  21.  *
  22.  * Chris Schoeneman - 9/6/98
  23.  * crs23@bigfoot.com
  24.  * http://www.bigfoot.com/~crs23/
  25.  *        
  26.  */
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include <GL/glut.h>
  31. #ifndef M_PI
  32. #define M_PI 3.14159265358979323846
  33. #endif
  34. /* menu constants */
  35. #define MENU_SHOW_GLOBE 1
  36. #define MENU_SHOW_MAP 2
  37. #define MENU_ADJUST_GLOBE 3
  38. #define MENU_ADJUST_DAY 4
  39. #define MENU_ADJUST_TIME 5
  40. #define MENU_QUIT 6
  41. static int mapMode = 0;
  42. static int adjustMode = 0;
  43. static GLdouble aspectRatio = 1.0;
  44. static double timeOfDay = 0.0;
  45. static double timeOfYear = 0.0;
  46. /*
  47.  * sun direction functions
  48.  */
  49. static const double radPerDeg = M_PI / 180.0;
  50. static const double radPerHour = M_PI / 12.0;
  51. static const double siderealHoursPerHour = 1.002737908;
  52. static const double epoch = 2415020.0;
  53. static double getGreenwichSideral(double julianDay)
  54. {
  55.   double jdMidnight;
  56.   double dayFraction;
  57.   double T; /* time (fractions of a century) */
  58.   double greenwichMidnight;
  59.   /* true position requires sidereal time of midnight at prime meridian.
  60.      get midnight of given julian day (midnight has decimal of .5). */
  61.   jdMidnight = floor(julianDay);
  62.   if (julianDay - jdMidnight >= 0.5) jdMidnight += 0.5;
  63.   else jdMidnight -= 0.5;
  64.   T = (jdMidnight - epoch) / 36525.0;
  65.   /* get fraction of a day */
  66.   dayFraction = (julianDay - jdMidnight) * 24.0;
  67.   /* get Greenwich midnight sidereal time (in hours) */
  68.   greenwichMidnight =
  69. fmod((0.00002581 * T + 2400.051262) * T + 6.6460656, 24.0);
  70.   /* return Greenwich sidereal time */
  71.   return radPerHour * (greenwichMidnight + dayFraction * siderealHoursPerHour);
  72. }
  73. static void getTruePosition(double julianDay,
  74. float latitude, float longitude,
  75. double sx, double sy, double sz,
  76. float pos[3])
  77. {
  78.   double tx, ty, tz;
  79.   double localSidereal;
  80.   /* convert to radians */
  81.   latitude *= radPerDeg;
  82.   longitude *= radPerDeg;
  83.   /* get local sidereal time */
  84.   localSidereal = getGreenwichSideral(julianDay) - longitude;
  85.   /* rotate around polar axis (y-axis) by local sidereal time */
  86.   tx = sx * cos(localSidereal) - sz * sin(localSidereal);
  87.   ty = sy;
  88.   tz = sz * cos(localSidereal) + sx * sin(localSidereal);
  89.   /* rotate by latitude to local position */
  90.   pos[0] = (float)tx;
  91.   pos[1] = (float)(ty * cos(latitude) - tz * sin(latitude));
  92.   pos[2] = (float)(tz * cos(latitude) + ty * sin(latitude));
  93. }
  94. static void getSunDirection(double julianDay, float latitude,
  95. float longitude, float pos[3])
  96. {
  97.   double C;
  98.   double T; /* time (fractions of a century) */
  99.   double sx, sy, sz; /* sun direction */
  100.   double obliquity; /* earth's tilt */
  101.   double meanAnomaly;
  102.   double geometricMeanLongitude;
  103.   double trueLongitude;
  104.   T = (julianDay - epoch) / 36525.0;
  105.   obliquity = radPerDeg *
  106. (23.452294 + (-0.0130125 + (-0.00000164 +
  107. 0.000000503 * T) * T) * T);
  108.   meanAnomaly = radPerDeg * (358.47583 +
  109. ((0.0000033 * T + 0.000150) * T + 35999.04975) * T);
  110.   geometricMeanLongitude = radPerDeg *
  111. ((0.0003025 * T + 36000.76892) * T + 279.69668);
  112.   C = radPerDeg *
  113. (sin(meanAnomaly) * (1.919460 - (0.004789 + 0.000014 * T) * T) +
  114. sin(2.0 * meanAnomaly) * (0.020094 - 0.0001 * T) +
  115. sin(3.0 * meanAnomaly) * 0.000293);
  116.   trueLongitude = geometricMeanLongitude + C;
  117.   /* position of sun if earth didn't rotate: */
  118.   sx = sin(trueLongitude) * cos(obliquity);
  119.   sy = sin(trueLongitude) * sin(obliquity);
  120.   sz = cos(trueLongitude);
  121.   /* get true position */
  122.   getTruePosition(julianDay, latitude, longitude, sx, sy, sz, pos);
  123. }
  124. /*
  125.  * globe/map calculation
  126.  */
  127. #define LAT_GRID 20
  128. #define LON_GRID 40
  129. static GLfloat sphere[LAT_GRID + 1][LON_GRID + 1][3];
  130. static GLfloat map[LAT_GRID + 1][LON_GRID + 1][2];
  131. static GLfloat uv[LAT_GRID + 1][LON_GRID + 1][2];
  132. static void initSphere(void)
  133. {
  134.   int lat, lon;
  135.   for (lat = 0; lat <= LAT_GRID; lat++) {
  136.     const float y = (float)-cos(M_PI * (double)lat / (double)LAT_GRID);
  137.     const float r = (float)sin(M_PI * (double)lat / (double)LAT_GRID);
  138.     for (lon = 0; lon <= LON_GRID; lon++) {
  139.       sphere[lat][lon][0] = r * (float)sin(-M_PI + 2.0 * M_PI *
  140. (double)lon / (double)LON_GRID);
  141.       sphere[lat][lon][1] = y;
  142.       sphere[lat][lon][2] = r * (float)cos(-M_PI + 2.0 * M_PI *
  143. (double)lon / (double)LON_GRID);
  144.     }
  145.   }
  146. }
  147. static void initMap(void)
  148. {
  149.   int lat, lon;
  150.   for (lat = 0; lat <= LAT_GRID; lat++) {
  151.     const float y = 1.0f * ((float)lat / (float)LAT_GRID - 0.5f);
  152.     for (lon = 0; lon <= LON_GRID; lon++) {
  153.       map[lat][lon][0] = 2.0f * ((float)lon / (float)LON_GRID - 0.5f);
  154.       map[lat][lon][1] = y;
  155.     }
  156.   }
  157. }
  158. static int isPowerOfTwo(int x)
  159. {
  160.   if (x <= 0) return 0;
  161.   while ((x & 1) == 0) x >>= 1;
  162.   return x == 1;
  163. }
  164. static void initTexture(const char* filename)
  165. {
  166.   FILE* imageFile;
  167.   int lat, lon;
  168.   unsigned char buffer[4];
  169.   unsigned char* image;
  170.   int dx, dy;
  171.   /* initialize texture coordinates */
  172.   for (lat = 0; lat <= LAT_GRID; lat++) {
  173.     const float y = (float)lat / (float)LAT_GRID;
  174.     for (lon = 0; lon <= LON_GRID; lon++) {
  175.       uv[lat][lon][0] = (float)lon / (float)LON_GRID;
  176.       uv[lat][lon][1] = y;
  177.     }
  178.   }
  179.   /* open image file */
  180.   imageFile = fopen(filename, "rb");
  181.   if (!imageFile) {
  182.     fprintf(stderr, "cannot open image file %s for readingn", filename);
  183.     exit(1);
  184.   }
  185.   /* read image size */
  186.   fread(buffer, 1, 4, imageFile);
  187.   dx = (int)((buffer[0] << 8) | buffer[1]);
  188.   dy = (int)((buffer[2] << 8) | buffer[3]);
  189.   if (!isPowerOfTwo(dx) || !isPowerOfTwo(dy)) {
  190.     fprintf(stderr, "image %s has an illegal size: %dx%dn", filename, dx, dy);
  191.     exit(1);
  192.   }
  193.   /* read image */
  194.   image = (unsigned char*)malloc(3 * dx * dy * sizeof(unsigned char));
  195.   fread(image, 3 * dx, dy, imageFile);
  196.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  197.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  198.   glTexImage2D(GL_TEXTURE_2D, 0, 3, dx, dy, 0,
  199. GL_RGB, GL_UNSIGNED_BYTE, image);
  200.   /* tidy up */
  201.   free(image);
  202.   fclose(imageFile);
  203. }
  204. /*
  205.  * misc OpenGL stuff
  206.  */
  207. static const GLfloat sunColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  208. static GLfloat sunDirection[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
  209. static const GLfloat surfaceColor[] = { 0.8f, 0.8f, 0.8f, 1.0f };
  210. static void initProjection(void)
  211. {
  212.   glMatrixMode(GL_PROJECTION);
  213.   glLoadIdentity();
  214.   if (mapMode) {
  215.     /* orthographic for map */
  216.     if (aspectRatio < 2.0)
  217.       glOrtho(-1.0, 1.0, -1.0 / aspectRatio, 1.0 / aspectRatio, 2.0, 4.0);
  218.     else
  219.       glOrtho(-0.5 * aspectRatio, 0.5 * aspectRatio, -0.5, 0.5, 2.0, 4.0);
  220.   }
  221.   else {
  222.     /* prespective for globe */
  223.     gluPerspective(40.0, aspectRatio, 1.0, 5.0);
  224.   }
  225.   glMatrixMode(GL_MODELVIEW);
  226. }
  227. static void initSunlight(void)
  228. {
  229.   getSunDirection(epoch + timeOfDay + 365.0 * timeOfYear,
  230. 0.0f, 0.0f, sunDirection);
  231.   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  232.   glLightfv(GL_LIGHT0, GL_DIFFUSE, sunColor);
  233.   glLightfv(GL_LIGHT0, GL_POSITION, sunDirection);
  234.   glEnable(GL_LIGHT0);
  235.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, surfaceColor);
  236. }
  237. /*
  238.  * glut callbacks
  239.  */
  240. static GLfloat angle = 0; /* in degrees */
  241. static GLfloat angle2 = 0; /* in degrees */
  242. static int moving = 0, startx, starty;
  243. static void reshapeCB(GLsizei w, GLsizei h)
  244. {
  245.   aspectRatio = (GLdouble)w / (GLdouble)h;
  246.   glViewport(0, 0, w, h);
  247.   initProjection();
  248.   glutPostRedisplay();
  249. }
  250. static void redrawCB(void)
  251. {
  252.   glClear(GL_COLOR_BUFFER_BIT);
  253.   glPushMatrix();
  254.     /* Perform scene rotations based on user mouse input. */
  255.     if (!mapMode) {
  256.       glRotatef(angle2, 1.0f, 0.0f, 0.0f);
  257.       glRotatef(angle, 0.0f, 1.0f, 0.0f);
  258.     }
  259.     glLightfv(GL_LIGHT0, GL_POSITION, sunDirection);
  260.     if (mapMode) {
  261.       /* use the normals for a sphere on a flat surface to get
  262.        * the lighting as if we unwrapped a lighted sphere. */
  263.       int lat, lon;
  264.       for (lat = 0; lat < LAT_GRID; lat++) {
  265. glBegin(GL_TRIANGLE_STRIP);
  266.   for (lon = 0; lon <= LON_GRID; lon++) {
  267.     glTexCoord2fv(uv[lat + 1][lon]);
  268.     glNormal3fv(sphere[lat + 1][lon]);
  269.     glVertex2fv(map[lat + 1][lon]);
  270.     glTexCoord2fv(uv[lat][lon]);
  271.     glNormal3fv(sphere[lat][lon]);
  272.     glVertex2fv(map[lat][lon]);
  273.   }
  274. glEnd();
  275.       }
  276.     }
  277.     else {
  278.       /* draw a sphere */
  279.       int lat, lon;
  280.       for (lat = 0; lat < LAT_GRID; lat++) {
  281. glBegin(GL_TRIANGLE_STRIP);
  282.   for (lon = 0; lon <= LON_GRID; lon++) {
  283.     glTexCoord2fv(uv[lat + 1][lon]);
  284.     glNormal3fv(sphere[lat + 1][lon]);
  285.     glVertex3fv(sphere[lat + 1][lon]);
  286.     glTexCoord2fv(uv[lat][lon]);
  287.     glNormal3fv(sphere[lat][lon]);
  288.     glVertex3fv(sphere[lat][lon]);
  289.   }
  290. glEnd();
  291.       }
  292.     }
  293.   glPopMatrix();
  294.   glutSwapBuffers();
  295. }
  296. static void mouseCB(int button, int state, int x, int y)
  297. {
  298.   if (button == GLUT_LEFT_BUTTON) {
  299.     if (state == GLUT_DOWN) {
  300.       moving = 1;
  301.       startx = x;
  302.       starty = y;
  303.     }
  304.     else if (state == GLUT_UP) {
  305.       moving = 0;
  306.     }
  307.   }
  308. }
  309. static void motionCB(int x, int y)
  310. {
  311.   if (moving) {
  312.     switch (adjustMode) {
  313.       case 0:
  314. /* move globe */
  315. if (!mapMode) {
  316.   angle = angle + (x - startx);
  317.   angle2 = angle2 + (y - starty);
  318.   glutPostRedisplay();
  319. }
  320. break;
  321.       case 1:
  322. /* change day of year */
  323. timeOfYear = timeOfYear + (y - starty) / 365.0;
  324. while (timeOfYear < 0) timeOfYear += 1.0;
  325. while (timeOfYear >= 1.0) timeOfYear -= 1.0;
  326. getSunDirection(epoch + timeOfDay + 365.0 * timeOfYear,
  327. 0.0f, 0.0f, sunDirection);
  328. glutPostRedisplay();
  329. break;
  330.       case 2:
  331. /* change time of day (by 4 minute increments (24 hrs / 360)) */
  332. timeOfDay = timeOfDay + (y - starty) / 360.0;
  333. while (timeOfDay < 0) timeOfDay += 1.0;
  334. while (timeOfDay >= 1.0) timeOfDay -= 1.0;
  335. getSunDirection(epoch + timeOfDay + 365.0 * timeOfYear,
  336. 0.0f, 0.0f, sunDirection);
  337. glutPostRedisplay();
  338. break;
  339.     }
  340.     startx = x;
  341.     starty = y;
  342.   }
  343. }
  344. static void keyCB(unsigned char c, int x, int y)
  345. {
  346.   if (c == 27) {
  347.     exit(0);
  348.   }
  349.   glutPostRedisplay();
  350. }
  351. /*
  352.  * menu handling
  353.  */
  354. static void handleMenu(int value)
  355. {
  356.   switch (value) {
  357.     default:
  358.       break;
  359.     case MENU_SHOW_GLOBE:
  360.       mapMode = 0;
  361.       initProjection();
  362.       glutPostRedisplay();
  363.       glutChangeToMenuEntry(2, "Show Globe *", MENU_SHOW_GLOBE);
  364.       glutChangeToMenuEntry(3, "Show Map", MENU_SHOW_MAP);
  365.       break;
  366.     case MENU_SHOW_MAP:
  367.       mapMode = 1;
  368.       initProjection();
  369.       glutPostRedisplay();
  370.       glutChangeToMenuEntry(2, "Show Globe", MENU_SHOW_GLOBE);
  371.       glutChangeToMenuEntry(3, "Show Map *", MENU_SHOW_MAP);
  372.       break;
  373.     case MENU_ADJUST_GLOBE:
  374.       adjustMode = 0;
  375.       glutChangeToMenuEntry(4, "Adjust Globe *", MENU_ADJUST_GLOBE);
  376.       glutChangeToMenuEntry(5, "Adjust Day", MENU_ADJUST_DAY);
  377.       glutChangeToMenuEntry(6, "Adjust Time", MENU_ADJUST_TIME);
  378.       break;
  379.     case MENU_ADJUST_DAY:
  380.       adjustMode = 1;
  381.       glutChangeToMenuEntry(4, "Adjust Globe", MENU_ADJUST_GLOBE);
  382.       glutChangeToMenuEntry(5, "Adjust Day *", MENU_ADJUST_DAY);
  383.       glutChangeToMenuEntry(6, "Adjust Time", MENU_ADJUST_TIME);
  384.       break;
  385.     case MENU_ADJUST_TIME:
  386.       adjustMode = 2;
  387.       glutChangeToMenuEntry(4, "Adjust Globe", MENU_ADJUST_GLOBE);
  388.       glutChangeToMenuEntry(5, "Adjust Day", MENU_ADJUST_DAY);
  389.       glutChangeToMenuEntry(6, "Adjust Time *", MENU_ADJUST_TIME);
  390.       break;
  391.     case MENU_QUIT:
  392.       exit(0);
  393.   }
  394. }
  395. /*
  396.  * main
  397.  */
  398. int main(int argc, char** argv)
  399. {
  400.   /*
  401.    * initialize GLUT and open a window
  402.    */
  403.   glutInit(&argc, argv);
  404.   glutInitWindowSize(512, 512);
  405.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
  406.   glutCreateWindow("Sunlight");
  407.   glutDisplayFunc(redrawCB);
  408.   glutReshapeFunc(reshapeCB);
  409.   glutMouseFunc(mouseCB);
  410.   glutMotionFunc(motionCB);
  411.   glutKeyboardFunc(keyCB);
  412.   /*
  413.    * make the menu
  414.    */
  415.   glutCreateMenu(handleMenu);
  416.   glutAddMenuEntry("SUNLIGHT", 0);
  417.   glutAddMenuEntry("Show Globe *", MENU_SHOW_GLOBE);
  418.   glutAddMenuEntry("Show Map", MENU_SHOW_MAP);
  419.   glutAddMenuEntry("Adjust Globe *", MENU_ADJUST_GLOBE);
  420.   glutAddMenuEntry("Adjust Day", MENU_ADJUST_DAY);
  421.   glutAddMenuEntry("Adjust Time", MENU_ADJUST_TIME);
  422.   glutAddMenuEntry("Quit", MENU_QUIT);
  423.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  424.   /*
  425.    * initialize GL
  426.    */
  427.   initProjection();
  428.   gluLookAt(0.0, 0.0, 3.0,
  429.     0.0, 0.0, 0.0,
  430.     0.0, 1.0, 0.0);
  431.   initSunlight();
  432.   glEnable(GL_LIGHTING);
  433.   glEnable(GL_CULL_FACE);
  434.   glEnable(GL_TEXTURE_2D);
  435.   /*
  436.    * initialize data structures
  437.    */
  438.   initSphere();
  439.   initMap();
  440.   initTexture("globe.raw");
  441.   glutMainLoop();
  442.   return 0;             /* ANSI C requires main to return int. */
  443. }