home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / mesa-1.2.8 / demos / shadow.c < prev    next >
C/C++ Source or Header  |  1996-05-27  |  7KB  |  311 lines

  1. /* shadow.c */
  2.  
  3. /*
  4.  * Use the stencil buffer to generate shadows.  This demo inspired by
  5.  * an article in IRIS Universe Magazine, No. 18.  This program is in
  6.  * the public domain.
  7.  *
  8.  * Brian Paul
  9.  */
  10.  
  11.  
  12.  
  13. #include <math.h>
  14. #include "gltk.h"
  15.  
  16.  
  17.  
  18. static GLfloat light_pos[4] = { 0.0, 10.0, 0.0, 1.0 };
  19. static GLfloat view_rotx, view_roty;
  20. static GLfloat ground_xrot, ground_yrot, ground_zrot;
  21. static GLfloat ground_y;
  22.  
  23.  
  24. /*
  25.  * These triangles cast the shadow.
  26.  */
  27.  
  28. #define NUM_TRI 4
  29.  
  30. static GLfloat triangle[NUM_TRI][3][3] = {
  31.     0.5, 4.0, 0.5,
  32.    -0.5, 4.0, 0.5,
  33.     0.0, 4.0, 2.0,
  34.  
  35.     0.5, 4.0, 0.5,
  36.     0.5, 4.0, -0.5,
  37.     2.0, 4.0, 0.0,
  38.  
  39.     0.5, 4.0, -0.5,
  40.     -0.5, 4.0, -0.5,
  41.     0.0, 4.0, -2.0,
  42.  
  43.     -0.5, 4.0, -0.5,
  44.     -0.5, 4.0,  0.5,
  45.     -2.0, 4.0,  0.0
  46. };
  47.  
  48.  
  49.  
  50. static void init( void )
  51. {
  52.    static GLfloat ambient[4] = {0.3, 0.3, 0.3, 1.0};
  53.  
  54.    view_rotx = 50.0;
  55.    view_roty = 20.0;
  56.  
  57.    ground_xrot = ground_yrot = ground_zrot = 0.0;
  58.    ground_y = 0.0;
  59.  
  60.    glEnable( GL_DEPTH_TEST );
  61.    glDepthFunc( GL_LEQUAL );
  62.    glShadeModel( GL_FLAT );
  63.    glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient );
  64.    glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
  65. }
  66.  
  67.  
  68.  
  69. /*
  70.  * Draw the whole scene.  For each frame we'll call this function twice.
  71.  * The first time with just ambient lighting, the second time with ambient
  72.  * and point source lighting.
  73.  */
  74. static void draw_scene( void )
  75. {
  76.    static GLint ground = -1;
  77.    GLint i, j;
  78.    GLfloat x, y, z;
  79.  
  80.    glPushMatrix();
  81.    glRotatef( ground_xrot, 1.0, 0.0, 0.0 );
  82.    glRotatef( ground_yrot, 0.0, 1.0, 0.0 );
  83.    glRotatef( ground_zrot, 0.0, 0.0, 1.0 );
  84.    glTranslatef( 0.0, ground_y, 0.0 );
  85.  
  86.    if (ground==-1) {
  87.       /* make the ground checkerboard */
  88.       ground = glGenLists(1);
  89.       glNewList( ground, GL_COMPILE_AND_EXECUTE );
  90.       for (i=0;i<5;i++) {
  91.      for (j=0;j<5;j++) {
  92.         if ((i+j)%2) {
  93.            glColor3f( 0.0, 1.0, 0.0 );
  94.         }
  95.         else {
  96.            glColor3f( 0.0, 0.0, 1.0 );
  97.         }
  98.         glNormal3f( 0.0, 1.0, 0.0 );
  99.         x = i*2.0 - 5.0;
  100.         y = 0.0;
  101.         z = j*2.0 - 5.0;
  102.         glBegin( GL_POLYGON );
  103.         glVertex3f( x,     y, z+2.0 );
  104.         glVertex3f( x+2.0, y, z+2.0 );
  105.         glVertex3f( x+2.0, y, z );
  106.         glVertex3f( x,     y, z );
  107.         glEnd();
  108.      }
  109.       }
  110.       glEndList();
  111.    }
  112.    else {
  113.       /* draw ground checkerboard */
  114.       glCallList( ground );
  115.    }
  116.  
  117.    glPopMatrix();
  118.  
  119.    /* draw triangles */
  120.    glColor3f( 1.0, 0.0, 0.0 );
  121.    glNormal3f( 0.0, 1.0, 0.0 );
  122.    glBegin( GL_TRIANGLES );
  123.    for (i=0;i<NUM_TRI;i++) {
  124.       glVertex3fv( triangle[i][0] );
  125.       glVertex3fv( triangle[i][1] );
  126.       glVertex3fv( triangle[i][2] );
  127.    }
  128.    glEnd();
  129. }
  130.  
  131.  
  132.  
  133. /*
  134.  * For each triangle in triangle list:
  135.  *    For each edge of triangle:
  136.  *       Construct a shadow volume boundary polygon by extending an edge away
  137.  *         from the light source for an arbitrary distance.
  138.  *       Draw the boundary polygon into the stencil planes, with invert
  139.  *         stencil op, do depth test but don't update depth buffer.
  140.  * When finished, where stencil buffer = 1 we're in a shadow.
  141.  */
  142. static void draw_shadow_volumes( void )
  143. {
  144.    GLint tri;
  145.    GLint i, j;
  146.    GLfloat v0[3], v1[3];
  147.    GLfloat p0[3], p1[3], p2[3], p3[3];
  148.  
  149.    for (tri=0;tri<NUM_TRI;tri++) {
  150.  
  151.       /* loop over triangle edges */
  152.       for (i=0;i<3;i++) {
  153.      j = (i+1) % 3;
  154.      /* v0 = vector from light to vertex i */
  155.      v0[0] = triangle[tri][i][0] - light_pos[0];
  156.      v0[1] = triangle[tri][i][1] - light_pos[1];
  157.      v0[2] = triangle[tri][i][2] - light_pos[2];
  158.      /* v1 = vector from light to vertex i+1 */
  159.      v1[0] = triangle[tri][j][0] - light_pos[0];
  160.      v1[1] = triangle[tri][j][1] - light_pos[1];
  161.      v1[2] = triangle[tri][j][2] - light_pos[2];
  162.  
  163.      /* compute vertices of shadow volume boundary side */
  164.      p0[0] = triangle[tri][i][0];
  165.      p0[1] = triangle[tri][i][1];
  166.      p0[2] = triangle[tri][i][2];
  167.  
  168.      p1[0] = triangle[tri][j][0];
  169.      p1[1] = triangle[tri][j][1];
  170.      p1[2] = triangle[tri][j][2];
  171.  
  172.      p2[0] = p1[0] + v1[0] * 10.0;
  173.      p2[1] = p1[1] + v1[1] * 10.0;
  174.      p2[2] = p1[2] + v1[2] * 10.0;
  175.  
  176.      p3[0] = p0[0] + v0[0] * 10.0;
  177.      p3[1] = p0[1] + v0[1] * 10.0;
  178.      p3[2] = p0[2] + v0[2] * 10.0;
  179.  
  180.      /* draw the shadow volume boundary polygon */
  181.      glBegin( GL_POLYGON );
  182.      glVertex3fv( p0 );
  183.      glVertex3fv( p1 );
  184.      glVertex3fv( p2 );
  185.      glVertex3fv( p3 );
  186.      glEnd();
  187.       }
  188.    }
  189. }
  190.  
  191.  
  192.  
  193. static void draw( void )
  194. {
  195.    /* clear the buffers */
  196.    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT
  197.         | GL_STENCIL_BUFFER_BIT );
  198.  
  199.    /* transform by the view angle */
  200.    glPushMatrix();
  201.    glRotatef( view_rotx, 1.0, 0.0, 0.0 );
  202.    glRotatef( view_roty, 0.0, 0.0, 1.0 );
  203.  
  204.    glLightfv( GL_LIGHT0, GL_POSITION, light_pos );
  205.  
  206.    /* Draw scene with ambient lighting only */
  207.    glEnable( GL_LIGHTING );
  208.    glDisable( GL_LIGHT0 );
  209.    glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT );
  210.    glEnable( GL_COLOR_MATERIAL );
  211.    draw_scene();
  212.  
  213.    /* Draw shadow volumes */
  214.    glDisable( GL_LIGHTING );
  215.    glStencilFunc( GL_ALWAYS, 0, 0xffffffff );
  216.    glStencilOp( GL_KEEP, GL_KEEP, GL_INVERT );
  217.    glEnable( GL_STENCIL_TEST );
  218.    glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
  219.    glDepthMask( GL_FALSE );
  220.    draw_shadow_volumes();
  221.  
  222.    /* Draw scene with point sources where stencil==0 only */
  223.    glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
  224.    glDepthMask( GL_TRUE );
  225.    glEnable( GL_LIGHT0 );
  226.    glEnable( GL_LIGHTING );
  227.    glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
  228.    glEnable( GL_COLOR_MATERIAL );
  229.    glStencilFunc( GL_EQUAL, 0, 0xffffffff );   /* draw where stencil==0 */
  230.    glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
  231.    draw_scene();
  232.  
  233.    /* all done */
  234.    glDisable( GL_STENCIL_TEST );
  235.    glDisable( GL_LIGHT0 );
  236.  
  237.    glPopMatrix();
  238.  
  239.    glFlush();
  240.    tkSwapBuffers();
  241. }
  242.  
  243.  
  244.  
  245.  
  246. static void idle( void )
  247. {
  248.    ground_yrot -= 2.0;
  249.    ground_xrot = sin(ground_yrot*0.1) * 10.0;
  250.    ground_zrot = cos(ground_yrot*0.1) * 10.0;
  251.    ground_y = sin( ground_yrot*0.15) * 2.0;
  252.    draw();
  253. }
  254.  
  255.  
  256. /* change view angle, exit upon ESC */
  257. static GLenum key(int k, GLenum mask)
  258. {
  259.    switch (k) {
  260.       case TK_UP:
  261.          view_rotx += 5.0;
  262.      return GL_TRUE;
  263.       case TK_DOWN:
  264.          view_rotx -= 5.0;
  265.      return GL_TRUE;
  266.       case TK_LEFT:
  267.          view_roty += 5.0;
  268.      return GL_TRUE;
  269.       case TK_RIGHT:
  270.          view_roty -= 5.0;
  271.      return GL_TRUE;
  272.       case TK_ESCAPE:
  273.      tkQuit();
  274.    }
  275.    return GL_FALSE;
  276. }
  277.  
  278.  
  279. /* new window size or exposure */
  280. static void reshape( int width, int height )
  281. {
  282.    glViewport(0, 0, (GLint)width, (GLint)height);
  283.    glMatrixMode(GL_PROJECTION);
  284.    glLoadIdentity();
  285.    glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 50.0 );
  286.    glMatrixMode(GL_MODELVIEW);
  287.    glLoadIdentity();
  288.    glTranslatef( 0.0, 0.0, -35.0 );
  289. }
  290.  
  291.  
  292.  
  293. main()
  294. {
  295.    tkInitPosition(0, 0, 300, 300);
  296.    tkInitDisplayMode( TK_RGB | TK_DEPTH | TK_DOUBLE | TK_STENCIL | TK_DIRECT );
  297.  
  298.    if (tkInitWindow("Stencil Shadow") == GL_FALSE) {
  299.       tkQuit();
  300.    }
  301.  
  302.    init();
  303.  
  304.    tkExposeFunc( reshape );
  305.    tkReshapeFunc( reshape );
  306.    tkKeyDownFunc( key );
  307.    tkIdleFunc( idle );
  308.    tkDisplayFunc( draw );
  309.    tkExec();
  310. }
  311.