home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / csg / csg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  15.4 KB  |  511 lines

  1. /*
  2.  * Copyright 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*  csg.c
  18.  *
  19.  *  demos implementation of boolean operations with stencil planes.
  20.  *
  21.  *  csg.c draws a CSG object - a cube with a hole drilled through the
  22.  *  center.  The stencil planes are used to determine where the cube
  23.  *  should be drawn and where the cylinder should be drawn.
  24.  *  There are several things to bear in mind.  The cube is drawn
  25.  *  "normally"; that is, with its back faces removed.  The cylinder is
  26.  *  subtracted from the cube, so only its BACK faces will show.  Also,
  27.  *  the cube is NOT drawn wherever it is inside the cylinder.  The stencil
  28.  *  planes and the z-buffer are used together to figure out where the
  29.  *  cube is inside the cylinder.
  30.  */
  31.  
  32. #include <gl/gl.h>
  33. #include <gl/device.h>
  34. #include <stdio.h>
  35. #include <math.h>
  36.  
  37.  
  38. void def_simple_light_calc(void);
  39. void use_simple_light_calc(void);
  40. void main(void);
  41. void initialize(void);
  42. void drawscene(void);
  43. void scrrect(void);
  44. void fcube(void);
  45.  
  46.  
  47. float red_material[] = {
  48.         DIFFUSE,        0.8, 0.0, 0.0,
  49.         SPECULAR,        1.0, 1.0, 1.0,
  50.         SHININESS, 128.0,
  51.         LMNULL };
  52.  
  53. float shiny_material[] = {
  54.         DIFFUSE,        0.4, 0.4, 0.0,
  55.         SPECULAR,        1.0, 1.0, 1.0,
  56.         SHININESS, 128.0,
  57.         LMNULL };
  58.  
  59. float blue_material[] = {
  60.         AMBIENT,        0.4, 0.4, 0.4,
  61.         DIFFUSE,        0.0, 0.0, 1.0,
  62.         SPECULAR,        0.0, 1.0, 1.0,
  63.         SHININESS, 45.0,
  64.         LMNULL };
  65.  
  66. float two_side[] = {
  67.         TWOSIDE, 1.0,
  68.         LMNULL };
  69.  
  70. void
  71. def_simple_light_calc(void){
  72.         lmdef(DEFMATERIAL, 1, 11, shiny_material);
  73.         lmdef(DEFMATERIAL, 2, 15, blue_material);
  74.         lmdef(DEFMATERIAL, 3, 11, red_material);
  75.         lmdef(DEFLIGHT, 1, 0, NULL);
  76.         lmdef(DEFLMODEL, 1, 3, two_side);
  77. }
  78.  
  79. void
  80. use_simple_light_calc(void){
  81.         lmbind(LIGHT0, 1);
  82.         lmbind(LMODEL, 1);
  83. }
  84.  
  85.  
  86.  
  87. /* default cube size */
  88. #define CUBE_X 1.0
  89. #define CUBE_Y 1.0
  90. #define CUBE_Z 1.0
  91.  
  92. /* three dimensional vector */
  93. typedef float vector[3];
  94.  
  95. /* cube vectors */
  96. static vector front  = { 0.0,  0.0,  1.0};
  97. static vector back   = { 0.0,  0.0, -1.0};
  98. static vector top    = { 0.0,  1.0,  0.0};
  99. static vector bottom = { 0.0, -1.0,  0.0};
  100. static vector right  = { 1.0,  0.0,  0.0};
  101. static vector left   = {-1.0,  0.0,  0.0};
  102. static vector center = { 0.0,  0.0,  0.0};
  103.  
  104. /* array for cube vertices */
  105. static vector cube_point[8];
  106.  
  107. /* has the cube been initialized */
  108. static Boolean cube_initialized = FALSE;
  109.  
  110. void setcube(float x, float y, float z)
  111. {
  112.     cube_point[1][0] = cube_point[2][0] = 
  113.         cube_point[5][0] = cube_point[6][0] = x/2.0;
  114.         
  115.     cube_point[0][0] = cube_point[3][0] = 
  116.         cube_point[4][0] = cube_point[7][0] = -x/2.0;
  117.         
  118.     cube_point[2][1] = cube_point[3][1] = 
  119.         cube_point[6][1] = cube_point[7][1] = y/2.0;
  120.         
  121.     cube_point[0][1] = cube_point[1][1] = 
  122.         cube_point[4][1] = cube_point[5][1] = -y/2.0;
  123.         
  124.     cube_point[0][2] = cube_point[1][2] = 
  125.         cube_point[2][2] = cube_point[3][2] = z/2.0;
  126.         
  127.     cube_point[4][2] = cube_point[5][2] = 
  128.         cube_point[6][2] = cube_point[7][2] = -z/2.0;
  129.  
  130.     cube_initialized = TRUE;
  131. }
  132.  
  133. /* filled cube */
  134. void fcube(void)
  135. {
  136.     if (! cube_initialized)
  137.             setcube(CUBE_X, CUBE_Y, CUBE_Z);
  138.  
  139.         /* draw bottom facing polygon */
  140.     bgnpolygon();
  141.             n3f(bottom);
  142.             v3f(cube_point[4]);
  143.             v3f(cube_point[5]);
  144.             v3f(cube_point[1]);
  145.             v3f(cube_point[0]);
  146.     endpolygon();
  147.  
  148.         /* draw left facing polygon */
  149.     bgnpolygon();
  150.             n3f(left);
  151.             v3f(cube_point[3]);
  152.             v3f(cube_point[7]);
  153.             v3f(cube_point[4]);
  154.             v3f(cube_point[0]);
  155.     endpolygon();
  156.  
  157.         /* draw right facing polygon */
  158.     bgnpolygon();
  159.             n3f(right);
  160.             v3f(cube_point[5]);
  161.             v3f(cube_point[6]);
  162.             v3f(cube_point[2]);
  163.             v3f(cube_point[1]);
  164.     endpolygon();
  165.  
  166.         /* draw top facing polygon */
  167.     bgnpolygon();
  168.             n3f(top);
  169.             v3f(cube_point[6]);
  170.             v3f(cube_point[7]);
  171.             v3f(cube_point[3]);
  172.             v3f(cube_point[2]);
  173.     endpolygon();
  174.  
  175.         /* draw front facing polygon */   
  176.     bgnpolygon();
  177.             n3f(front);
  178.             v3f(cube_point[1]);
  179.             v3f(cube_point[2]);
  180.             v3f(cube_point[3]);
  181.             v3f(cube_point[0]);
  182.     endpolygon();
  183.  
  184.         /* draw back facing polygon */
  185.     bgnpolygon();
  186.             n3f(back);
  187.             v3f(cube_point[6]);
  188.             v3f(cube_point[5]);
  189.             v3f(cube_point[4]);
  190.             v3f(cube_point[7]);
  191.     endpolygon();
  192. }
  193.  
  194.  
  195.  
  196. /* number of polygons around the cross section of the cylinder */
  197. #define CYL_NUMC 20
  198.  
  199. /* number of polygons down the length of the cylinder */
  200. #define CYL_NUML 10
  201.  
  202. /* arrays for torus vertices and normals */
  203. static vector cyl_point[CYL_NUMC][CYL_NUML+1];
  204. static vector cyl_norm[CYL_NUMC][CYL_NUML+1];
  205.  
  206. /* has the cylinder been initialized */
  207. static Boolean cylinder_initialized = FALSE;
  208.  
  209.  
  210. /* initialize a cylinder */
  211. static void initcylinder(
  212.         vector point[CYL_NUMC][CYL_NUML+1],        /* array of vertex data */
  213.         vector norm[CYL_NUMC][CYL_NUML+1])        /* array of normal data */
  214. {
  215.         int i,j;
  216.         float theta,nx,ny;
  217.         int numc = CYL_NUMC, numl = CYL_NUML;
  218.         
  219.         for (i = 0; i < numc; i++) {
  220.                 theta = 2.0*M_PI*(float)i/(float)numc;
  221.  
  222.                 nx = fcos(theta);
  223.                 ny = fsin(theta);
  224.                 
  225.                 for (j = 0; j <= numl; j++) {
  226.                         point[i][j][0] = nx;
  227.                         point[i][j][1] = ny;
  228.                         point[i][j][2] =(float)j/(float)numl - .5;
  229.  
  230.                         norm[i][j][0] = nx;
  231.                         norm[i][j][1] = ny;
  232.                         norm[i][j][2] = 0.0;
  233.                 }
  234.         }
  235. }
  236.  
  237.  
  238. /* wireframe cylinder */
  239. void wcylinder(void)
  240. {
  241.         int i,j;
  242.         int numc = CYL_NUMC, numl = CYL_NUML;
  243.  
  244.         if (! cylinder_initialized) {
  245.                 initcylinder(cyl_point,cyl_norm);
  246.                 cylinder_initialized = TRUE;
  247.         }
  248.         
  249.         for (i = 0; i < numl; i++)
  250.                 for (j = 0; j < numc; j++) {
  251.                         bgnclosedline();
  252.                                 v3f(cyl_point[j][i]);
  253.                                 v3f(cyl_point[(j+1)%numc][i]);
  254.                                 v3f(cyl_point[j][i+1]);
  255.                         endclosedline();
  256.                         
  257.                         bgnclosedline();
  258.                                 v3f(cyl_point[(j+1)%numc][i]);
  259.                                 v3f(cyl_point[j][i+1]);
  260.                                 v3f(cyl_point[(j+1)%numc][i+1]);
  261.                         endclosedline();
  262.                 }
  263. }
  264.  
  265. /* filled cylinder */
  266. void fcylinder(void)
  267. {
  268.         int i,j;
  269.         int numc = CYL_NUMC, numl = CYL_NUML;
  270.  
  271.         if (! cylinder_initialized) {
  272.                 initcylinder(cyl_point,cyl_norm);
  273.                 cylinder_initialized = TRUE;
  274.         }
  275.  
  276.         for (i = 0; i < numc; i++) {
  277.             bgntmesh();
  278.                 n3f(cyl_norm[i][0]);
  279.                 v3f(cyl_point[i][0]);
  280.                 for (j = 0; j < numl; j++) {
  281.                             n3f(cyl_norm[(i+1)%numc][j]);
  282.                             v3f(cyl_point[(i+1)%numc][j]);
  283.                             n3f(cyl_norm[i][j+1]);
  284.                             v3f(cyl_point[i][j+1]);
  285.                 }
  286.                 n3f(cyl_norm[(i+1)%numc][numl]);
  287.                 v3f(cyl_point[(i+1)%numc][numl]);
  288.             endtmesh();
  289.         }
  290. }
  291.  
  292. void
  293. main(void)
  294. {
  295.         short attached;
  296.         short value;
  297.         int dev;
  298.  
  299.         attached = TRUE;
  300.  
  301.         if (getgdesc(GD_BITS_STENCIL) < 8)
  302.         {
  303.                 fprintf(stderr, "This machine does not have enough stencil planes for this program.\n");
  304.                 exit(0);
  305.         }
  306.  
  307.         initialize();
  308.  
  309.         while (TRUE)
  310.         {
  311.                 while (qtest() || !attached)
  312.                 {
  313.                         dev = qread (&value);
  314.                         if ((dev == ESCKEY) && (value == 0))
  315.                                 exit(0);
  316.                         else if (dev == REDRAW)
  317.                         {
  318.                                 reshapeviewport();
  319.                                 drawscene();
  320.                         }
  321.                         else if (dev == INPUTCHANGE)
  322.                                 attached = value;        
  323.                 }        /*  end while qtest or not attached  */
  324.                 drawscene();
  325.         }        /*  end while (TRUE)  */
  326. }        /*  end main()  */
  327.  
  328. /*        The initialize subroutine positions the window and specifies
  329.  *        its future constraints.  The program is in double buffer
  330.  *        and RGB mode.  The simplest lighting model is used.
  331.  */ 
  332. void
  333. initialize(void)
  334. {
  335.         long gid1;
  336.         long xmax, ymax;
  337.  
  338.         xmax = getgdesc(GD_XPMAX);
  339.         ymax = getgdesc(GD_YPMAX);
  340.         prefposition( xmax/4, xmax*3/4, ymax/4, ymax*3/4 );
  341.         gid1 = winopen ("stencil");
  342.         minsize (xmax/10, ymax/10);
  343.         keepaspect (xmax, ymax);
  344.         winconstraints();
  345.  
  346.         doublebuffer();
  347.         RGBmode();
  348.         stensize ( 8 );
  349.         gconfig();
  350.         zbuffer(TRUE);
  351.         subpixel(TRUE);
  352.  
  353.         qdevice (ESCKEY);
  354.         qenter (REDRAW, gid1);
  355.  
  356.         mmode(MVIEWING);
  357.         perspective( 450, (float)xmax/(float)ymax, 0.99, 10.0);
  358.         lookat(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0);
  359.  
  360.         def_simple_light_calc();
  361.         use_simple_light_calc();
  362.  
  363. }
  364.  
  365. /*
  366.  *  The drawscene routine does the CSG.  The basic algorithm is as 
  367.  *  follows:  
  368.  *                Turn off drawing.
  369.  *                Render the cube's z-values into the z-buffer planes.
  370.  *                Use the stencil and the z-buffer comparison hardware
  371.  *                  to count how many times the cylinder is drawn in
  372.  *                  front of the cube.
  373.  *                Wherever exactly one face of the cylinder is in front
  374.  *                  of the cube (in other words, the cube is between
  375.  *                  or inside the cylinder), force z-values to the
  376.  *                  largest possible z, because these pixels are inside
  377.  *                  the hole in the cube.
  378.  *                Render the cube's back faces into this hole as needed (to
  379.  *                  clip the back of the cylinder).
  380.  *                Render the cylinder's z-values into this hole as needed.
  381.  *                Turn drawing on.
  382.  *                Render the cube and cylinder where their z-values equal
  383.  *                  the values in the z-buffer planes.
  384.  */
  385. void
  386. drawscene(void)
  387. {
  388.         czclear(0x0, getgdesc(GD_ZMAX));
  389.         sclear(0);
  390.         pushmatrix();
  391.                 rot(15.0, 'y');
  392.  
  393.                 /* turn color planes off until we're ready to draw */
  394.                 wmpack(0);
  395.         
  396.                 /* render the cube into the z planes */
  397.                 frontface (FALSE);
  398.                 backface(TRUE);
  399.                 zfunction(ZF_LEQUAL);
  400.                 fcube();
  401.         
  402.                 /* use the z-buffer comparison hardware to
  403.                 increment the stencil planes wherever either face of
  404.                 the cylinder is in front of the cube (the z-test 
  405.                 passes), but don't update the z-buffer planes */
  406.  
  407.                 stencil( TRUE, 0, SF_ALWAYS, 0xFF, 
  408.                 ST_KEEP, ST_KEEP, ST_INCR );
  409.                 zwritemask(0);
  410.                 frontface (FALSE);
  411.                 backface(FALSE);
  412.                 pushmatrix();
  413.                         scale(0.2, 0.2, 12.0);
  414.                         fcylinder();
  415.                 popmatrix();
  416.                 zwritemask(0xFFFFFF);
  417.         
  418.                 /* force z-values to infinity wherever the cube is inside the
  419.                 cylinder (wherever the stencil planes have a value of one */
  420.                 zfunction(ZF_ALWAYS);
  421.                 stencil( TRUE, 0x1, SF_EQUAL, 0xFF, 
  422.                 ST_KEEP, ST_KEEP, ST_KEEP );
  423.                 scrrect();
  424.         
  425.                 /* render back faces of cube into z planes where the hole
  426.                 is (the stencil test is still active).  This will
  427.                 keep the cylinder from sticking out the back. */
  428.                 backface (FALSE);
  429.                 frontface (TRUE);
  430.                 zfunction(ZF_LEQUAL);
  431.                 fcube();
  432.         
  433.                 /* render back faces of cylinder into z-buffer planes wherever 
  434.                 stencil planes are 1 and z passes */
  435.  
  436.                 stencil( TRUE, 0x1, SF_EQUAL, 0xFF, 
  437.                 ST_KEEP, ST_KEEP, ST_KEEP );
  438.                 pushmatrix();
  439.                         scale(0.2, 0.2, 12.0);
  440.                         fcylinder();
  441.                 popmatrix();
  442.         
  443.                 /* now draw - turn color planes on and set up z test to pass only
  444.                 if the incoming z equals the stored z.  Turn off the
  445.                 stencil test. */
  446.  
  447.                 stencil( FALSE, 0x0, SF_ALWAYS, 0xFF, 
  448.                 ST_KEEP, ST_KEEP, ST_KEEP );
  449.                 zfunction (ZF_EQUAL);
  450.                 wmpack(0xFFFFFF);
  451.                 frontface (FALSE);
  452.                 backface (TRUE);
  453.                 lmbind(MATERIAL, 1);
  454.                 lmbind(BACKMATERIAL, 3);
  455.                 fcube();
  456.         
  457.                 /* draw the BACK faces of the cylinder because we want
  458.                 to see the inside of it. */
  459.                 backface (FALSE);
  460.                 frontface (TRUE);
  461.                 pushmatrix();
  462.                         scale(0.2, 0.2, 12.0);
  463.                         lmbind(MATERIAL, 2);
  464.                         lmbind(BACKMATERIAL, 3);
  465.                         fcylinder();
  466.                 popmatrix();
  467.  
  468.         popmatrix();
  469.         swapbuffers();
  470. }
  471.  
  472. /*
  473.  *  scrrect()
  474.  *
  475.  *  This routine forces the z-values of whatever it draws to
  476.  *  be getgdesc(GD_ZMAX).  Then it draws a big polygon.  Effectively,
  477.  *  this routine clears the z-values of every pixel it draws into to
  478.  *  the maximum z value.  Since it does this by drawing a polygon
  479.  *  rather than calling zclear, it is affected by the current
  480.  *  stencil test.  Thus in this program, it clears the cube's
  481.  *  z-values out of the z-buffer planes wherever the cube is
  482.  *  inside the cylinder (see the call to stencil which precedes
  483.  *  the call to scrrect in the drawscene routine).
  484.  */
  485.  
  486. static Matrix Identity = {
  487.         {1.,0.,0.,0.},
  488.         {0.,1.,0.,0.},
  489.         {0.,0.,1.,0.},
  490.         {0.,0.,0.,1.}}; 
  491.  
  492. void
  493. scrrect(void)
  494. {
  495.         static long verts[4][2] = {{-10,-10},{10,-10},{10,10},{-10,10}};
  496.  
  497.         pushmatrix();
  498.         loadmatrix(Identity);
  499.         translate(0., 0., -1.);
  500.         lsetdepth(getgdesc(GD_ZMAX), getgdesc(GD_ZMAX));
  501.         bgnpolygon();
  502.                 v2i (verts[0]);
  503.                 v2i (verts[1]);
  504.                 v2i (verts[2]);
  505.                 v2i (verts[3]);
  506.         endpolygon(); 
  507.  
  508.         lsetdepth(getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
  509.         popmatrix();
  510. }
  511.