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

GIS编程

开发平台:

Visual C++

  1. /* Copyright (c) Mark J. Kilgard, 1997.  */
  2. /* This program is freely distributable without licensing fees  and is
  3.    provided without guarantee or warrantee expressed or  implied. This
  4.    program is -not- in the public domain. */
  5. /* This program demonstrates virtualization of OpenGL's lights.  The idea is
  6.    that if an object is lit by many lights, it is computationally more
  7.    efficient to calculate the approximate lighting contribution of the
  8.    various lights per-object and only enable the "brightest" lights while
  9.    rendering the object.  This also lets you render scenes with more lights
  10.    than the OpenGL implementation light (usually 8).  Two approaches are
  11.    used:  The "distance-based" approach only enables the 8 closest lights
  12.    based purely on distance.  The "Lambertian-based" approach accounts for
  13.    diffuse lighting contributions and approximates the diffuse contribution. */
  14. #include <math.h>
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <GL/glut.h>
  19. /* Some <math.h> files do not define M_PI... */
  20. #ifndef M_PI
  21. #define M_PI 3.14159265358979323846
  22. #endif
  23. #define MIN_VALUE(a,b) (((a)<(b))?(a):(b))
  24. #define MAX_VALUE(a,b) (((a)>(b))?(a):(b))
  25. enum {
  26.   DL_LIGHT_SPHERE = 1,
  27.   DL_BIG_SPHERE = 2,
  28.   DL_ICO = 3
  29. };
  30. enum {
  31.   M_SPHERE, M_ICO, M_LABELS, M_LINEAR, M_QUAD, M_REPORT_SIG,
  32.   M_LAMBERTIAN, M_DISTANCE, M_TIME
  33. };
  34. typedef struct _LightInfo {
  35.   GLfloat xyz[4];
  36.   GLfloat *rgb;
  37.   int enable;
  38. } LightInfo;
  39. typedef struct _LightBrightness {
  40.   int num;
  41.   GLfloat brightness;
  42. } LightBrightness;
  43. static int animation = 1;
  44. static int labelLights = 1;
  45. static int reportLightSignificance = 0;
  46. static int brightnessModel = M_LAMBERTIAN;
  47. static int numActiveLights;
  48. static int timeFrames = 0;
  49. static int singleBuffer = 0;
  50. /* *INDENT-OFF* */
  51. static GLfloat modelAmb[4] = {0.1, 0.1, 0.1, 1.0};
  52. static GLfloat matAmb[4] = {0.2, 0.2, 0.2, 1.0};
  53. static GLfloat matDiff[4] = {0.8, 0.8, 0.8, 1.0};
  54. static GLfloat matSpec[4] = {0.4, 0.4, 0.4, 1.0};
  55. static GLfloat matEmission[4] = {0.0, 0.0, 0.0, 1.0};
  56. GLfloat red[] = {1.0, 0.0, 0.0, 1.0};
  57. GLfloat green[] = {0.0, 1.0, 0.0, 1.0};
  58. GLfloat blue[] = {0.0, 0.0, 1.0, 1.0};
  59. GLfloat yellow[] = {1.0, 1.0, 0.0, 1.0};
  60. GLfloat magenta[] = {1.0, 0.0, 1.0, 1.0};
  61. GLfloat white[] = {1.0, 1.0, 1.0, 1.0};
  62. GLfloat dim[] = {0.5, 0.5, 0.5, 1.0};
  63. LightInfo linfo[] = {
  64.   { {-4.0, 0.0, -10.0, 1.0}, yellow},
  65.   { {4.0, 0.0, -10.0, 1.0}, green},
  66.   { {-4.0, 0.0, -6.0, 1.0}, red},
  67.   { {4.0, 0.0, -6.0, 1.0}, blue},
  68.   { {-4.0, 0.0, -2.0, 1.0}, green},
  69.   { {4.0, 0.0, -2.0, 1.0}, yellow},
  70.   { {-4.0, 0.0, 2.0, 1.0}, blue},
  71.   { {4.0, 0.0, 2.0, 1.0}, red},
  72.   { {-4.0, 0.0, 6.0, 1.0}, yellow},
  73.   { {4.0, 0.0, 6.0, 1.0}, green},
  74.   { {-4.0, 0.0, 10.0, 1.0}, red},
  75.   { {4.0, 0.0, 10.0, 1.0}, blue},
  76. };
  77. int lightState[8] = {1, 1, 1, 1, 1, 1, 1, 1};
  78. /* *INDENT-ON* */
  79. #define MAX_LIGHTS (sizeof(linfo)/sizeof(linfo[0]))
  80. int moving = 0, begin;
  81. GLfloat angle = 0.0;
  82. int object = M_SPHERE;
  83. int attenuation = M_QUAD;
  84. GLfloat t = 0.0;
  85. void
  86. initLight(int num)
  87. {
  88.   glLightf(GL_LIGHT0 + num, GL_CONSTANT_ATTENUATION, 0.0);
  89.   if (attenuation == M_LINEAR) {
  90.     glLightf(GL_LIGHT0 + num, GL_LINEAR_ATTENUATION, 0.4);
  91.     glLightf(GL_LIGHT0 + num, GL_QUADRATIC_ATTENUATION, 0.0);
  92.   } else {
  93.     glLightf(GL_LIGHT0 + num, GL_LINEAR_ATTENUATION, 0.0);
  94.     glLightf(GL_LIGHT0 + num, GL_QUADRATIC_ATTENUATION, 0.1);
  95.   }
  96.   glLightfv(GL_LIGHT0 + num, GL_SPECULAR, dim);
  97. }
  98. /* Draw a sphere the same color as the light at the light position so it is
  99.    easy to tell where the positional light sources are. */
  100. void
  101. drawLight(LightInfo * info)
  102. {
  103.   glPushMatrix();
  104.   glTranslatef(info->xyz[0], info->xyz[1], info->xyz[2]);
  105.   glColor3fv(info->rgb);
  106.   glCallList(DL_LIGHT_SPHERE);
  107.   glPopMatrix();
  108. }
  109. /* Place the light's OpenGL light number next to the light's sphere.  To
  110.    ensure a readable number with good contrast, a black version of the number 
  111.    is drawn shifted a pixel to the left and right of the actual white number. 
  112.  */
  113. void
  114. labelLight(LightInfo * info, int num)
  115. {
  116.   GLubyte nothin = 0;
  117.   void *font = GLUT_BITMAP_HELVETICA_18;
  118.   int width = glutBitmapWidth(font, '0' + num);
  119.   glPushMatrix();
  120.   glColor3f(0.0, 0.0, 0.0);
  121.   glRasterPos3f(info->xyz[0], info->xyz[1], info->xyz[2]);
  122.   glBitmap(1, 1, 0, 0, 4, 5, &nothin);
  123.   glutBitmapCharacter(font, '0' + num);
  124.   glBitmap(1, 1, 0, 0, 2 - width, 0, &nothin);
  125.   glutBitmapCharacter(font, '0' + num);
  126.   if (lightState[num]) {
  127.     glColor3fv(white);
  128.   } else {
  129.     /* Draw disabled lights dimmer. */
  130.     glColor3fv(dim);
  131.   }
  132.   glRasterPos3f(info->xyz[0], info->xyz[1], info->xyz[2]);
  133.   glBitmap(1, 1, 0, 0, 5, 5, &nothin);
  134.   glutBitmapCharacter(font, '0' + num);
  135.   glPopMatrix();
  136. }
  137. /* Comparison routine used by qsort. */
  138. int
  139. lightBrightnessCompare(const void *a, const void *b)
  140. {
  141.   LightBrightness *ld1 = (LightBrightness *) a;
  142.   LightBrightness *ld2 = (LightBrightness *) b;
  143.   GLfloat diff;
  144.   /* The brighter lights get sorted close to top of the list. */
  145.   diff = ld2->brightness - ld1->brightness;
  146.   if (diff > 0)
  147.     return 1;
  148.   if (diff < 0)
  149.     return -1;
  150.   return 0;
  151. }
  152. void
  153. display(void)
  154. {
  155.   int i;
  156.   GLfloat x, y, z;
  157.   LightBrightness ld[MAX_LIGHTS];
  158.   int start, end;
  159.   if (timeFrames) {
  160.     start = glutGet(GLUT_ELAPSED_TIME);
  161.   }
  162.   x = cos(t * 12.3) * 2.0;
  163.   y = 0.0;
  164.   z = sin(t) * 7.0;
  165.   for (i = 0; i < MAX_LIGHTS; i++) {
  166.     GLfloat dx, dy, dz;
  167.     GLfloat quadraticAttenuation;
  168.     /* Calculate object to light position vector. */
  169.     dx = (linfo[i].xyz[0] - x);
  170.     dy = (linfo[i].xyz[1] - y);
  171.     dz = (linfo[i].xyz[2] - z);
  172.     quadraticAttenuation = dx * dx + dy * dy + dz * dz;
  173.     if (brightnessModel == M_LAMBERTIAN) {
  174.       /* Lambertian surface-based brightness determination. */
  175.       GLfloat ex, ey, ez;
  176.       GLfloat nx, ny, nz;
  177.       GLfloat distance;
  178.       GLfloat diffuseReflection;
  179.       /* Determine eye point location (remember we can rotate by angle). */
  180.       ex = 16.0 * sin(angle * M_PI / 180.0);
  181.       ey = 1.0;
  182.       ez = 16.0 * -cos(angle * M_PI / 180.0);
  183.       /* Calculated normalized object to eye position direction (nx,ny,nz). */
  184.       nx = (ex - x);
  185.       ny = (ey - y);
  186.       nz = (ez - z);
  187.       distance = sqrt(nx * nx + ny * ny + nz * nz);
  188.       nx = nx / distance;
  189.       ny = ny / distance;
  190.       nz = nz / distance;
  191.       /* True distance needed, take square root. */
  192.       distance = sqrt(quadraticAttenuation);
  193.       /* Calculate normalized object to light postition direction (dx,dy,dz). 
  194.        */
  195.       dx = dx / distance;
  196.       dy = dy / distance;
  197.       dz = dz / distance;
  198.       /* Dot product of object->eye and object->light source directions.
  199.          OpenGL's lighting equations actually force the diffuse contribution
  200.          to be zero if the dot product is less than zero.  For our purposes,
  201.          that's too strict since we are approximating the entire object with
  202.          a single object-to-eye normal. */
  203.       diffuseReflection = nx * dx + ny * dy + nz * dz;
  204.       if (attenuation == M_QUAD) {
  205.         /* Attenuate based on square of distance. */
  206.         ld[i].brightness = diffuseReflection / quadraticAttenuation;
  207.       } else {
  208.         /* Attenuate based on linear distance. */
  209.         ld[i].brightness = diffuseReflection / distance;
  210.       }
  211.     } else {
  212.       /* Distance-based brightness determination. */
  213.       /* In theory, we are really determining brightness based on just the
  214.          linear distance of the light source, but since we are just doing
  215.          comparisons, there is no reason to waste time doing a square root. */
  216.       /* Negation makes sure closer distances are "bigger" than further
  217.          distances for sorting. */
  218.       ld[i].brightness = -quadraticAttenuation;
  219.     }
  220.     ld[i].num = i;
  221.   }
  222.   /* Sort the lights so that the "brightest" are listed first.  We really
  223.      want to just determine the first numActiveLights so a full sort is
  224.      overkill. */
  225.   qsort(ld, MAX_LIGHTS, sizeof(ld[0]), lightBrightnessCompare);
  226.   if (reportLightSignificance) {
  227.     printf("n");
  228.     for (i = 0; i < MAX_LIGHTS; i++) {
  229.       printf("%d: dist = %gn", ld[i].num, ld[i].brightness);
  230.     }
  231.   }
  232.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  233.   glPushMatrix();
  234.   glRotatef(angle, 0.0, 1.0, 0.0);
  235.   glDisable(GL_LIGHTING);
  236.   for (i = 0; i < MAX_LIGHTS; i++) {
  237.     drawLight(&linfo[i]);
  238.   }
  239.   /* After sorting, the first numActiveLights (ie, <8) light sources are the
  240.      light sources with the biggest contribution to the object's lighting.
  241.      Assign these "virtual lights of significance" to OpenGL's actual
  242.      available light sources. */
  243.   glEnable(GL_LIGHTING);
  244.   for (i = 0; i < numActiveLights; i++) {
  245.     if (lightState[i]) {
  246.       int num = ld[i].num;
  247.       glLightfv(GL_LIGHT0 + i, GL_POSITION, linfo[num].xyz);
  248.       glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, linfo[num].rgb);
  249.       glEnable(GL_LIGHT0 + i);
  250.     } else {
  251.       glDisable(GL_LIGHT0 + i);
  252.     }
  253.   }
  254.   glPushMatrix();
  255.   glTranslatef(x, y, z);
  256.   switch (object) {
  257.   case M_SPHERE:
  258.     glCallList(DL_BIG_SPHERE);
  259.     break;
  260.   case M_ICO:
  261.     glCallList(DL_ICO);
  262.     break;
  263.   }
  264.   glPopMatrix();
  265.   if (labelLights) {
  266.     glDisable(GL_DEPTH_TEST);
  267.     glDisable(GL_LIGHTING);
  268.     for (i = 0; i < numActiveLights; i++) {
  269.       labelLight(&linfo[ld[i].num], i);
  270.     }
  271.     glEnable(GL_DEPTH_TEST);
  272.   }
  273.   glPopMatrix();
  274.   if (timeFrames) {
  275.     glFinish();
  276.     end = glutGet(GLUT_ELAPSED_TIME);
  277.     printf("Speed %.3g frames/sec (%d ms)n",
  278.       1000.0 / (end - start), end - start);
  279.   }
  280.   if (!singleBuffer) {
  281.     glutSwapBuffers();
  282.   }
  283. }
  284. void
  285. idle(void)
  286. {
  287.   t += 0.005;
  288.   glutPostRedisplay();
  289. }
  290. /* When not visible, stop animating.  Restart when visible again. */
  291. static void
  292. visible(int vis)
  293. {
  294.   if (vis == GLUT_VISIBLE) {
  295.     if (animation)
  296.       glutIdleFunc(idle);
  297.   } else {
  298.     if (!animation)
  299.       glutIdleFunc(NULL);
  300.   }
  301. }
  302. /* Press any key to redraw; good when motion stopped and performance
  303.    reporting on. */
  304. /* ARGSUSED */
  305. static void
  306. key(unsigned char c, int x, int y)
  307. {
  308.   int i;
  309.   switch (c) {
  310.   case 27:
  311.     exit(0);            /* IRIS GLism, Escape quits. */
  312.     break;
  313.   case ' ':
  314.     animation = 1 - animation;
  315.     if (animation)
  316.       glutIdleFunc(idle);
  317.     else
  318.       glutIdleFunc(NULL);
  319.     break;
  320.   case '0':
  321.   case '1':
  322.   case '2':
  323.   case '3':
  324.   case '4':
  325.   case '5':
  326.   case '6':
  327.   case '7':
  328.     lightState[c - '0'] = 1 - lightState[c - '0'];
  329.     break;
  330.   case 13:
  331.     for (i = 0; i < numActiveLights; i++) {
  332.       lightState[i] = 1;
  333.     }
  334.     break;
  335.   }
  336.   glutPostRedisplay();
  337. }
  338. /* ARGSUSED3 */
  339. void
  340. mouse(int button, int state, int x, int y)
  341. {
  342.   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  343.     moving = 1;
  344.     begin = x;
  345.   }
  346.   if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
  347.     moving = 0;
  348.   }
  349. }
  350. /* ARGSUSED1 */
  351. void
  352. motion(int x, int y)
  353. {
  354.   if (moving) {
  355.     angle = angle + (x - begin);
  356.     begin = x;
  357.     glutPostRedisplay();
  358.   }
  359. }
  360. void
  361. menu(int value)
  362. {
  363.   int i;
  364.   switch (value) {
  365.   case M_SPHERE:
  366.     object = M_SPHERE;
  367.     break;
  368.   case M_ICO:
  369.     object = M_ICO;
  370.     break;
  371.   case M_LABELS:
  372.     labelLights = 1 - labelLights;
  373.     break;
  374.   case M_LINEAR:
  375.   case M_QUAD:
  376.     attenuation = value;
  377.     for (i = 0; i < numActiveLights; i++) {
  378.       initLight(i);
  379.     }
  380.     break;
  381.   case M_REPORT_SIG:
  382.     reportLightSignificance = 1 - reportLightSignificance;
  383.     break;
  384.   case M_LAMBERTIAN:
  385.     brightnessModel = M_LAMBERTIAN;
  386.     glutSetWindowTitle("multilight (Lambertian-based)");
  387.     break;
  388.   case M_DISTANCE:
  389.     brightnessModel = M_DISTANCE;
  390.     glutSetWindowTitle("multilight (Distance-based)");
  391.     break;
  392.   case M_TIME:
  393.     timeFrames = 1 - timeFrames;
  394.     break;
  395.   case 666:
  396.     exit(0);
  397.   }
  398.   glutPostRedisplay();
  399. }
  400. int
  401. main(int argc, char **argv)
  402. {
  403.   int i;
  404.   glutInitWindowSize(400, 200);
  405.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
  406.   glutInit(&argc, argv);
  407.   for (i = 1; i < argc; i++) {
  408.     if (!strcmp("-sb", argv[i])) {
  409.       glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE);
  410.       singleBuffer = 1;
  411.     }
  412.   }
  413.   glutCreateWindow("multilight");
  414.   glClearColor(0.0, 0.0, 0.0, 0.0);
  415.   glMatrixMode(GL_PROJECTION);
  416.   gluPerspective(50.0, 2.0, 0.1, 100.0);
  417.   glMatrixMode(GL_MODELVIEW);
  418.   gluLookAt(
  419.     0.0, 1.0, -16.0,
  420.     0.0, 0.0, 0.0,
  421.     0.0, 1.0, 0.);
  422.   numActiveLights = MIN_VALUE(MAX_LIGHTS, 8);
  423.   for (i = 0; i < numActiveLights; i++) {
  424.     initLight(i);
  425.   }
  426.   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, modelAmb);
  427.   glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
  428.   glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
  429.   glEnable(GL_CULL_FACE);
  430.   glEnable(GL_DEPTH_TEST);
  431.   glMaterialfv(GL_FRONT, GL_AMBIENT, matAmb);
  432.   glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiff);
  433.   glMaterialfv(GL_FRONT, GL_SPECULAR, matSpec);
  434.   glMaterialfv(GL_FRONT, GL_EMISSION, matEmission);
  435.   glMaterialf(GL_FRONT, GL_SHININESS, 10.0);
  436.   glNewList(DL_LIGHT_SPHERE, GL_COMPILE);
  437.   glutSolidSphere(0.2, 4, 4);
  438.   glEndList();
  439.   glNewList(DL_BIG_SPHERE, GL_COMPILE);
  440.   glutSolidSphere(1.5, 20, 20);
  441.   glEndList();
  442.   glNewList(DL_ICO, GL_COMPILE);
  443.   glutSolidIcosahedron();
  444.   glEndList();
  445.   glutDisplayFunc(display);
  446.   glutVisibilityFunc(visible);
  447.   glutKeyboardFunc(key);
  448.   glutMouseFunc(mouse);
  449.   glutMotionFunc(motion);
  450.   glutCreateMenu(menu);
  451.   glutAddMenuEntry("Sphere", M_SPHERE);
  452.   glutAddMenuEntry("Icosahedron", M_ICO);
  453.   glutAddMenuEntry("Linear attenuation", M_LINEAR);
  454.   glutAddMenuEntry("Quadratic attenuation", M_QUAD);
  455.   glutAddMenuEntry("Toggle Light Number Labels", M_LABELS);
  456.   glutAddMenuEntry("Report Light Significance", M_REPORT_SIG);
  457.   glutAddMenuEntry("Lambertian-based Significance", M_LAMBERTIAN);
  458.   glutAddMenuEntry("Distance-based Significance", M_DISTANCE);
  459.   glutAddMenuEntry("Time Frames", M_TIME);
  460.   glutAddMenuEntry("Quit", 666);
  461.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  462.   glutMainLoop();
  463.   return 0;             /* ANSI C requires main to return int. */
  464. }