home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / x / gui / x3d.lha / x3d / x3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-08  |  102.8 KB  |  3,528 lines

  1. /*
  2.   Copyright 1992 Mark Spychalla
  3.  
  4.   Permission to use, copy, modify, distribute, and sell this software and
  5.   its documentation for any purpose is hereby granted without fee,
  6.   provided that the above copyright notice appear in all copies and that
  7.   both that copyright notice and this permission notice appear in
  8.   supporting documentation, and that the name of Mark Spychalla not be used
  9.   in advertising or publicity pertaining to distribution of the software
  10.   without specific, written prior permission.  Mark Spychalla makes no
  11.   representations about the suitability of this software for any purpose.
  12.   It is provided "as is" without express or implied warranty.
  13.  
  14.   Mark Spychalla disclaims all warranties with regard to this software,
  15.   including all implied warranties of merchantability and fitness, in no
  16.   event shall Mark Spychalla be liable for any special, indirect or
  17.   consequential damages or any damages whatsoever resulting from loss of use,
  18.   data or profits, whether in an action of contract, negligence or other
  19.   tortious action, arising out of or in connection with the use or performance
  20.   of this software.
  21. */
  22.  
  23.  
  24.  
  25. /*
  26.  
  27. NOTE ON X3D CODING STYLE:
  28.  
  29.    Don't think I usually code in the gerberized fashion that X3D demonstrates.
  30. X3D was written for speed at any cost.  My goal was to write the fastest 3D
  31. object viewer that I could, period.   Regular programs ought to be written
  32. with different goals in mind such as:
  33.  
  34. 1) A program has excellent documentation that ANYONE can read.
  35. 2) A program when released has no strange "features" or bugs.
  36. 3) A program is robust and handles ALL extreme and unusual cases.
  37. 4) A program is written in phases and modules with hard tests for each one.
  38. 5) A program is written for any user who doesn't need special knowledge
  39.    to use the program.
  40. 6) A program has well defined user requirements and functional specifications. 
  41. 7) A program is written with regard to future expansion and integreation
  42.    with other systems (portability). 
  43.  
  44. When programming following these additional principles make programs easier
  45. to maintain.
  46.  
  47. A) Choose variable names that accurately describes what the variable does/is.
  48. B) Write comments to inform someone faced with the task of modifying your code.
  49. C) Avoid excessive comments.  Write the code so that it says what it does.
  50. D) Follow a strict one-in, one-out flow of control structues except in the
  51.    case of fatal error conditions.
  52. E) Avoid using global variables.
  53. F) Do not cause side effects to variables that were not parameters to a
  54.    function.
  55. G) Have a single function perform a single purpose.
  56. H) Select a single indentation style and stick with it.
  57. I) Use a consistent naming convention. 
  58.  
  59. The following principles help me when I try optimizing code:
  60.  
  61. a) If optimizing, use a profiler to determine which sections of code most of
  62.    the time is spent in.  Spend most of your effort in the most used sections.
  63.    Don't bother optimizing a procedure using less than 10% of the time.
  64.  
  65. b) High level optimizations are far more effective than cycle shaving.
  66.    (e.g. use quick sort instead of optimizing a bubble sort.)
  67.  
  68. c) Be flexible in your approach to solving a problem.  List exactly what you
  69.    need as a result at a minimum.  Get rid of unnecessary assumptions.
  70.  
  71. d) Become familiar with sets of operations that are equivalent, or nearly so.
  72.    Learn the relative expense of basic operations.
  73.  
  74. e) If possible, be careful not to needlessly sacrifice significant readability
  75.    of the code for a cycle or two.
  76.  
  77. -- Spy
  78.  
  79. */
  80.  
  81. #include <stdio.h>
  82. #include <math.h>
  83. #include <X11/Xlib.h>
  84. #include <X11/Xatom.h>
  85. #include <X11/Xutil.h>
  86. #include <X11/X.h>
  87. #include "x3d.h"
  88.  
  89.  
  90.  
  91. static void sort(list, numPolys)
  92. polygon **list;
  93. int numPolys;
  94. /*****************************************************************************
  95.    Specialized quick sort for painter algorithm.
  96. *****************************************************************************/
  97. {
  98. polygon **v0, **v1, **v2, **v3, **v4, **v5, **v6, *poly;
  99. register int stackIndex, stackNotSet, length, start, end, high;
  100. float dist;
  101. int numPoints;
  102. StackElement stack[MAXSTACK];
  103. point **Point, **lastPoint;
  104.  
  105.    v0 = list;
  106.    v1 = &(list[numPolys]);
  107.  
  108. /* Set the key value to be the average of the vertices' distances */
  109.  
  110.    while(v0 < v1){
  111.       poly = *v0;
  112.       numPoints = poly->numPoints;
  113.       Point = poly->points;
  114.       lastPoint = Point + numPoints;
  115.       dist = 0.0;
  116.  
  117.       do{
  118.          dist += (*Point)->dist;
  119.          Point++;
  120.       }while(Point < lastPoint);
  121.  
  122.       poly->dist = dist / ((float)numPoints);
  123.       v0++;
  124.       }
  125.  
  126. /* Initialize for the qsort() */
  127.  
  128.    stackIndex = 1;
  129.    stackNotSet = 0;
  130.    start = 0;
  131.    end = numPolys - 1;
  132.  
  133. /* Do Qsort */
  134.  
  135.    while(stackIndex){
  136.  
  137.        if(stackNotSet){
  138.           start = stack[stackIndex].start;
  139.           end = stack[stackIndex].end;
  140.        }
  141.  
  142.        stackIndex--;
  143.        stackNotSet = 1;
  144.        length = end - start;
  145.  
  146. /* Big enough to qsort ? */
  147.  
  148.       if(length > STOP){
  149.          v1 = &(list[start]);
  150.          v2 = &(list[start + (length / 4)]);
  151.          v3 = &(list[start + (length / 2)]);
  152.          v4 = &(list[start + ((length * 3) / 4)]);
  153.          v5 = &(list[end]);
  154.          v6 = v1;
  155.  
  156.          median5(v1,v2,v3,v4,v5)
  157.  
  158.          *v0 = *v3;
  159.          *v3 = *v6;
  160.          *v6 = *v0;
  161.  
  162.          v1 = &(list[start + 1]);
  163.          v2 = &(list[end]);
  164.  
  165. /* Split */
  166.  
  167.          dist = (*v6)->dist;
  168.          while((*v2)->dist < dist) v2--;
  169.          while((*v1)->dist > dist) v1++;
  170.  
  171.          v5 = v0;
  172.  
  173.          while(v1 < v2){
  174.  
  175.             *v5 = *v2;
  176.             *v2 = *v1;
  177.  
  178.             v5 = v1;
  179.  
  180.             do{
  181.                v2--;
  182.             }while((*v2)->dist < dist);
  183.  
  184.             do{
  185.                v1++;
  186.             }while((*v1)->dist > dist);
  187.  
  188.          }
  189.  
  190.          v2 = v1 - 1;
  191.  
  192.          *v5 = *v2;
  193.          *v2 = *v6;
  194.          *v6 = *v0;
  195.  
  196.          high = v2 - list;
  197.  
  198. /* Put sublists on the stack, smallest on top */
  199.  
  200.          if((high - start) > (end - high)){
  201.             stack[++stackIndex].start = start;
  202.             stack[stackIndex].end = high - 1;
  203.             ++stackIndex;
  204.             start = high + 1;
  205.             stackNotSet = 0;
  206.          }else{
  207.             stack[++stackIndex].start = high + 1;
  208.             stack[stackIndex].end = end;
  209.             ++stackIndex;
  210.             end = high - 1;
  211.             stackNotSet = 0;
  212.             }
  213.       }
  214.    }
  215.  
  216. /* insertion sort all the remaining sublists at once */
  217.  
  218.    v2 = list;
  219.    v3 = &(list[numPolys - 1]);
  220.    v4 = v2 + 1;
  221.  
  222.    while(v4 <= v3){
  223.  
  224.       *v0 = *v4;
  225.       v1 = v4 - 1;
  226.  
  227.       while((v1 >= v2) && ((*v1)->dist < (*v0)->dist)){
  228.          *(v1 + 1) = *v1;
  229.          v1--;
  230.          }
  231.  
  232.       *(v1 + 1) = *v0;
  233.       v4++;
  234.       }
  235. }
  236.  
  237.  
  238.  
  239. static int readLine(fd, line, lineNo)
  240. FILE *fd;
  241. char *line;
  242. int  *lineNo;
  243. /******************************************************************************
  244.    Read a significant line from a file.
  245. ******************************************************************************/
  246. {
  247. float value;
  248.  
  249.    do{
  250.       if(fgets(line, MAXLINE, fd) == NULL){
  251.          if(feof(fd)){
  252.             return ERROR;
  253.          }else{
  254.             fprintf(stderr, "fgets() failed on line %d\n", *lineNo);
  255.             exit(1);
  256.             }
  257.       }else{
  258.          (*lineNo)++;
  259.  
  260. /* Warn about long lines */
  261.  
  262.          if(strlen(line) > (MAXLINE - 5)){
  263.             fprintf(stderr, "Line too long on line %d, line may be trucated.\n",
  264.             *lineNo);
  265.             exit(1);
  266.             }
  267.          }
  268.    }while(sscanf(line, "%f", &value) <= 0);
  269.  
  270.    return EOK;
  271. }
  272.  
  273.  
  274.  
  275. static void readObjectFile(filename, colors, numColors, points, numPoints, segs,
  276. numSegs, polys, numPolys, list, bounds)
  277. char    *filename;
  278. Color   **colors;
  279. int     *numColors;
  280. point   **points;
  281. int     *numPoints;
  282. segment **segs;
  283. int     *numSegs;
  284. polygon **polys;
  285. int     *numPolys;
  286. polygon ***list;
  287. point   **bounds;
  288. /******************************************************************************
  289.    Read the point list and segment list from a file.  We allocate space
  290.    for both lists.
  291. ******************************************************************************/
  292. {
  293. FILE    *fd;
  294. char     line[MAXLINE], s[MAXLINE];
  295. int      index, index2, lineNo = 0, p, q, num, seg, color, count;
  296. point   *prevPoint;
  297. segment *tmpSeg;
  298. float   xMin, xMax, yMin, yMax, zMin, zMax;
  299. float   x, y, z;
  300.  
  301. /* Can we open the file? */
  302.  
  303.    if(!filename){
  304.       (void)fprintf(stderr, "No file specified\n"); exit(1);}
  305.  
  306.    if(!strcmp(filename, "-"))
  307.       fd = stdin;
  308.    else
  309.       if((fd = fopen(filename, "r")) == NULL){
  310.          (void)fprintf(stderr, "Unable to open file: %s\n", filename);
  311.          exit(1);
  312.          }
  313.  
  314. /* Allocate space for bounding points */
  315.  
  316.    if((*bounds = (point *)calloc(1, NUMBOUNDS * sizeof(point))) == NULL){
  317.       (void)fprintf(stderr, "Unable to allocate memory for bounds\n");
  318.       exit(1);
  319.       }
  320.  
  321. /* Read colors */
  322.  
  323.    if(readLine(fd, line, &lineNo)){
  324.       (void)fprintf(stderr, "Number of colors not specified\n");
  325.       exit(1);
  326.       }
  327.  
  328.    sscanf(line, "%d", numColors);
  329.  
  330.    if((*colors = (Color *)calloc(1, (*numColors + 4) * sizeof(Color))) == NULL){
  331.       (void)fprintf(stderr, "Unable to allocate memory for colors\n");
  332.       exit(1);
  333.       }
  334.  
  335.    for(index = 0; index < *numColors; index++){
  336.       if(readLine(fd, line, &lineNo)){
  337.          (void)fprintf(stderr, "Expected color on line %d\n", lineNo);
  338.          exit(1);
  339.          }
  340.  
  341.       if(sscanf(line, "%d %d %d %d", &num, &((*colors)[index].red),
  342.       &((*colors)[index].green), &((*colors)[index].blue)) != 4){
  343.          fprintf(stderr, "Error reading color on line %d\n", lineNo);
  344.          exit(1);
  345.          }
  346.  
  347.       if((((*colors)[index].red< 0) || ((*colors)[index].red   > 255)) ||
  348.       (((*colors)[index].green < 0) || ((*colors)[index].green > 255)) ||
  349.       (((*colors)[index].blue  < 0) || ((*colors)[index].blue  > 255))){
  350.          fprintf(stderr, "Color out of range on line %d\n", lineNo);
  351.          exit(1);
  352.          }
  353.       }
  354.  
  355. /* Read points */
  356.  
  357.    if(readLine(fd, line, &lineNo)){
  358.       (void)fprintf(stderr, "Number of points not specified\n");
  359.       exit(1);
  360.       }
  361.  
  362.    sscanf(line, "%d", numPoints);
  363.  
  364.    if((*points = (point *)calloc(1, *numPoints * sizeof(point))) == NULL){
  365.       (void)fprintf(stderr, "Unable to allocate memory for points\n");
  366.       exit(1);
  367.       }
  368.  
  369.    for(index = 0; index < *numPoints; index++){
  370.       if(readLine(fd, line, &lineNo)){
  371.          (void)fprintf(stderr, "Expected point on line %d\n", lineNo);
  372.          exit(1);
  373.          }
  374.  
  375.       if(sscanf(line, "%d %f %f %f", &num, &x, &y, &z) != 4){
  376.          fprintf(stderr, "Error reading point on line %d\n", lineNo);
  377.          exit(1);
  378.          }
  379.  
  380.       (*points)[index].x  = (number)x;
  381.       (*points)[index].y = (number)y;
  382.       (*points)[index].z = (number)z;
  383.       }
  384.  
  385. /* Read segments */
  386.  
  387.    if(readLine(fd, line, &lineNo)){
  388.       (void)fprintf(stderr, "Number of segments not specified\n");
  389.       exit(1);
  390.       }
  391.  
  392.    sscanf(line, "%d", numSegs);
  393.  
  394.    if((*segs = (segment *)calloc(1, *numSegs * sizeof(segment))) == NULL){
  395.       (void)fprintf(stderr, "Unable to allocate memory for segments\n");
  396.       exit(1);
  397.       }
  398.  
  399.    for(index = 0; index < *numSegs; index++){
  400.       if(readLine(fd, line, &lineNo)){
  401.          (void)fprintf(stderr, "Expected segment on line %d\n", lineNo);
  402.          exit(1);
  403.          }
  404.  
  405.       if(sscanf(line, "%d %d %d %d", &num, &color,
  406.       &p, &q) != 4){
  407.          fprintf(stderr, "Error reading segment on line %d\n", lineNo);
  408.          exit(1);
  409.          }
  410.  
  411.       if((p < 0) || (q < 0) || (p >= *numPoints) || (q >= *numPoints) ||
  412.       (color < 0) || (color >= *numColors)){
  413.          fprintf(stderr, "Segment value out of range on line %d\n", lineNo);
  414.          exit(1);
  415.          }
  416.  
  417.       (*segs)[index].color = &((*colors)[color]);
  418.       (*segs)[index].P = &((*points)[p]);
  419.       (*segs)[index].Q = &((*points)[q]);
  420.  
  421. /* Update points' segment lists */
  422.  
  423.       if((*points)[p].numSegs == 0){
  424.          if(((*points)[p].segs = (segment **)calloc(1, sizeof(segment *)))
  425.          == NULL){
  426.             fprintf(stderr,
  427.             "Unable to allocate memory for point segments on line %d\n",
  428.             lineNo);
  429.             exit(1);
  430.             }
  431.       }else{
  432.          if(((*points)[p].segs = (segment **)realloc((*points)[p].segs,
  433.          ((*points)[p].numSegs + 1) * sizeof(segment *))) == NULL){
  434.             fprintf(stderr,
  435.             "Unable to allocate memory for point segments on line %d\n",
  436.             lineNo);
  437.             exit(1);
  438.             }
  439.          }
  440.  
  441.       if((*points)[q].numSegs == 0){
  442.          if(((*points)[q].segs = (segment **)calloc(1, sizeof(segment *)))
  443.          == NULL){
  444.             fprintf(stderr,
  445.             "Unable to allocate memory for point segments on line %d\n",
  446.             lineNo);
  447.             exit(1);
  448.             }
  449.       }else{
  450.          if(((*points)[q].segs = (segment **)realloc((*points)[q].segs,
  451.          ((*points)[q].numSegs + 1) * sizeof(segment *))) == NULL){
  452.             fprintf(stderr,
  453.             "Unable to allocate memory for point segments on line %d\n",
  454.             lineNo);
  455.             exit(1);
  456.             }
  457.          }
  458.  
  459.       (*points)[p].segs[(*points)[p].numSegs] = &((*segs)[index]);
  460.       (*points)[q].segs[(*points)[q].numSegs] = &((*segs)[index]);
  461.       (*points)[p].numSegs++;
  462.       (*points)[q].numSegs++;
  463.       }
  464.  
  465. /* Read polygons */
  466.  
  467.    if(readLine(fd, line, &lineNo)){
  468.       (void)fprintf(stderr, "Number of polygons not specified\n");
  469.       exit(1);
  470.       }
  471.  
  472.    sscanf(line, "%d", numPolys);
  473.  
  474.    if((*polys = (polygon *)calloc(1, *numPolys * sizeof(polygon))) == NULL){
  475.       (void)fprintf(stderr, "Unable to allocate memory for polygons\n");
  476.       exit(1);
  477.       }
  478.  
  479.    for(index = 0; index < *numPolys; index++){
  480.       if(readLine(fd, line, &lineNo)){
  481.          (void)fprintf(stderr, "Expected polygon on line %d\n", lineNo);
  482.          exit(1);
  483.          }
  484.  
  485.       if(sscanf(line, "%d %d %d %[^#]", &num, &color,
  486.       &((*polys)[index].numSegs), s) != 4){
  487.          fprintf(stderr, "Error reading polygon on line %d\n", lineNo);
  488.          exit(1);
  489.          }
  490.  
  491.       if((color < 0) || (color >= *numColors) || 
  492.       ((*polys)[index].numSegs <= 2)){
  493.          fprintf(stderr, "Polygon value out of range on line %d\n", lineNo);
  494.          exit(1);
  495.          }
  496.  
  497.       if(((*polys)[index].segs = (segment **)calloc(1, (*polys)[index].numSegs *
  498.       sizeof(segment *))) == NULL){
  499.          fprintf(stderr,
  500.          "Unable to allocate memory for polygon segments on line %d\n", lineNo);
  501.          exit(1);
  502.          }
  503.  
  504.       (*polys)[index].color = &((*colors)[color]);
  505.  
  506.       for(index2 = 0; index2 < (*polys)[index].numSegs; index2++){
  507.  
  508.          strcpy(line, s);
  509.  
  510.          count = sscanf(line, "%d %[^#]", &seg, s);
  511.  
  512.          if(!((count == 2) || ((count == 1) &&
  513.          (index2 == ((*polys)[index].numSegs - 1))))){
  514.             fprintf(stderr, "Error reading polygon on line %d\n", lineNo);
  515.             exit(1);
  516.             }
  517.  
  518.          if((seg < 0) || (seg >= *numSegs)){
  519.             fprintf(stderr, "Polygon value out of range on line %d\n",
  520.             lineNo);
  521.             exit(1);
  522.             }
  523.    
  524.          (*polys)[index].segs[index2] = &((*segs)[seg]);
  525.  
  526. /* Update segments' polygon lists */
  527.  
  528.          if((*segs)[seg].numPolys == 0){
  529.             if(((*segs)[seg].polys = (polygon **)calloc(1, sizeof(polygon *)))
  530.             == NULL){
  531.                fprintf(stderr,
  532.                "Unable to allocate memory for segment polygons on line %d\n",
  533.                lineNo);
  534.                exit(1);
  535.                }
  536.          }else{
  537.             if(((*segs)[seg].polys = (polygon **)realloc((*segs)[seg].polys,
  538.             ((*segs)[seg].numPolys + 1) * sizeof(polygon *))) == NULL){
  539.                fprintf(stderr,
  540.                "Unable to allocate memory for segment polygons on line %d\n",
  541.                lineNo);
  542.                exit(1);
  543.                }
  544.             }
  545.  
  546.          (*segs)[seg].polys[((*segs)[seg].numPolys)] = &((*polys)[index]); 
  547.          ((*segs)[seg].numPolys)++;
  548.          }
  549.       }
  550.  
  551.    if(readLine(fd, line, &lineNo) == EOK){
  552.       (void)fprintf(stderr, "WARNING: file not entirely read, line %d\n",
  553.       lineNo);
  554.       }
  555.  
  556. /* Close file */
  557.  
  558.    (void)fclose(fd);
  559.  
  560. /* Make polygon pointer array */
  561.  
  562.    if((*list = (polygon **)calloc(1, *numPolys * sizeof(polygon *))) == NULL){
  563. (void)fprintf(stderr, "Unable to allocate memory for pointer list\n"); exit(1);}
  564.  
  565.    for(index = 0; index < *numPolys; index++){
  566.       (*list)[index] = &((*polys)[index]);
  567.       }
  568.  
  569. /* Update more lists */
  570.  
  571.    for(index = 0; index < *numPolys; index++){
  572.  
  573.       index2 = 0;
  574.  
  575.       if(((*list)[index]->segs[0]->P ==
  576.        (*list)[index]->segs[1]->P) ||
  577.       ((*list)[index]->segs[0]->P ==
  578.        (*list)[index]->segs[1]->Q)){
  579.           prevPoint = (*list)[index]->segs[0]->Q;
  580.       }else{
  581.           prevPoint = (*list)[index]->segs[0]->P;
  582.          }
  583.  
  584.       while(index2 < (*list)[index]->numSegs){
  585.  
  586.          tmpSeg = (*list)[index]->segs[index2]; 
  587.  
  588.          if(tmpSeg->P == prevPoint){
  589.             prevPoint = tmpSeg->Q;
  590.          }else{ 
  591.             prevPoint = tmpSeg->P;
  592.             }
  593.  
  594. /* Update points' polygon lists */
  595.  
  596.          if(prevPoint->numPolys == 0){
  597.             if((prevPoint->polys = (polygon **)calloc(1, sizeof(polygon *)))
  598.             == NULL){
  599.                fprintf(stderr,
  600.                "Unable to allocate memory for point polygons\n");
  601.                exit(1);
  602.                }
  603.          }else{
  604.             if((prevPoint->polys = (polygon **)realloc(prevPoint->polys,
  605.             (prevPoint->numPolys + 1) * sizeof(polygon *))) == NULL){
  606.                fprintf(stderr,
  607.                "Unable to allocate memory for point polygons\n");
  608.                exit(1);
  609.                }
  610.             }
  611.  
  612.          prevPoint->polys[prevPoint->numPolys] = &((*polys)[index]);
  613.          (prevPoint->numPolys)++;
  614.          
  615. /* Update polygons' point lists */
  616.  
  617.          if((*polys)[index].numPoints == 0){
  618.             if(((*polys)[index].points = (point **)calloc(1, sizeof(point *)))
  619.             == NULL){
  620.                fprintf(stderr,
  621.                "Unable to allocate memory for polygon points\n");
  622.                exit(1);
  623.                }
  624.          }else{
  625.             if(((*polys)[index].points = (point **)realloc(
  626.             (*polys)[index].points, ((*polys)[index].numPoints + 1) *
  627.             sizeof(point *))) == NULL){
  628.                fprintf(stderr,
  629.                "Unable to allocate memory for point polygons\n");
  630.                exit(1);
  631.                }
  632.             }
  633.  
  634.          (*polys)[index].points[(*polys)[index].numPoints] = prevPoint;
  635.          ((*polys)[index].numPoints)++;
  636.  
  637.          index2++;
  638.          }
  639.       }
  640.  
  641. /* Calculate the bounding cube */
  642.  
  643.    xMin = xMax = (*points)[0].x;
  644.    yMin = yMax = (*points)[0].y;
  645.    zMin = zMax = (*points)[0].z;
  646.  
  647.    for(index = 1; index < *numPoints; index++){
  648.  
  649.       if((*points)[index].x < xMin){
  650.          xMin = (*points)[index].x;
  651.          }
  652.       if((*points)[index].x > xMax){
  653.          xMax = (*points)[index].x;
  654.          }
  655.  
  656.       if((*points)[index].y < yMin){
  657.          yMin = (*points)[index].y;
  658.          }
  659.       if((*points)[index].y > yMax){
  660.          yMax = (*points)[index].y;
  661.          }
  662.  
  663.       if((*points)[index].z < zMin){
  664.          zMin = (*points)[index].z;
  665.          }
  666.       if((*points)[index].z > zMax){
  667.          zMax = (*points)[index].z;
  668.          }
  669.       }
  670.  
  671.    (*bounds)[0].x = xMin; (*bounds)[0].y = yMin; (*bounds)[0].z = zMin;
  672.    (*bounds)[1].x = xMin; (*bounds)[1].y = yMin; (*bounds)[1].z = zMax;
  673.    (*bounds)[2].x = xMin; (*bounds)[2].y = yMax; (*bounds)[2].z = zMin;
  674.    (*bounds)[3].x = xMin; (*bounds)[3].y = yMax; (*bounds)[3].z = zMax;
  675.    (*bounds)[4].x = xMax; (*bounds)[4].y = yMin; (*bounds)[4].z = zMin;
  676.    (*bounds)[5].x = xMax; (*bounds)[5].y = yMin; (*bounds)[5].z = zMax;
  677.    (*bounds)[6].x = xMax; (*bounds)[6].y = yMax; (*bounds)[6].z = zMin;
  678.    (*bounds)[7].x = xMax; (*bounds)[7].y = yMax; (*bounds)[7].z = zMax;
  679. }
  680.  
  681.  
  682.  
  683. static void ParseCommandLine(argc, argv, filename, g)
  684. int argc;
  685. char *argv[];
  686. char **filename;
  687. Ginfo *g;
  688. /******************************************************************************
  689.    Parse the command line set the filename and the appropriate flags
  690. ******************************************************************************/
  691. {
  692.  
  693. static char options[][MAXOPTIONLEN] = {
  694.    "-help",
  695.    "-display",
  696.    "-geometry"
  697. };
  698.  
  699. int NUMOPTIONS = 3;
  700. int index, option, filenameValid = 0;
  701.  
  702.    g->helpMenu = 0;
  703.    g->DisplayName = g->Geometry = NULL;
  704.  
  705. /* Default values for flags */
  706.  
  707.    g->renderMode = WIREFRAME;
  708.    g->buffer = 1;
  709.    g->mono   = 0;
  710.    g->stereo = 1;
  711.    g->stereoBlue = 0;
  712.  
  713.    for(index = 1; index < argc; index++){
  714.       for(option = 0; option < NUMOPTIONS; option++)
  715.          if(!strcmp(argv[index], options[option]))
  716.             break;
  717.  
  718.       switch(option){
  719.          
  720.          case 0:    
  721.    (void)fprintf(stderr, "Options:\n");  
  722.    (void)fprintf(stderr, "-display  <display>        X display name\n");  
  723.    (void)fprintf(stderr, "-geometry <geometry>       Window geometry\n");  
  724.    (void)fprintf(stderr, "-help                      Print this message\n"); 
  725.    (void)fprintf(stderr, "\n");
  726.    (void)fprintf(stderr, "Type M or m to get a help menu\n");
  727.    (void)fprintf(stderr, "when the program is running\n");
  728.    (void)fprintf(stderr, "\n");
  729.             exit(0);
  730.             break;
  731.        
  732.          case 1:
  733.             g->DisplayName = argv[++index];
  734.             break;
  735.  
  736.          case 2:
  737.             g->Geometry = argv[++index];
  738.             break;
  739.  
  740.          default:
  741.             if(!filenameValid){
  742.                *filename = (char *)(argv[index]);
  743.                filenameValid = 1;
  744.             }else{
  745.          (void)fprintf(stderr,"usage:    %s <object file>\n", argv[0]);
  746.          (void)fprintf(stderr,"%s -help  for a list of options\n", argv[0]);
  747.                exit(1);
  748.                }
  749.             break; 
  750.          }
  751.       }
  752.  
  753.    if(!filenameValid){
  754.       (void)fprintf(stderr,"usage:    %s <object file>\n", argv[0]);
  755.       (void)fprintf(stderr,"%s -help  for a list of options\n", argv[0]);
  756.       exit(1);
  757.       }
  758. }
  759.  
  760.  
  761.  
  762. static void Rotate(points, cx, cy, cz, sx, sy, sz)
  763. anglePoint *points;
  764. double cx, cy, cz, sx, sy, sz;
  765. /******************************************************************************
  766.    Rotate about Z, X, then Y, for two points.
  767. ******************************************************************************/
  768. {
  769. int index;
  770. double x, y, z, t;
  771.  
  772.     for(index = 0; index < 2; index++){
  773.        x = points[index].x;
  774.        y = points[index].y;
  775.        z = points[index].z;
  776.  
  777.        t = x * cz + y * sz;
  778.        y = y * cz - x * sz;
  779.        x = t;
  780.    
  781.        points[index].y = y * cx + z * sx;
  782.  
  783.        z = z * cx - y * sx;
  784.  
  785.        points[index].x = x * cy + z * sy;
  786.        points[index].z = z * cy - x * sy;
  787.        }
  788. }
  789.  
  790.  
  791.  
  792. static double DotProduct(x1, Y1, x2, y2)
  793. double x1, Y1, x2, y2;
  794. /******************************************************************************
  795.    Dot product (calculate the cosine of the angle between two vectors).
  796. ******************************************************************************/
  797. {
  798. double temp;
  799.  
  800.    if((x1 == 0.0 && Y1 == 0.0)){
  801.       return 1.0;
  802.       }
  803.  
  804.    temp = sqrt(x1 * x1 + Y1 * Y1);
  805.    x1 = x1 / temp;
  806.    Y1 = Y1 / temp;
  807.   
  808.    temp = x1 * x2 + Y1 * y2;
  809.  
  810.    if(temp > 1.0)
  811.       temp = fmod(temp, 1.0); 
  812.    
  813.    if(temp < -1.0)
  814.       temp = -fmod(-temp, 1.0); 
  815.       
  816.    return(temp); 
  817. }
  818.  
  819.  
  820.  
  821. static void CalculateAngles(X, Y, Z, X1, Y1, Z1)
  822. double *X, *Y, *Z;
  823. double X1, Y1, Z1;
  824. /******************************************************************************
  825.    Calculate what the result of the angle changes of X1, Y1, and Z1 are
  826.    in my weird coordinate system.
  827. ******************************************************************************/
  828. {
  829. anglePoint points[2];
  830.  
  831.    points[0].x = 0.0; points[0].y = 0.0; points[0].z = 1.0;
  832.    points[1].x = 1.0; points[1].y = 0.0; points[1].z = 0.0;
  833.  
  834.    Rotate(points, cos(*X), cos(*Y), cos(*Z), sin(*X), sin(*Y), sin(*Z));
  835.    Rotate(points, cos(X1), cos(Y1), cos(Z1), sin(X1), sin(Y1), sin(Z1));
  836.  
  837.    *Y = acos(DotProduct(points[0].x, points[0].z, 0.0, 1.0)); 
  838.  
  839.    if(points[0].x < 0.0)
  840.       *Y = -*Y;
  841.  
  842.    Rotate(points, 1.0, cos(-*Y), 1.0, 0.0, sin(-*Y), 0.0);
  843.    *X = acos(DotProduct(points[0].y, points[0].z, 0.0, 1.0)); 
  844.  
  845.    if(points[0].y < 0.0)
  846.       *X = -*X;
  847.  
  848.    Rotate(points, cos(-*X), 1.0, 1.0, sin(-*X), 0.0, 0.0);
  849.    *Z = acos(DotProduct(points[1].x, points[1].y, 1.0, 0.0)); 
  850.  
  851.    if(!(points[1].y < 0.0))
  852.       *Z = -*Z;
  853. }
  854.  
  855.  
  856.  
  857. static void DrawLogo(g, x, y)
  858. Ginfo *g;
  859. int x, y;
  860. /******************************************************************************
  861.    Display the Logo.
  862. ******************************************************************************/
  863. {
  864. int hUnit, vUnit;
  865. XPoint points[512];
  866.  
  867.    hUnit = XTextWidth(g->font, LONGESTSTRING, strlen(LONGESTSTRING)) /
  868.    strlen(LONGESTSTRING);
  869.    vUnit = FONTHEIGHT(g->font);
  870.  
  871. /* X */
  872.  
  873.    points[0].x =  9 * hUnit + x; points[0].y =  1 * vUnit + y; 
  874.    points[1].x =  9 * hUnit + vUnit + x; points[1].y =  1 * vUnit + y; 
  875.    points[2].x = 14 * hUnit + vUnit + x; points[2].y =  6 * vUnit + y; 
  876.    points[3].x = 14 * hUnit + x; points[3].y =  6 * vUnit + y; 
  877.     
  878.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  879.    CoordModeOrigin); 
  880.  
  881.    points[0].x = 14 * hUnit + vUnit + x; points[0].y =  1 * vUnit + y; 
  882.    points[1].x = 14 * hUnit + x; points[1].y =  1 * vUnit + y; 
  883.    points[2].x =  9 * hUnit + x; points[2].y =  6 * vUnit + y; 
  884.    points[3].x =  9 * hUnit + vUnit + x; points[3].y =  6 * vUnit + y; 
  885.     
  886.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  887.    CoordModeOrigin); 
  888.  
  889. /* 3 */
  890.  
  891.    points[0].x = 18 * hUnit + x; points[0].y =  1 * vUnit + y; 
  892.    points[1].x = 22 * hUnit + x; points[1].y =  1 * vUnit + y; 
  893.    points[2].x = 23 * hUnit + x; points[2].y =  2 * vUnit + y; 
  894.    points[3].x = 18 * hUnit + x; points[3].y =  2 * vUnit + y; 
  895.     
  896.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  897.    CoordModeOrigin); 
  898.  
  899.    points[0].x = 23 * hUnit - vUnit + x; points[0].y =  2 * vUnit + y; 
  900.    points[1].x = 23 * hUnit + x; points[1].y =  2 * vUnit + y; 
  901.    points[2].x = 23 * hUnit + x; points[2].y =  3 * vUnit + y; 
  902.    points[3].x = 23 * hUnit - vUnit + x; points[3].y =  4 * vUnit + y; 
  903.     
  904.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  905.    CoordModeOrigin); 
  906.  
  907.    points[0].x = 23 * hUnit - vUnit + x; points[0].y =  3 * vUnit + y; 
  908.    points[1].x = 23 * hUnit + x; points[1].y =  4 * vUnit + y; 
  909.    points[2].x = 23 * hUnit + x; points[2].y =  5 * vUnit + y; 
  910.    points[3].x = 23 * hUnit - vUnit + x; points[3].y =  5 * vUnit + y; 
  911.     
  912.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  913.    CoordModeOrigin); 
  914.  
  915.    points[0].x = 18 * hUnit + x; points[0].y =  5 * vUnit + y; 
  916.    points[1].x = 23 * hUnit + x; points[1].y =  5 * vUnit + y; 
  917.    points[2].x = 22 * hUnit + x; points[2].y =  6 * vUnit + y; 
  918.    points[3].x = 18 * hUnit + x; points[3].y =  6 * vUnit + y; 
  919.     
  920.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  921.    CoordModeOrigin); 
  922.  
  923.    points[0].x = 19 * hUnit + x; points[0].y =  3 * vUnit + y; 
  924.    points[1].x = 23 * hUnit - vUnit + x; points[1].y =  3 * vUnit + y; 
  925.    points[2].x = 23 * hUnit - vUnit + x; points[2].y =  4 * vUnit + y; 
  926.    points[3].x = 19 * hUnit + x; points[3].y =  4 * vUnit + y; 
  927.     
  928.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  929.    CoordModeOrigin); 
  930.  
  931. /* D */
  932.  
  933.    points[0].x = 26 * hUnit + x; points[0].y =  1 * vUnit + y; 
  934.    points[1].x = 30 * hUnit + x; points[1].y =  1 * vUnit + y; 
  935.    points[2].x = 30 * hUnit + vUnit + x; points[2].y =  2 * vUnit + y; 
  936.    points[3].x = 26 * hUnit + x; points[3].y =  2 * vUnit + y; 
  937.     
  938.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  939.    CoordModeOrigin); 
  940.  
  941.    points[0].x = 26 * hUnit + x; points[0].y =  5 * vUnit + y; 
  942.    points[1].x = 30 * hUnit + vUnit + x; points[1].y =  5 * vUnit + y; 
  943.    points[2].x = 30 * hUnit + x; points[2].y =  6 * vUnit + y; 
  944.    points[3].x = 26 * hUnit + x; points[3].y =  6 * vUnit + y; 
  945.     
  946.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  947.    CoordModeOrigin); 
  948.  
  949.    points[0].x = 26 * hUnit + x; points[0].y =  1 * vUnit + y; 
  950.    points[1].x = 26 * hUnit + vUnit + x; points[1].y =  1 * vUnit + y; 
  951.    points[2].x = 26 * hUnit + vUnit + x; points[2].y =  6 * vUnit + y; 
  952.    points[3].x = 26 * hUnit + x; points[3].y =  6 * vUnit + y; 
  953.     
  954.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  955.    CoordModeOrigin); 
  956.  
  957.    points[0].x = 30 * hUnit + x; points[0].y =  2 * vUnit + y; 
  958.    points[1].x = 30 * hUnit + vUnit + x; points[1].y =  2 * vUnit + y; 
  959.    points[2].x = 30 * hUnit + vUnit + x; points[2].y =  5 * vUnit + y; 
  960.    points[3].x = 30 * hUnit + x; points[3].y =  5 * vUnit + y; 
  961.     
  962.    XFillPolygon(g->dpy, g->helpWin, g->helpGc, points, 4, Convex,
  963.    CoordModeOrigin); 
  964. }
  965.  
  966.  
  967.  
  968. static void DisplayMenu(g)
  969. Ginfo *g;
  970. /******************************************************************************
  971.    Display the help menu.
  972. ******************************************************************************/
  973. {
  974. int x = 5, y = 5;
  975.  
  976.    XSetFont(g->dpy, g->helpGc, g->font->fid );
  977.  
  978.    XSetWindowBackground(g->dpy, g->helpWin, g->black);
  979.    XSetForeground(g->dpy, g->helpGc, g->white);
  980.    XSetBackground(g->dpy, g->helpGc, g->black);
  981.  
  982.    XSetStipple(g->dpy, g->helpGc, g->stipple[NUMSTIPPLES / 3]);
  983.    XSetFillStyle(g->dpy, g->helpGc, FillOpaqueStippled);
  984.  
  985.    DrawLogo(g, (XTextWidth(g->font, LONGESTSTRING, strlen(LONGESTSTRING)) /
  986.    strlen(LONGESTSTRING)) / 2, FONTHEIGHT(g->font) / 3);
  987.    
  988.    XSetFillStyle(g->dpy, g->helpGc, FillSolid);
  989.  
  990.    DrawLogo(g, 0, 0);
  991.  
  992.    HelpPrint(g,x,y,"");
  993.    HelpPrint(g,x,y,"");
  994.    HelpPrint(g,x,y,"");
  995.    HelpPrint(g,x,y,"");
  996.    HelpPrint(g,x,y,"");
  997.    HelpPrint(g,x,y,"");
  998.    HelpPrint(g,x,y,"");
  999.    HelpPrint(g,x,y,"              VERSION 2.2");
  1000.    HelpPrint(g,x,y,"");
  1001.    HelpPrint(g,x,y,"  CONTROLS SUMMARY");
  1002.    HelpPrint(g,x,y,"");
  1003.    HelpPrint(g,x,y,"     QUIT                    q Q");
  1004.    HelpPrint(g,x,y,"     WIREFRAME MODE          w W");
  1005.    HelpPrint(g,x,y,"     HIDDEN LINE MODE        e E");
  1006.    HelpPrint(g,x,y,"     HIDDEN SURFACE MODE     r R");
  1007.    HelpPrint(g,x,y,"     MOVE OBJECT DOWN        u U");
  1008.    HelpPrint(g,x,y,"     MOVE OBJECT UP          i I");
  1009.    HelpPrint(g,x,y,"     TOGGLE CONTROLS STYLE   o O");
  1010.    HelpPrint(g,x,y,"     TOGGLE STEREO DISPLAY   s S");
  1011.    HelpPrint(g,x,y,"     TOGGLE BLUE STEREO VIEW d D");
  1012.    HelpPrint(g,x,y,"     TOGGLE DOUBLE BUFFER    f F");
  1013.    HelpPrint(g,x,y,"     MOVE OBJECT RIGHT       h H");
  1014.    HelpPrint(g,x,y,"     MOVE OBJECT BACKWARD    j J");
  1015.    HelpPrint(g,x,y,"     MOVE OBJECT FOREWARD    k K");
  1016.    HelpPrint(g,x,y,"     MOVE OBJECT LEFT        l L");
  1017.    HelpPrint(g,x,y,"     TOGGLE HELP MENU        m M");
  1018.    HelpPrint(g,x,y,"     ROTATE ABOUT X          x X a A");
  1019.    HelpPrint(g,x,y,"     ROTATE ABOUT Y          y Y b B");
  1020.    HelpPrint(g,x,y,"     ROTATE ABOUT Z          z Z c C");
  1021.    HelpPrint(g,x,y,"     AUTOROTATE ABOUT X      1 2 3");
  1022.    HelpPrint(g,x,y,"     AUTOROTATE ABOUT Y      4 5 6");
  1023.    HelpPrint(g,x,y,"     AUTOROTATE ABOUT Z      7 8 9");
  1024.    HelpPrint(g,x,y,"     ADJUST FOCUS            [ ] { }");
  1025.    HelpPrint(g,x,y,"");
  1026.    HelpPrint(g,x,y,"  POINTER MOVEMENT WITH LEFT BUTTON :");
  1027.    HelpPrint(g,x,y,"");
  1028.    HelpPrint(g,x,y,"     ROTATE OBJECT ABOUT X   Vertical");
  1029.    HelpPrint(g,x,y,"     ROTATE OBJECT ABOUT Z   Horizontal");
  1030. }
  1031.  
  1032.  
  1033.  
  1034. static void ResetPurpleRectangle(XL, YL, XH, YH, g)
  1035. int XL, YL, XH, YH;
  1036. Ginfo *g;
  1037. /******************************************************************************
  1038.    Reset the vertices of the purple rectangle.
  1039. ******************************************************************************/
  1040. {
  1041.    g->redSegments[3].x1  = (XL + MARGIN);
  1042.    g->blueSegments[3].x1 = (XL + MARGIN);
  1043.    g->redSegments[3].y1  = (YL + MARGIN);
  1044.    g->blueSegments[3].y1 = (YL + MARGIN);
  1045.    g->redSegments[3].x2  = (XH - MARGIN);
  1046.    g->blueSegments[3].x2 = (XH - MARGIN);
  1047.    g->redSegments[3].y2  = (YL + MARGIN);
  1048.    g->blueSegments[3].y2 = (YL + MARGIN);
  1049.    g->redSegments[2].x1  = (XH - MARGIN);
  1050.    g->blueSegments[2].x1 = (XH - MARGIN);
  1051.    g->redSegments[2].y1  = (YH - MARGIN);
  1052.    g->blueSegments[2].y1 = (YH - MARGIN);
  1053.    g->redSegments[2].x2  = (XL + MARGIN);
  1054.    g->blueSegments[2].x2 = (XL + MARGIN);
  1055.    g->redSegments[2].y2  = (YH - MARGIN);
  1056.    g->blueSegments[2].y2 = (YH - MARGIN);
  1057.    g->redSegments[1].x1  = (XH - MARGIN);
  1058.    g->blueSegments[1].x1 = (XH - MARGIN);
  1059.    g->redSegments[1].y1  = (YL + MARGIN);
  1060.    g->blueSegments[1].y1 = (YL + MARGIN);
  1061.    g->redSegments[1].x2  = (XH - MARGIN);
  1062.    g->blueSegments[1].x2 = (XH - MARGIN);
  1063.    g->redSegments[1].y2  = (YH - MARGIN);
  1064.    g->blueSegments[1].y2 = (YH - MARGIN);
  1065.    g->redSegments[0].x1  = (XL + MARGIN);
  1066.    g->blueSegments[0].x1 = (XL + MARGIN);
  1067.    g->redSegments[0].y1  = (YL + MARGIN);
  1068.    g->blueSegments[0].y1 = (YL + MARGIN);
  1069.    g->redSegments[0].x2  = (XL + MARGIN);
  1070.    g->blueSegments[0].x2 = (XL + MARGIN);
  1071.    g->redSegments[0].y2  = (YH - MARGIN);
  1072.    g->blueSegments[0].y2 = (YH - MARGIN);
  1073. }
  1074.  
  1075.  
  1076.  
  1077. static void OneBitSetColors(g)
  1078. Ginfo *g;
  1079. /******************************************************************************
  1080.    Set up color information/stipples for a one bit display.
  1081. ******************************************************************************/
  1082. {
  1083. int index;
  1084. Color *colors;
  1085. int numColors;
  1086.  
  1087.    colors = g->colors;
  1088.    numColors = g->numColors;
  1089.  
  1090. /* Set the colors (may not be used) */
  1091.  
  1092.    for(index = 0; index < numColors; index++){
  1093.       colors[index].value = 1; 
  1094.  
  1095. /* Set the stipples */
  1096.  
  1097.       colors[index].stipple =(int)((double)NUMSTIPPLES *
  1098.       ((double)sqrt((double)(
  1099.       (double)colors[index].red   * (double)colors[index].red +
  1100.       (double)colors[index].green * (double)colors[index].green +
  1101.       (double)colors[index].blue  * (double)colors[index].blue))
  1102.       / MAXCOLORDIST));
  1103.       }   
  1104. }
  1105.  
  1106.  
  1107.  
  1108. static void EightBitSetColors(g)
  1109. Ginfo *g;
  1110. /******************************************************************************
  1111.    Set up color information/stipples for a eight bit display.
  1112. ******************************************************************************/
  1113. {
  1114. Color *colors;
  1115. int numColors;
  1116. int index, index2, colorIndex, redIndex, blueIndex, greenIndex;
  1117. XColor c;
  1118.  
  1119.    colors = g->colors;
  1120.    numColors = g->numColors;
  1121.  
  1122. /* Put "black" into the place reserved for it in the end */
  1123.  
  1124.    colors[numColors].red   = 0;
  1125.    colors[numColors].green = 0;
  1126.    colors[numColors].blue  = 0;
  1127.  
  1128. /* Put "red" into the place reserved for it in the end */
  1129.  
  1130.    colors[numColors + 1].red   = 255;
  1131.    colors[numColors + 1].green = 0;
  1132.    colors[numColors + 1].blue  = 0;
  1133.  
  1134. /* Put "blue" into the place reserved for it in the end */
  1135.  
  1136.    colors[numColors + 2].red   = 0;
  1137.    colors[numColors + 2].green = 0;
  1138.    colors[numColors + 2].blue  = 255;
  1139.  
  1140. /* Put "purple" into the place reserved for it in the end */
  1141.  
  1142.    colors[numColors + 3].red   = 255;
  1143.    colors[numColors + 3].green = 0;
  1144.    colors[numColors + 3].blue  = 255;
  1145.  
  1146. /* Blank out the colormap */
  1147.  
  1148.    for(index = 0; index < 256; index++){
  1149.       c.red    = 0;
  1150.       c.green  = 0;
  1151.       c.blue   = 0;
  1152.       c.flags  = DoRed | DoGreen | DoBlue;
  1153.       c.pixel  = 255; 
  1154.       g->cmapColors[0][index] = c;
  1155.       g->cmapColors[1][index] = c;
  1156.       g->cmapColors[2][index] = c;
  1157.       }
  1158.  
  1159.    if(numColors <= BUFFER_CMAP){
  1160.  
  1161.       colorIndex= numColors + 3;
  1162.       index = 15;
  1163.  
  1164. /* Set stipple, and colormap double buffer colors */
  1165.  
  1166.       while((index > 0) && (colorIndex >= 0)){
  1167.          c.red    = colors[colorIndex].red   << 8;
  1168.          c.green  = colors[colorIndex].green << 8;
  1169.          c.blue   = colors[colorIndex].blue  << 8;
  1170.          c.flags  = DoRed | DoGreen | DoBlue;
  1171.  
  1172.          colors[colorIndex].value = index * 16 + index; 
  1173.  
  1174.          colors[colorIndex].stipple =(int)((double)NUMSTIPPLES *
  1175.          ((double)sqrt((double)(
  1176.          (double)colors[colorIndex].red   * (double)colors[colorIndex].red +
  1177.          (double)colors[colorIndex].green * (double)colors[colorIndex].green +
  1178.          (double)colors[colorIndex].blue  * (double)colors[colorIndex].blue))
  1179.          / MAXCOLORDIST));
  1180.  
  1181.          for(index2 = 1; index2 < 16; index2++){
  1182.             c.pixel  = index2 * 16 + index; 
  1183.             g->cmapColors[0][index2 * 16 + index] = c;
  1184.  
  1185.             c.pixel  = index * 16 + index2; 
  1186.             g->cmapColors[1][index * 16 + index2] = c;
  1187.             }
  1188.  
  1189.          index--; 
  1190.          colorIndex--;
  1191.          }
  1192.    }else{
  1193.  
  1194. /* Set permanent black, red, blue, purple for cmap double buffer */
  1195.  
  1196.       for(index = 0; index < 4; index++){
  1197.          c.red    = colors[numColors + index].red   << 8;
  1198.          c.green  = colors[numColors + index].green << 8;
  1199.          c.blue   = colors[numColors + index].blue  << 8;
  1200.          c.flags  = DoRed | DoGreen | DoBlue;
  1201.          c.pixel  = 12 + index; 
  1202.          g->cmapColors[0][12 + index] = c;
  1203.          g->cmapColors[1][12 + index] = c;
  1204.          colors[numColors + index].value = c.pixel; 
  1205.          } 
  1206.  
  1207.       if(numColors <= MAX_COLORS){
  1208.          colorIndex = 0;
  1209.          index = 9;
  1210.          index2 = 0;
  1211.  
  1212. /* Fill in the rest of the colors */
  1213.  
  1214.          while(colorIndex < numColors){
  1215.             if((index < 12) || (index > 15)){
  1216.                c.red    = colors[colorIndex].red   << 8;
  1217.                c.green  = colors[colorIndex].green << 8;
  1218.                c.blue   = colors[colorIndex].blue  << 8;
  1219.                c.flags  = DoRed | DoGreen | DoBlue;
  1220.                c.pixel  = index; 
  1221.                g->cmapColors[0][index] = c;
  1222.                g->cmapColors[1][index] = c;
  1223.                colors[colorIndex].value = index; 
  1224.  
  1225.                colors[colorIndex].stipple =(int)((double)NUMSTIPPLES *
  1226.                ((double)sqrt((double)(
  1227.                (double)colors[colorIndex].red *
  1228.                (double)colors[colorIndex].red +
  1229.                (double)colors[colorIndex].green *
  1230.                (double)colors[colorIndex].green +
  1231.                (double)colors[colorIndex].blue  *
  1232.                (double)colors[colorIndex].blue))
  1233.                / MAXCOLORDIST));
  1234.  
  1235.                colorIndex++;
  1236.                }
  1237.             index++;
  1238.             }
  1239.       }else{
  1240.          index = 17;
  1241.          index2 = 0;
  1242.          redIndex   = 0;
  1243.          greenIndex = 0;
  1244.          blueIndex  = 0;
  1245.  
  1246. /* Otherwise use a default lot */
  1247.  
  1248.          while(blueIndex < MAXVALUE){
  1249.             c.red    = (redIndex * VALUESCALE) << 8;
  1250.             c.green  = (greenIndex * VALUESCALE) << 8;
  1251.             c.blue   = (blueIndex * VALUESCALE) << 8;
  1252.             c.flags  = DoRed | DoGreen | DoBlue;
  1253.             c.pixel  = index; 
  1254.             g->cmapColors[0][index] = c;
  1255.             g->cmapColors[1][index] = c;
  1256.  
  1257.             redIndex++;
  1258.  
  1259.             if(redIndex >= MAXVALUE){
  1260.                redIndex = 0;
  1261.                greenIndex++;
  1262.                }
  1263.  
  1264.             if(greenIndex >= MAXVALUE){
  1265.                greenIndex = 0;
  1266.                blueIndex++;
  1267.                }
  1268.             index++;
  1269.             }
  1270.  
  1271.          for(index = 0; index < numColors; index++){
  1272.             colors[index].value = colors[index].red * 36 +
  1273.                colors[index].green * 6 + colors[index].blue + 17;
  1274.  
  1275.             colors[colorIndex].stipple =(int)((double)NUMSTIPPLES *
  1276.             ((double)sqrt((double)(
  1277.             (double)colors[colorIndex].red *
  1278.             (double)colors[colorIndex].red +
  1279.             (double)colors[colorIndex].green *
  1280.             (double)colors[colorIndex].green +
  1281.             (double)colors[colorIndex].blue  *
  1282.             (double)colors[colorIndex].blue))
  1283.             / MAXCOLORDIST));
  1284.  
  1285.             }
  1286.          }
  1287.       }
  1288.  
  1289. /* Set the colors for the special fast colormap double buffer */
  1290.  
  1291.    index = 0;
  1292.    for(redIndex = 0; redIndex < 4; redIndex++){
  1293.       for(blueIndex = 0; blueIndex < 4; blueIndex++){
  1294.           if(redIndex != blueIndex){
  1295.              g->wireframeColors[0][index] =
  1296.                 g->cmapColors[0][(redIndex + 12) * 16 + (blueIndex + 12)];
  1297.              g->wireframeColors[1][index] =
  1298.                 g->cmapColors[1][(redIndex + 12) * 16 + (blueIndex + 12)];
  1299.              index++;
  1300.              }
  1301.           }
  1302.       }
  1303.  
  1304. /* Just in case set the rest of the colors */
  1305.  
  1306.    for(index = 13; index < 256; index++){
  1307.       g->wireframeColors[0][index] = g->wireframeColors[0][3];
  1308.       g->wireframeColors[1][index] = g->wireframeColors[1][3];
  1309.       }
  1310.  
  1311. /* Set the colors for the pix stereo mode */
  1312.  
  1313.    for(redIndex = 0; redIndex < 15; redIndex++){
  1314.       for(blueIndex = 0; blueIndex < 15; blueIndex++){
  1315.          c.red    = (redIndex * 17) << 8;
  1316.          c.green  = 0;
  1317.          c.blue   = (blueIndex * 17) << 8;
  1318.          c.flags  = DoRed | DoGreen | DoBlue;
  1319.          c.pixel  = (redIndex + 1) * 16 + (blueIndex + 1); 
  1320.          g->cmapColors[2][c.pixel] = c;
  1321.          }
  1322.       }
  1323.  
  1324. /* Set stereoColor to nearest color */
  1325.  
  1326.    for(index = 0; index < numColors; index++){
  1327.       colorIndex = (int)((double)15 *
  1328.       ((double)sqrt((double)((double)colors[index].red *
  1329.       (double)colors[index].red + (double)colors[index].green *
  1330.       (double)colors[index].green + (double)colors[index].blue *
  1331.       (double)colors[index].blue)) / MAXCOLORDIST));
  1332.  
  1333.       colors[index].stereoColor = (colorIndex + 1) * 16 + (colorIndex + 1);  
  1334.       }
  1335.  
  1336. /* Set various important color values */
  1337.  
  1338.    g->stereoBlack  = (0 + 1) * 16 + (0 + 1); 
  1339.    g->redMask  = BUFFER0; 
  1340.    g->blueMask = BUFFER1; 
  1341.    g->Black  = colors[numColors].value; 
  1342.    g->Red    = colors[numColors + 1].value; 
  1343.    g->Blue   = colors[numColors + 2].value; 
  1344.    g->Purple = colors[numColors + 3].value; 
  1345. }
  1346.  
  1347.  
  1348.  
  1349. static void TwentyFourBitSetColors(g)
  1350. Ginfo *g;
  1351. /******************************************************************************
  1352.    Set up color information/stipples for a twenty-four  bit display.
  1353. ******************************************************************************/
  1354. {
  1355. int index, colorValue;
  1356. Color *colors;
  1357. int numColors;
  1358.  
  1359.    colors = g->colors;
  1360.    numColors = g->numColors;
  1361.  
  1362.    for(index = 0; index < numColors; index++){
  1363.  
  1364. /* In 24 bit every color is what it is */
  1365.  
  1366.       colors[index].value = 
  1367.       colors[index].red << 16 |
  1368.       colors[index].green << 8 |
  1369.       colors[index].blue; 
  1370.  
  1371. /* Set stipple */
  1372.  
  1373.       colors[index].stipple =(int)((double)NUMSTIPPLES *
  1374.       ((double)sqrt((double)(
  1375.       (double)colors[index].red   * (double)colors[index].red +
  1376.       (double)colors[index].green * (double)colors[index].green +
  1377.       (double)colors[index].blue  * (double)colors[index].blue))
  1378.       / MAXCOLORDIST));
  1379.       
  1380. /* Set stereo color */
  1381.  
  1382.       colorValue= (int)((double)255 *
  1383.       ((double)sqrt((double)((double)colors[index].red *
  1384.       (double)colors[index].red + (double)colors[index].green *
  1385.       (double)colors[index].green + (double)colors[index].blue *
  1386.       (double)colors[index].blue)) / MAXCOLORDIST));
  1387.  
  1388.       colors[index].stereoColor = colorValue << 16 | colorValue; 
  1389.       }   
  1390.  
  1391. /* Set various important color values */
  1392.  
  1393.    g->stereoBlack  = 0; 
  1394.    g->redMask  = 255 << 16; 
  1395.    g->blueMask = 255; 
  1396.    g->Black  = 0; 
  1397.    g->Red    = 255 << 16; 
  1398.    g->Blue   = 255; 
  1399.    g->Purple = (255 << 16) | 255; 
  1400. }
  1401.  
  1402.  
  1403.  
  1404. static void InitDisplay(o, g)
  1405. Oinfo *o;
  1406. Ginfo *g;
  1407. /******************************************************************************
  1408.    Set up an X window and our colormap.  We rely on X's own error handling and
  1409.    reporting for most bad X calls because X buffers requests.
  1410. ******************************************************************************/
  1411. {
  1412. static int stipples[NUMSTIPPLES][NUMSTIPPLES * 2 + 1] = {
  1413. {0},
  1414. {1, 1, 1},
  1415. {2, 0, 2, 2, 1},
  1416. {3, 1, 0, 1, 2, 3, 1},
  1417. {4, 0, 1, 0, 3, 2, 1, 2, 3},
  1418. {5, 0, 0, 0, 2, 2, 0, 2, 3, 3, 2},
  1419. {6, 0, 2, 1, 1, 1, 3, 2, 0, 3, 1, 3, 3},
  1420. {7, 0, 1, 0, 3, 1, 0, 1, 1, 2, 2, 3, 1, 3, 3},
  1421. {8, 0, 1, 0, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 0, 3, 2},
  1422. {9, 0, 0, 0, 2, 1, 2, 1, 3, 2, 0, 2, 1, 2, 3, 3, 1, 3, 2},
  1423. {10,0, 0, 0, 1, 0, 3, 1, 0, 1, 2, 2, 1, 2, 2, 2, 3, 3, 0, 3, 2},
  1424. {11,0, 1, 0, 3, 1, 0, 1, 1, 1, 2, 1, 3, 2, 1, 2, 2, 3, 0, 3, 2, 3, 3},
  1425. {12,0, 0, 0, 2, 1, 0, 1, 1, 1, 2, 1, 3, 2, 1, 2, 3, 3, 0, 3, 1, 3, 2, 3, 3},
  1426. {13,0, 0, 0, 2, 0, 3, 1, 0, 1, 1, 1, 2, 2, 0, 2, 2, 2, 3, 3, 0, 3, 1, 3, 2,
  1427.  3, 3},
  1428. {14,0, 0, 0, 1, 0, 2, 0, 3, 1, 0, 1, 1, 1, 3, 2, 1, 2, 2, 2, 3, 3, 0, 3, 1,
  1429.  3, 2, 3, 3},
  1430. {15,0, 0, 0, 1, 0, 2, 0, 3, 1, 0, 1, 2, 1, 3, 2, 0, 2, 1, 2, 2, 2, 3, 3, 0,
  1431.  3, 1, 3, 2, 3, 3},
  1432. {16,0, 0, 0, 1, 0, 2, 0, 3, 1, 0, 1, 1, 1, 2, 1, 3, 2, 0, 2, 1, 2, 2, 2, 3,
  1433.  3, 0, 3, 1, 3, 2, 3, 3}
  1434. };
  1435.  
  1436. char bits[(STIPPLESIZE * STIPPLESIZE) / BITSPERBYTE];
  1437.  
  1438. GC temp_gc;
  1439. XColor oldColormap[MAXCOLORS];
  1440. XWindowAttributes attributes;
  1441. XSetWindowAttributes attribs;
  1442. XWMHints wmhint;
  1443. int index, index2, screen;
  1444. XVisualInfo vInfo;
  1445. XSizeHints sizehint;
  1446. int x, y, NUMCOLORS;
  1447. unsigned int width, height, numSegments;
  1448.  
  1449.    numSegments = o->numSegs;
  1450.  
  1451.    if((g->redColors = (long *)calloc(1, (numSegments + 4) * (sizeof(long))))
  1452.     == NULL){
  1453. (void)fprintf(stderr, "Unable to allocate memory for redColors\n"); exit(1);}
  1454.  
  1455.    if((g->redSegments = (XSegment *)calloc(1, (numSegments + 4) *
  1456.    (sizeof(XSegment)))) == NULL){
  1457. (void)fprintf(stderr, "Unable to allocate memory for redSegments\n"); exit(1);}
  1458.  
  1459.    if((g->blueSegments = (XSegment *)calloc(1, (numSegments + 4) *
  1460.    sizeof(XSegment))) == (XSegment *)NULL){
  1461. (void)fprintf(stderr, "Unable to allocate memory for blueSegments\n"); exit(1);}
  1462.  
  1463. /* Can we connect with the server? */
  1464.  
  1465.    if((g->dpy = XOpenDisplay(g->DisplayName)) == NULL){
  1466.       fprintf(stderr, "Cannot connect to server\n");
  1467.       exit(1);
  1468.       }
  1469.  
  1470.    screen = DefaultScreen(g->dpy);
  1471.    g->black =  (long)BlackPixel(g->dpy, screen);
  1472.    g->white =  (long)WhitePixel(g->dpy, screen);
  1473.  
  1474. /* Initialize various flags and default values */
  1475.  
  1476.    g->requestSize = XMaxRequestSize(g->dpy) / REQUESTFACTOR;
  1477.    g->dpyX = DisplayWidth(g->dpy, screen);
  1478.    g->dpyY = DisplayHeight(g->dpy, screen);
  1479.    g->winX = g->dpyX / 2;
  1480.    g->winY = g->dpyY / 2 /* - 25 */ ;
  1481.    g->mono = g->ColorSelect = g->oldPointerX = g->oldPointerY = 0;
  1482.    g->Block = 1;
  1483.    g->Relative = 0;
  1484.  
  1485. /* Initialize the fonts */
  1486.  
  1487.    if((g->font = XLoadQueryFont(g->dpy, FONT)) == NULL){
  1488.       fprintf(stderr, "Unable to load font: %s ... trying fixed\n", FONT);
  1489.  
  1490.       if((g->font = XLoadQueryFont(g->dpy, FIXED)) == NULL){
  1491.          fprintf(stderr, "Unable to load font: %s\n", FIXED);
  1492.          exit(1);
  1493.          }
  1494.       }
  1495.  
  1496.    if((g->titleFont = XLoadQueryFont(g->dpy, TITLEFONT)) == NULL){
  1497.       fprintf(stderr, "Unable to load font: %s ... trying fixed\n", TITLEFONT);
  1498.  
  1499.       if((g->titleFont = XLoadQueryFont(g->dpy, FIXED)) == NULL){
  1500.          fprintf(stderr, "Unable to load font: %s\n", FIXED);
  1501.          exit(1);
  1502.          }
  1503.       }
  1504.  
  1505.    if((g->boldFont = XLoadQueryFont(g->dpy, BOLDFONT)) == NULL){
  1506.       fprintf(stderr, "Unable to load font: %s ... trying fixed\n", BOLDFONT);
  1507.  
  1508.       if((g->boldFont = XLoadQueryFont(g->dpy, FIXED)) == NULL){
  1509.          fprintf(stderr, "Unable to load font: %s\n", FIXED);
  1510.          exit(1);
  1511.          }
  1512.       }
  1513.  
  1514. /* Which visual do we get? */
  1515.  
  1516.    g->depth = ONE;
  1517.  
  1518. /* An 8 bit PseudoColor ? */
  1519.  
  1520.    if(XMatchVisualInfo(g->dpy, screen, 8, PseudoColor, &vInfo)){
  1521.       g->depth = EIGHT;
  1522.    }else{
  1523.  
  1524. /* A 24 bit TrueColor ? */
  1525.  
  1526.      if(XMatchVisualInfo(g->dpy, screen, 24, TrueColor, &vInfo)){
  1527.         g->depth = TWENTYFOUR;
  1528.         }
  1529.      }
  1530.  
  1531.    g->pix = XCreatePixmap(g->dpy, RootWindow(g->dpy,screen), g->winX,
  1532.    g->winY, g->depth);
  1533.  
  1534. /* Everything else we treat as monochrome whether or not
  1535.    something better may be supported */
  1536.  
  1537. /* Make a vanilla window */
  1538.  
  1539.    g->helpWinX =XTextWidth(g->font, LONGESTSTRING, strlen(LONGESTSTRING));
  1540.    g->helpWinY = FONTHEIGHT(g->font) * HELPLINES;
  1541.  
  1542.    g->helpWin = XCreateSimpleWindow(g->dpy, RootWindow(g->dpy, screen), 0, 0,
  1543.       g->helpWinX, g->helpWinY, 0, 0, 0);
  1544.  
  1545.    g->win = XCreateSimpleWindow(g->dpy, RootWindow(g->dpy,screen), 0, 0,
  1546.       g->winX, g->winY, 0, 0, 0);
  1547.  
  1548. /* Any user geometry? */
  1549.  
  1550.    if(g->Geometry){
  1551.  
  1552.       x = 0;
  1553.       y = 0;
  1554.       width = g->winX;
  1555.       height = g->winY;
  1556.       sizehint.flags = USPosition | USSize;
  1557.  
  1558.       XParseGeometry(g->Geometry, &x, &y, &width, &height); 
  1559.  
  1560.       sizehint.x = x;
  1561.       sizehint.y = y;
  1562.       sizehint.width  = width;
  1563.       sizehint.height = height;
  1564.       g->winX = width;
  1565.       g->winY = height;
  1566.  
  1567.       XResizeWindow(g->dpy, g->win, width, height);
  1568.       XSetNormalHints(g->dpy, g->win, &sizehint);
  1569.       } 
  1570.  
  1571. /* Set horizontal and vertical ranges */
  1572.  
  1573.    g->winH = (int)(g->winX / 2.0); 
  1574.    g->winV = (int)(g->winY / 2.0); 
  1575.  
  1576. /* Make our graphics context */
  1577.  
  1578.    g->gc = XCreateGC(g->dpy, g->win, 0x0, NULL);
  1579.    g->helpGc = XCreateGC(g->dpy, g->helpWin, 0x0, NULL);
  1580.  
  1581. /* Create Tiles for monochrome display */
  1582.  
  1583.    for(index = 0; index < NUMSTIPPLES; index++){
  1584.       g->stipple[index]= XCreateBitmapFromData(g->dpy, g->win, bits,
  1585.       STIPPLESIZE, STIPPLESIZE);
  1586.       temp_gc = XCreateGC(g->dpy, g->stipple[index], 0x0, NULL);
  1587.       XSetForeground(g->dpy, temp_gc, 0);
  1588.       XFillRectangle(g->dpy, g->stipple[index], temp_gc, 0, 0, STIPPLESIZE,
  1589.       STIPPLESIZE);
  1590.       XSetForeground(g->dpy, temp_gc, 1);
  1591.       for(index2 = 0; index2 < stipples[index][0]; index2++){
  1592.          XDrawPoint(g->dpy, g->stipple[index], temp_gc,
  1593.          stipples[index][index2 * 2 + 1], stipples[index][index2 * 2 + 2]);
  1594.          }
  1595.       XFreeGC(g->dpy, temp_gc);
  1596.       }
  1597.  
  1598. /* We want to have the input focus if we can */
  1599.  
  1600.    XSetInputFocus(g->dpy, PointerRoot, RevertToNone, CurrentTime);
  1601.  
  1602. /*
  1603.    Thanks go to Otmar Lendl for the following bit of code that
  1604.    permits the program to work properly with losing window managers
  1605.    that don't handle input focus correctly.
  1606. */
  1607.  
  1608.    wmhint.input = True;
  1609.    wmhint.flags = InputHint;
  1610.    XSetWMHints(g->dpy,g->win,&wmhint);
  1611.  
  1612. /* Please do not do backing store on the contents of our window */
  1613.  
  1614.    attribs.backing_store = NotUseful;
  1615.    XChangeWindowAttributes(g->dpy, g->win, CWBackingStore, &attribs);
  1616.  
  1617. /* We only want certain kinds of events */
  1618.  
  1619.    XSelectInput(g->dpy, g->win, ButtonPressMask | ButtonReleaseMask |
  1620.       KeyPressMask | Button1MotionMask | Button2MotionMask |
  1621.       StructureNotifyMask | ExposureMask | ColormapChangeMask);
  1622.  
  1623.    XSelectInput(g->dpy, g->helpWin, ButtonPressMask | ButtonReleaseMask |
  1624.       KeyPressMask | Button1MotionMask | Button2MotionMask |
  1625.       StructureNotifyMask | ExposureMask | ColormapChangeMask);
  1626.  
  1627. /* Do not generate expose events */
  1628.  
  1629.    XSetGraphicsExposures(g->dpy, g->gc, 0);
  1630.  
  1631. /* Name our windows */
  1632.  
  1633.    XStoreName(g->dpy, g->win, "X3D"); 
  1634.    XStoreName(g->dpy, g->helpWin, "X3D Help"); 
  1635.  
  1636. /* Some window managers are not friendly, explicitly set the background color */
  1637.  
  1638.    XSetWindowBackground(g->dpy, g->win, g->black);
  1639.  
  1640.    if(g->depth == ONE){
  1641.       OneBitSetColors(g);
  1642.       }
  1643.  
  1644.    if(g->depth == TWENTYFOUR){
  1645.       TwentyFourBitSetColors(g);
  1646.       }
  1647.  
  1648.    if(g->depth == EIGHT){
  1649.  
  1650.       NUMCOLORS = 256;
  1651.  
  1652. /* Make our colormap */
  1653.  
  1654.       g->colormap = XCreateColormap(g->dpy, g->win, DefaultVisual(g->dpy,
  1655.       screen), AllocAll);
  1656.  
  1657. /* Get the current colormap */
  1658.  
  1659.       XGetWindowAttributes(g->dpy, RootWindow(g->dpy,screen), &attributes);
  1660.  
  1661. /* Since we only use 16 colors, set all our other entries to the old values.
  1662.    Hopefully some other windows might display in true colors */
  1663.     
  1664.       for(index = 0; index < NUMCOLORS; index++)
  1665.          oldColormap[index].pixel = index;
  1666.  
  1667.       XQueryColors(g->dpy, attributes.colormap, oldColormap, NUMCOLORS);
  1668.       XStoreColors(g->dpy, g->colormap, oldColormap, NUMCOLORS);
  1669.  
  1670. /* Set up the colormap */
  1671.  
  1672.       EightBitSetColors(g);
  1673.  
  1674. /* Set our special 12 colors to something */
  1675.  
  1676.       XStoreColors(g->dpy, g->colormap, g->cmapColors[0], 256);
  1677.       XSetWindowColormap(g->dpy, g->helpWin, g->colormap);
  1678.       XSetWindowColormap(g->dpy, g->win, g->colormap);
  1679.    }
  1680.  
  1681. /* Make the purple rectangle */
  1682.  
  1683.    ResetPurpleRectangle(0, 0, g->winX, g->winY, g);
  1684.  
  1685. /* 
  1686.    Make the windows appear. 
  1687. */
  1688.    XMapWindow(g->dpy, g->win);
  1689.    DisplayMenu(g);
  1690. }
  1691.  
  1692.  
  1693.  
  1694. static int CheckEvent(display, event, arg)
  1695. Display *display;
  1696. XEvent *event;
  1697. char *arg;
  1698. /******************************************************************************
  1699.    Check an event to see if it is one we are interested in.
  1700.    This is used by X to wake up our program once some interesting event
  1701.    happens.  Returns: 1 if we are interested, 0 if we are not. 
  1702. ******************************************************************************/
  1703. {
  1704.    if(event == NULL){
  1705.       fprintf(stderr, "WARNING: Null event in CheckEvent()!!\n");
  1706.       }
  1707.  
  1708.    if((event->type == MotionNotify) || (event->type == KeyPress) ||
  1709.       (event->type == ConfigureNotify) || (event->type == Expose) ||
  1710.       (event->type == ColormapNotify))
  1711.       return 1;
  1712.  
  1713.    return 0;
  1714. }
  1715.  
  1716.  
  1717.  
  1718. static void GetInput(pointerX, pointerY, command, same, g)
  1719. int *pointerX, *pointerY;
  1720. char *command;
  1721. int *same;
  1722. Ginfo *g;
  1723. /******************************************************************************
  1724.    Get an interesting event and update the user input information.
  1725.  
  1726.    The routine will eventually block waiting for an event if block is 1 
  1727.    and the no events of interest have shown up.
  1728. ******************************************************************************/
  1729. {
  1730. XEvent event;
  1731. XSizeHints sizehint;
  1732. int  numEvents;
  1733. char string[TMPSTRLEN];
  1734.  
  1735. /* set command to a meaningless value (hopefully) */
  1736.  
  1737.    *command = '\0';
  1738.  
  1739.    do{
  1740.        string[0] = '\0';
  1741.  
  1742. /* How many events? */
  1743.  
  1744.        numEvents = XEventsQueued(g->dpy, QueuedAfterReading);
  1745.  
  1746. /* Block to obtain an event yet? */
  1747.  
  1748.        if((numEvents == 0) && (g->Block)){
  1749.  
  1750. /* If the user falls asleep stop using CPU cycles */
  1751.  
  1752.           XIfEvent(g->dpy, &event, CheckEvent, NULL);
  1753.           numEvents = 1;
  1754.        }else{
  1755.  
  1756. /* If we have at least one event , fetch the first event off the queue*/
  1757.  
  1758.           if(numEvents)
  1759.              XNextEvent(g->dpy,&event);
  1760.        }
  1761.  
  1762.    }while((numEvents == 0) && (g->Block));
  1763.  
  1764. /* Process the events we have obtained (if any) */
  1765.        
  1766.    while(numEvents){
  1767.  
  1768.       switch(event.type){
  1769.  
  1770.          case MotionNotify    : 
  1771.             if(numEvents == 1){
  1772.                *pointerX = (int)event.xmotion.x;
  1773.                *pointerY = (int)event.xmotion.y;
  1774.             }
  1775.             break;
  1776.  
  1777.          case KeyPress        :
  1778.             if(numEvents == 1){
  1779.                XLookupString(&event.xkey,string,TMPSTRLEN,NULL,NULL);
  1780.                *command = string[0];
  1781.                }
  1782.             break;
  1783.  
  1784.          case ConfigureNotify :
  1785.  
  1786.             if(event.xconfigure.window == g->win){
  1787.  
  1788.                g->winX = event.xconfigure.width;
  1789.                g->winY = event.xconfigure.height;
  1790.                g->winH = (int)(g->winX / 2.0); 
  1791.                g->winV = (int)(g->winY / 2.0); 
  1792.                ResetPurpleRectangle(0, 0, g->winX, g->winY, g);
  1793.                sizehint.flags  = USSize | USPosition;
  1794.                sizehint.width  = g->winX;
  1795.                sizehint.height = g->winY;
  1796.                XSetNormalHints(g->dpy, g->win, &sizehint);
  1797.  
  1798. /* Resize our pix etc... */
  1799.  
  1800.                XFreePixmap(g->dpy, g->pix);
  1801.  
  1802.                g->pix = XCreatePixmap(g->dpy, g->win, g->winX, g->winY,
  1803.                g->depth);
  1804.  
  1805.                }
  1806.             if(event.xconfigure.window == g->helpWin){
  1807.                DisplayMenu(g);
  1808.                }
  1809.             g->modeChanged = 1;
  1810.             *same = 0;
  1811.             break;
  1812.  
  1813.          case Expose          :
  1814.             if(event.xexpose.window == g->helpWin){
  1815.                DisplayMenu(g);
  1816.                }
  1817.             *same = 0;
  1818.             break;
  1819.  
  1820.          case MapNotify       :
  1821.  
  1822.             if(event.xmap.window == g->helpWin){
  1823.    
  1824.                sizehint.flags = USPosition | USSize;
  1825.                XSetNormalHints(g->dpy, g->helpWin, &sizehint);
  1826.  
  1827.                DisplayMenu(g);
  1828.                }
  1829.             g->modeChanged = 1;
  1830.             *same = 0;
  1831.             break;
  1832.  
  1833.          case ColormapNotify  :
  1834.  
  1835.             if(event.xcolormap.colormap == g->colormap){
  1836.  
  1837.                if(event.xcolormap.state == ColormapUninstalled){
  1838.                   g->mono = 1;
  1839.                }else{
  1840.                   g->mono = 0;
  1841.                   }
  1842.  
  1843.               g->modeChanged = 1;
  1844.               *same = 0;
  1845.               }
  1846.             break;
  1847.  
  1848.          default              :
  1849.             break;
  1850.          }
  1851.  
  1852.          numEvents--;
  1853.  
  1854.          if(numEvents)
  1855.             XNextEvent(g->dpy,&event);
  1856.       }
  1857. }
  1858.  
  1859.  
  1860.  
  1861. static void UpdatePosition(o, g)
  1862. Oinfo *o;
  1863. Ginfo *g;
  1864. /******************************************************************************
  1865.    Update the scene position information using user input. 
  1866.  
  1867.    The routine will eventually block waiting for an event if block is True
  1868.    and the no events of interest show up due to the call to GetInput()
  1869. ******************************************************************************/
  1870. {
  1871. int same, pointerX, pointerY, dx, dy;
  1872. char command;
  1873. double X, Y, Z;
  1874.  
  1875.    X = Y = Z = 0.0;
  1876.  
  1877.    same = 1;
  1878.       
  1879.    pointerX = g->oldPointerX;                             
  1880.    pointerY = g->oldPointerY;
  1881.  
  1882.    while(same) {
  1883.    
  1884. /* dx, dy, dz are the amount to step about each axis every frame 
  1885.    We want the scene to continue to rotate even if the user does
  1886.    not give any new input */
  1887.  
  1888. /* Do not forget to put your automatic update variables into this if
  1889.    statement.  Be careful somehow you can get MANY bugs with these!  */
  1890.  
  1891.       if((o->dX) || (o->dY) || (o->dZ)){
  1892.          same = 0;
  1893.          g->Block = 0;
  1894.       }else
  1895.          g->Block = 1;
  1896.  
  1897. /* Get the input */
  1898.  
  1899.       GetInput(&pointerX, &pointerY, &command, &same, g);
  1900.  
  1901. /* Fill in code for your favorite keyboard and pointer controls */
  1902.  
  1903. /* My default controls */
  1904.  
  1905. /* Note: I do not move the origin which the scene is rotated about around.
  1906.    You may want to do oX += ???; oY += ???; oZ += ???    */  
  1907.  
  1908.       switch(command){
  1909.          case ' ' : break;
  1910.          case 'm' : same = 0; g->helpMenu    = !g->helpMenu;
  1911.             if(g->helpMenu == False){
  1912.                XUnmapWindow(g->dpy, g->helpWin);
  1913.             }else{
  1914.                XMapWindow(g->dpy, g->helpWin);
  1915.                }
  1916.             break;
  1917.          case 'M' : same = 0; g->helpMenu    = !g->helpMenu;
  1918.             if(g->helpMenu == False){
  1919.                XUnmapWindow(g->dpy, g->helpWin);
  1920.             }else{
  1921.                XMapWindow(g->dpy, g->helpWin);
  1922.                }
  1923.             break;
  1924.          case 's' : same = 0; g->stereo  = !g->stereo; g->modeChanged = 1;
  1925.             break;
  1926.          case 'S' : same = 0; g->stereo  = !g->stereo; g->modeChanged = 1;
  1927.             break;
  1928.          case 'd' : same = 0; g->stereoBlue = !g->stereoBlue;
  1929.             g->modeChanged = 1;break;
  1930.          case 'D' : same = 0; g->stereoBlue = !g->stereoBlue;
  1931.             g->modeChanged = 1;break;
  1932.          case 'f' : same = 0; g->buffer = !g->buffer; g->modeChanged = 1;break;
  1933.          case 'F' : same = 0; g->buffer = !g->buffer; g->modeChanged = 1;break;
  1934.          case 'o' : same = 0; g->Relative = !g->Relative; break;
  1935.          case 'O' : same = 0; g->Relative = !g->Relative; break;
  1936.          case 'w' : same = 0; g->renderMode = WIREFRAME; g->modeChanged = 1;
  1937.             break;
  1938.          case 'W' : same = 0; g->renderMode = WIREFRAME; g->modeChanged = 1;
  1939.             break;
  1940.          case 'e' : same = 0; g->renderMode = HIDDENLINE; g->modeChanged = 1;
  1941.             break;
  1942.          case 'E' : same = 0; g->renderMode = HIDDENLINE; g->modeChanged = 1;
  1943.             break;
  1944.          case 'r' : same = 0; g->renderMode = SOLID; g->modeChanged = 1;break;
  1945.          case 'R' : same = 0; g->renderMode = SOLID; g->modeChanged = 1;break;
  1946.          case 'l' : same = 0; o->tX  -= 100.0; break;
  1947.          case 'j' : same = 0; o->tY  -= 100.0; break;
  1948.          case 'k' : same = 0; o->tY  += 100.0; break;
  1949.          case 'h' : same = 0; o->tX  += 100.0; break;
  1950.          case 'i' : same = 0; o->tZ  += 100.0; break;
  1951.          case 'u' : same = 0; o->tZ  -= 100.0; break;
  1952.          case 'L' : same = 0; o->tX  -= 500.0; break;
  1953.          case 'J' : same = 0; o->tY  -= 500.0; break;
  1954.          case 'K' : same = 0; o->tY  += 500.0; break;
  1955.          case 'H' : same = 0; o->tX  += 500.0; break;
  1956.          case 'I' : same = 0; o->tZ  += 500.0; break;
  1957.          case 'U' : same = 0; o->tZ  -= 500.0; break;
  1958.          case '1' : same = 0; o->dX += 0.02; break;
  1959.          case '2' : same = 0; o->dX =  0.0 ; break;
  1960.          case '3' : same = 0; o->dX -= 0.02; break;
  1961.          case '4' : same = 0; o->dY -= 0.02; break;
  1962.          case '5' : same = 0; o->dY =  0.0 ; break;
  1963.          case '6' : same = 0; o->dY += 0.02; break;
  1964.          case '7' : same = 0; o->dZ += 0.02; break;
  1965.          case '8' : same = 0; o->dZ =  0.0 ; break;
  1966.          case '9' : same = 0; o->dZ -= 0.02; break;
  1967.          case 'x' : same = 0; X -= 0.03; break;
  1968.          case 'X' : same = 0; X += 0.03; break;
  1969.          case 'y' : same = 0; Y += 0.03; break;
  1970.          case 'Y' : same = 0; Y -= 0.03; break;
  1971.          case 'z' : same = 0; Z -= 0.03; break;
  1972.          case 'Z' : same = 0; Z += 0.03; break;
  1973.          case 'a' : same = 0; X -= 0.05; break;
  1974.          case 'A' : same = 0; X += 0.05; break;
  1975.          case 'b' : same = 0; Y += 0.05; break;
  1976.          case 'B' : same = 0; Y -= 0.05; break;
  1977.          case 'c' : same = 0; Z -= 0.05; break;
  1978.          case 'C' : same = 0; Z += 0.05; break;
  1979.          case '[' : same = 0;
  1980.                     o->focus = o->focus += 0.1;
  1981.                     if((o->focus > 1.8))
  1982.                        o->focus = 1.8;
  1983.                     break;
  1984.          case ']' : same = 0;
  1985.                     o->focus = o->focus -= 0.1;
  1986.                     if((o->focus < -0.8))
  1987.                        o->focus = -0.8;
  1988.                     break;
  1989.          case '{' : same = 0; o->BViewpointX -= 4.0; break;
  1990.          case '}' : same = 0; o->BViewpointX += 4.0; break;
  1991.          case 'q' : XFreePixmap(g->dpy, g->pix); exit(0);
  1992.          case 'Q' : XFreePixmap(g->dpy, g->pix); exit(0);
  1993.  
  1994.          default : {
  1995.  
  1996. /* My pointer movement stuff */
  1997.  
  1998. /* Only update if the movement was reasonably small */
  1999.              
  2000.             dx = pointerX - g->oldPointerX;
  2001.             dy = pointerY - g->oldPointerY;
  2002.  
  2003.             if((dy * dy <= SMALLMOVEMENT) &&
  2004.                (dx * dx <= SMALLMOVEMENT)){
  2005.  
  2006. /* Rotate proportionally with the amount the pointer moved */
  2007. /* Note: I only control the X and Z axes by the pointer */
  2008.             
  2009.                X -= (dy * POINTERRATIO);
  2010.                Z -= (dx * POINTERRATIO);
  2011.                same = 0;
  2012.                }
  2013.  
  2014.             g->oldPointerY = pointerY;
  2015.             g->oldPointerX = pointerX;
  2016.             }
  2017.          }
  2018.       }
  2019.  
  2020. /* Keep angles 0 - 6.28 */
  2021.  
  2022.    X = fmod(X + o->dX, TWOPI);
  2023.    Y = fmod(Y + o->dY, TWOPI);
  2024.    Z = fmod(Z + o->dZ, TWOPI);
  2025.  
  2026. /* Fix up the angles */
  2027.  
  2028.    if(g->Relative){
  2029.       o->X = fmod(X + o->X, TWOPI);
  2030.       o->Y = fmod(Y + o->Y, TWOPI);
  2031.       o->Z = fmod(Z + o->Z, TWOPI);
  2032.    }else{
  2033.       CalculateAngles(&(o->X), &(o->Y), &(o->Z), X, Y, Z);
  2034.       }
  2035. }
  2036.  
  2037.  
  2038.  
  2039. static int clipSegment(pX, pY, qX, qY, Pclip, Qclip, H, V)
  2040. float *pX, *pY, *qX, *qY;
  2041. int Pclip, Qclip;
  2042. float H,V;
  2043. /******************************************************************************
  2044.    Calculate the portion of the projected line segment that is visible.
  2045. ******************************************************************************/
  2046. {
  2047. register float PX, PY, QX, QY, dx, dy;
  2048.  
  2049.    PX = *pX; QX = *qX;
  2050.    PY = *pY; QY = *qY;
  2051.  
  2052.    dx = QX - PX;
  2053.    dy = QY - PY;
  2054.  
  2055. /* Clip P first so it will be somewhere on the screen,
  2056.    if we cannot move P on screen the segment is not visible */
  2057.  
  2058. /* See x3d.h for the meaning of the clipping flags */
  2059.  
  2060.    switch(Pclip){
  2061.  
  2062.       case 1 :             /*  00001  */
  2063.          clipWithTop(PX, PY, dx, dy, V)
  2064.          if((PX < -H) || (PX > H))
  2065.             return 0;
  2066.          break;
  2067.  
  2068.       case 2 :             /*  00010  */
  2069.          clipWithBottom(PX, PY, dx, dy, V)
  2070.          if((PX < -H) || (PX > H))
  2071.             return 0;
  2072.          break;
  2073.  
  2074.       case 4 :             /*  00100  */
  2075.          clipWithLeftSide(PX, PY, dx, dy, H)
  2076.          if((PY < -V) || (PY > V))
  2077.             return 0;
  2078.          break;
  2079.  
  2080.       case 5 :             /*  00101  */
  2081.          clipWithTop(PX, PY, dx, dy, V)
  2082.          if((PX < -H) || (PX > H)){
  2083.             clipWithLeftSide(PX, PY, dx, dy, H)
  2084.             if((PY < -V) || (PY > V))
  2085.                return 0;
  2086.             }
  2087.          break;
  2088.  
  2089.       case 6 :             /*  00110  */
  2090.          clipWithBottom(PX, PY, dx, dy, V)
  2091.          if((PX < -H) || (PX > H)){
  2092.             clipWithLeftSide(PX, PY, dx, dy, H)
  2093.             if((PY < -V) || (PY > V))
  2094.                return 0;
  2095.             }
  2096.          break;
  2097.  
  2098.       case 8 :             /*  01000  */
  2099.          clipWithRightSide(PX, PY, dx, dy, H)
  2100.          if((PY < -V) || (PY > V))
  2101.             return 0;
  2102.          break;
  2103.  
  2104.       case 9 :             /*  01001  */
  2105.          clipWithTop(PX, PY, dx, dy, V)
  2106.          if((PX < -H) || (PX > H)){
  2107.             clipWithRightSide(PX, PY, dx, dy, H)
  2108.             if((PY < -V) || (PY > V))
  2109.                return 0;
  2110.             }
  2111.          break;
  2112.  
  2113.       case 10 :             /*  01010  */
  2114.          clipWithBottom(PX, PY, dx, dy, V)
  2115.          if((PX < -H) || (PX > H)){
  2116.             clipWithRightSide(PX, PY, dx, dy, H)
  2117.             if((PY < -V) || (PY > V))
  2118.                return 0;
  2119.             }
  2120.          break;
  2121.       
  2122.    }
  2123.  
  2124. /* P is now somewhere on screen, calculate where Q should be */
  2125.  
  2126.    switch(Qclip){
  2127.  
  2128.       case 1 :          /*  00001  */
  2129.          clipWithTop(QX, QY, dx, dy, V)
  2130.          break; 
  2131.  
  2132.       case 2 :          /*  00010  */
  2133.          clipWithBottom(QX, QY, dx, dy, V)
  2134.          break; 
  2135.  
  2136.       case 4 :          /*  00100  */
  2137.          clipWithLeftSide(QX, QY, dx, dy, H)
  2138.          break; 
  2139.  
  2140.       case 5 :          /*  00101  */
  2141.          clipWithTop(QX, QY, dx, dy, V)
  2142.          if(QX < -H)
  2143.             clipWithLeftSide(QX, QY, dx, dy, H) 
  2144.          break;
  2145.  
  2146.       case 6 :          /*  00110  */
  2147.          clipWithBottom(QX, QY, dx, dy, V)
  2148.          if(QX < -H)
  2149.             clipWithLeftSide(QX, QY, dx, dy, H) 
  2150.          break;
  2151.  
  2152.       case 8 :          /*  01000  */
  2153.          clipWithRightSide(QX, QY, dx, dy, H)
  2154.          break;
  2155.  
  2156.       case 9 :          /*  01001  */
  2157.          clipWithTop(QX, QY, dx, dy, V)
  2158.          if(QX > H)
  2159.             clipWithRightSide(QX, QY, dx, dy, H) 
  2160.          break;
  2161.  
  2162.       case 10 :          /*  01010  */
  2163.          clipWithBottom(QX, QY, dx, dy, V)
  2164.          if(QX > H)
  2165.             clipWithRightSide(QX, QY, dx, dy, H) 
  2166.          break;
  2167.  
  2168.       case 21 :          /*  10101  */
  2169.          clipWithTop(QX, QY, dx, dy, V)
  2170.          if(QX < -H)
  2171.             clipWithLeftSide(QX, QY, dx, dy, H) 
  2172.          break;
  2173.  
  2174.       case 22 :          /*  10110  */
  2175.          clipWithBottom(QX, QY, dx, dy, V)
  2176.          if(QX < -H)
  2177.             clipWithLeftSide(QX, QY, dx, dy, H) 
  2178.          break;
  2179.  
  2180.       case 23 :          /*  10111  */
  2181.          if(QY < PY) 
  2182.             clipWithTop(QX, QY, dx, dy, V)
  2183.          else
  2184.             clipWithBottom(QX, QY, dx, dy, V)
  2185.          if(QX < -H)
  2186.             clipWithLeftSide(QX, QY, dx, dy, H) 
  2187.          break;
  2188.  
  2189.       case 25 :          /*  11001  */
  2190.          clipWithTop(QX, QY, dx, dy, V)
  2191.          if(QX > H)
  2192.             clipWithRightSide(QX, QY, dx, dy, H) 
  2193.          break;
  2194.  
  2195.       case 26 :          /*  11010  */
  2196.          clipWithBottom(QX, QY, dx, dy, V)
  2197.          if(QX > H)
  2198.             clipWithRightSide(QX, QY, dx, dy, H) 
  2199.          break;
  2200.  
  2201.       case 27 :          /*  11011  */
  2202.          if(QY < PY) 
  2203.             clipWithTop(QX, QY, dx, dy, V)
  2204.          else
  2205.             clipWithBottom(QX, QY, dx, dy, V)
  2206.          if(QX > H)
  2207.             clipWithRightSide(QX, QY, dx, dy, H) 
  2208.          break;
  2209.  
  2210.       case 29 :          /*  11101  */
  2211.          if(QX < PX) 
  2212.             clipWithRightSide(QX, QY, dx, dy, H)
  2213.          else
  2214.             clipWithLeftSide(QX, QY, dx, dy, H)
  2215.          if(QY > V)
  2216.             clipWithTop(QX, QY, dx, dy, V) 
  2217.          break;
  2218.  
  2219.       case 30 :          /*  11110  */
  2220.          if(QX < PX) 
  2221.             clipWithRightSide(QX, QY, dx, dy, H)
  2222.          else
  2223.             clipWithLeftSide(QX, QY, dx, dy, H)
  2224.          if(QY < -V)
  2225.             clipWithBottom(QX, QY, dx, dy, V) 
  2226.          break;
  2227.  
  2228.       case 31 :          /*  11111  */
  2229.          if(QX < PX) 
  2230.             clipWithRightSide(QX, QY, dx, dy, H)
  2231.          else
  2232.             clipWithLeftSide(QX, QY, dx, dy, H)
  2233.       
  2234.          if((QY < -V) || (QY > V))
  2235.             if(*qY < PY)
  2236.                clipWithTop(QX, QY, dx, dy, V) 
  2237.             else
  2238.                clipWithBottom(QX, QY, dx, dy, V) 
  2239.          break;
  2240.       
  2241.    }
  2242.  
  2243.    *pX = PX; *qX = QX;
  2244.    *pY = PY; *qY = QY;
  2245.    return 1; 
  2246. }
  2247.  
  2248.  
  2249.  
  2250. static void clip(o, g)
  2251. Oinfo *o;
  2252. Ginfo *g;
  2253. /******************************************************************************
  2254.    Clip a list of segments.
  2255. ******************************************************************************/
  2256. {
  2257. register int PClipFlags, QClipFlags, Pclip, Qclip, Tclip;
  2258. register float H, V;
  2259. register short pX, pY, qX, qY;
  2260. float PX, PY, QX, QY;
  2261. segment *seg, *lastSeg;
  2262. point *P, *Q, *T;
  2263. XSegment *red, *blue;
  2264. long *redCol;
  2265.  
  2266.    lastSeg = &(o->segs[o->numSegs]);
  2267.        seg = o->segs;
  2268.  
  2269.    H = (float)g->winH; 
  2270.    V = (float)g->winV;
  2271.  
  2272.    red  = &(g->redSegments[g->numberRed]);
  2273.    redCol = &(g->redColors[g->numRedColors]);
  2274.  
  2275.    if((g->mono) || ((g->stereo) && (!(g->stereoBlue))) ||
  2276.    ((g->renderMode == WIREFRAME) && (!g->stereo))){
  2277.  
  2278.       if(o->objClip){
  2279.  
  2280. /* For every segment ... */
  2281.  
  2282.          while(seg < lastSeg){
  2283.       
  2284.             P = seg->P;
  2285.             PClipFlags = P->ClipFlags;
  2286.             Q = seg->Q;
  2287.             QClipFlags = Q->ClipFlags;
  2288.  
  2289. /* Optimization for best case */
  2290.  
  2291.             if((PClipFlags | QClipFlags) == 0){
  2292.                *redCol = seg->color->value;
  2293.                redCol++;
  2294.                ((xsegment *)red)->P = P->R;
  2295.                ((xsegment *)red)->Q = Q->R;
  2296.                red++;
  2297.             }else{
  2298.  
  2299. /* Red segments */
  2300.  
  2301. /* Shuffle the bits around so we get the right configuration
  2302.    for the clipping function */
  2303.  
  2304.                Pclip = (PClipFlags & RBmask) | ((PClipFlags & RLeftRight) >> 3);
  2305.                Qclip = (QClipFlags & RBmask) | ((QClipFlags & RLeftRight) >> 3);
  2306.  
  2307.                if((Qclip | Pclip) == 0){
  2308.  
  2309.                *redCol = seg->color->value;
  2310.                redCol++;
  2311.                red->x1 = P->R.x;
  2312.                red->y1 = P->R.y;
  2313.                red->x2 = Q->R.x;
  2314.                red->y2 = Q->R.y;
  2315.                red++;
  2316.  
  2317.                }else{
  2318.  
  2319.                   if((Qclip & Pclip) == 0){
  2320.  
  2321. /* We make P be a point in front of us if there is one in front,
  2322.    (it simplifies the code) */
  2323.  
  2324.                      if((Pclip > Qclip) || (Pclip & Behind)){
  2325.                         T = P; P = Q; Q = T;
  2326.                         Tclip = Pclip; Pclip = Qclip; Qclip = Tclip;
  2327.                         }
  2328.  
  2329.                      PX = P->RX - H; PY = -(P->Y - V);
  2330.                      QX = Q->RX - H; QY = -(Q->Y - V);
  2331.  
  2332.                      if(clipSegment(&PX, &PY, &QX, &QY, Pclip, Qclip, H, V)){
  2333.  
  2334.                         *redCol = seg->color->value;
  2335.                         redCol++;
  2336.                         red->x1 = (short)(PX + H);
  2337.                         red->y1 = (short)(V - PY);
  2338.                         red->x2 = (short)(QX + H);
  2339.                         red->y2 = (short)(V - QY);
  2340.                         red++;
  2341.  
  2342.                         }
  2343.                      }
  2344.                   }
  2345.                }
  2346.          seg++;
  2347.          }
  2348.       }else{
  2349.  
  2350. /* Optimization for object completely visible */
  2351.  
  2352.          if((g->renderMode == WIREFRAME) && (g->stereo)){
  2353.             while(seg < lastSeg){
  2354.                   ((xsegment *)red)->P = seg->P->R;
  2355.                   ((xsegment *)red)->Q = seg->Q->R;
  2356.                   red++;
  2357.                   seg++;
  2358.                }
  2359.          }else{
  2360.             while(seg < lastSeg){
  2361.                   *redCol = seg->color->value;
  2362.                   redCol++;
  2363.                   ((xsegment *)red)->P = seg->P->R;
  2364.                   ((xsegment *)red)->Q = seg->Q->R;
  2365.                   red++;
  2366.                   seg++;
  2367.                }
  2368.             }
  2369.          }
  2370.    }else{
  2371.       blue = &(g->blueSegments[g->numberBlue]);
  2372.  
  2373.       if(o->objClip){
  2374.          while(seg < lastSeg){
  2375.    
  2376.             P = seg->P; Q = seg->Q;
  2377.             PClipFlags = P->ClipFlags;
  2378.             QClipFlags = Q->ClipFlags;
  2379.  
  2380. /* Optimization for best case */
  2381.  
  2382.             if((PClipFlags | QClipFlags) == 0){
  2383.  
  2384.                pX = P->R.x; pY = P->R.y;
  2385.                qX = Q->R.x; qY = Q->R.y;
  2386.                red->x1 = pX;
  2387.                red->y1 = pY;
  2388.                red->x2 = qX;
  2389.                red->y2 = qY;
  2390.                red++;
  2391.                pX = P->sBX; qX = Q->sBX;
  2392.                blue->x1 = pX;
  2393.                blue->y1 = pY;
  2394.                blue->x2 = qX;
  2395.                blue->y2 = qY;
  2396.                blue++;
  2397.  
  2398.             }else{
  2399.  
  2400. /* Red segments */
  2401.  
  2402. /* Shuffle the bits around so we get the right configuration
  2403.    for the clipping function */
  2404.  
  2405.                Pclip = (PClipFlags & RBmask) | ((PClipFlags & RLeftRight) >> 3);
  2406.                Qclip = (QClipFlags & RBmask) | ((QClipFlags & RLeftRight) >> 3);
  2407.  
  2408.                if((Qclip | Pclip) == 0){
  2409.  
  2410.                red->x1 = P->R.x;
  2411.                red->y1 = P->R.y;
  2412.                red->x2 = Q->R.x;
  2413.                red->y2 = Q->R.y;
  2414.                red++;
  2415.  
  2416.                }else{
  2417.  
  2418.                   if((Qclip & Pclip) == 0){
  2419.  
  2420. /* We make P be a point in front of us if there is one in front,
  2421.    (it simplifies the code) */
  2422.  
  2423.                      if((Pclip > Qclip) || (Pclip & Behind)){
  2424.                         T = P; P = Q; Q = T;
  2425.                         Tclip = Pclip; Pclip = Qclip; Qclip = Tclip;
  2426.                         }
  2427.  
  2428.                      PX = P->RX - H; PY = -(P->Y - V);
  2429.                      QX = Q->RX - H; QY = -(Q->Y - V);
  2430.  
  2431.                      if(clipSegment(&PX, &PY, &QX, &QY, Pclip, Qclip, H, V)){
  2432.    
  2433.                         red->x1 = (short)(PX + H);
  2434.                         red->y1 = (short)(V - PY);
  2435.                         red->x2 = (short)(QX + H);
  2436.                         red->y2 = (short)(V - QY);
  2437.                         red++;
  2438.  
  2439.                         }
  2440.  
  2441.                      }
  2442.                   }
  2443.  
  2444. /* Blue segments */
  2445.  
  2446.                PClipFlags = P->ClipFlags;
  2447.                QClipFlags = Q->ClipFlags;
  2448.  
  2449. /* Shuffle the bits around so we get the right configuration
  2450.    for the clipping function */
  2451.  
  2452.                Pclip = (PClipFlags & Rmask);
  2453.                Qclip = (QClipFlags & Rmask);
  2454.  
  2455.                if((Qclip | Pclip) == 0){
  2456.  
  2457.                   blue->x1 = P->sBX;
  2458.                   blue->y1 = P->R.y;
  2459.                   blue->x2 = Q->sBX;
  2460.                   blue->y2 = Q->R.y;
  2461.                   blue++;
  2462.  
  2463.                }else{
  2464.                   if((Qclip & Pclip) == 0){
  2465.  
  2466. /* We make P be a point in front of us if there is one in front,
  2467.    (it simplifies the code) */
  2468.  
  2469.                      if((Pclip > Qclip) || (Pclip & Behind)){
  2470.                         T = P; P = Q; Q = T;
  2471.                         Tclip = Pclip; Pclip = Qclip; Qclip = Tclip;
  2472.                         }
  2473.  
  2474. /* check the bits, clip if necessary, and add the segment to the
  2475.    appropriate buffer if visible */
  2476.  
  2477.                      PX = P->BX - H; PY = -(P->Y - V);
  2478.                      QX = Q->BX - H; QY = -(Q->Y - V);
  2479.  
  2480.                      if(clipSegment(&PX, &PY, &QX, &QY, Pclip, Qclip, H, V)){
  2481.  
  2482.                         blue->x1 = (short)(PX + H);
  2483.                         blue->y1 = (short)(V - PY);
  2484.                         blue->x2 = (short)(QX + H);
  2485.                         blue->y2 = (short)(V - QY);
  2486.                         blue++;
  2487.  
  2488.                         }
  2489.                      }
  2490.                   }
  2491.                }
  2492.             seg++;
  2493.          }
  2494.       }else{
  2495.  
  2496. /* Optimization for object completely visible */
  2497.  
  2498.          while(seg < lastSeg){
  2499.             P = seg->P; Q = seg->Q;
  2500.             pX = P->R.x; pY = P->R.y;
  2501.             qX = Q->R.x; qY = Q->R.y;
  2502.             red->x1 = pX;
  2503.             red->y1 = pY;
  2504.             red->x2 = qX;
  2505.             red->y2 = qY;
  2506.             red++;
  2507.             pX = P->sBX; qX = Q->sBX;
  2508.             blue->x1 = pX;
  2509.             blue->y1 = pY;
  2510.             blue->x2 = qX;
  2511.             blue->y2 = qY;
  2512.             blue++;
  2513.             seg++;
  2514.             }
  2515.  
  2516.          }
  2517.  
  2518.       g->numberBlue = blue - g->blueSegments;
  2519.    }
  2520.  
  2521.    g->numRedColors = redCol - g->redColors;
  2522.    g->numberRed = red - g->redSegments;
  2523. }
  2524.  
  2525.  
  2526. #ifdef USE_INTS
  2527.  
  2528. /* The REDROTATE macro does 3 rotates, 2 translates, 1 projection */
  2529.  
  2530. #define REDROTATE                                                         \
  2531.       r8 = p0->x + c16;                                                   \
  2532.       r5 = p0->y + c17;                                                   \
  2533.       r2 = ((r8 * c5 + r5 * c6) >> SHIFT);                                \
  2534.       r7 = ((r5 * c5 - r8 * c6) >> SHIFT);                                \
  2535.       r8 = p0->z + c18;                                                   \
  2536.       r5 = ((r7 * c3 + r8 * c4) >> SHIFT) + c12;                          \
  2537.       r6 = ((r8 * c3 - r7 * c4) >> SHIFT);                                \
  2538.       r7 = c7 + ((((r6 * c1 - r2 * c2) >> SHIFT) + c13) * c0) / r5;       \
  2539.       r8 = c9 - ((((r2 * c1 + r6 * c2) >> SHIFT) + c11) * c0) / r5;       \
  2540.       r5 = (c0 * 8192) / r5
  2541.  
  2542. /* Project the blue point too */
  2543.  
  2544. #define STEREOROTATE                                                      \
  2545.       r8 = p0->x + c16;                                                   \
  2546.       r5 = p0->y + c17;                                                   \
  2547.       r2 = ((r8 * c5 + r5 * c6) >> SHIFT);                                \
  2548.       r7 = ((r5 * c5 - r8 * c6) >> SHIFT);                                \
  2549.       r8 = p0->z + c18;                                                   \
  2550.       r5 = ((r7 * c3 + r8 * c4) >> SHIFT) + c12;                          \
  2551.       r6 = ((r8 * c3 - r7 * c4) >> SHIFT);                                \
  2552.       r7 = c7 + ((((r6 * c1 - r2 * c2) >> SHIFT) + c13) * c0) / r5;       \
  2553.       r8 = c9 - ((((r2 * c1 + r6 * c2) >> SHIFT) + c11) * c0) / r5;       \
  2554.       r9 = r8 - c15 - (c0 * c14) / r5;                                    \
  2555.       r5 = (c0 * 8192) / r5
  2556.  
  2557. #else
  2558.  
  2559. /* The REDROTATE macro does 3 rotates, 2 translates, 1 projection */
  2560.  
  2561. #define REDROTATE                                                         \
  2562.       r8 = p0->x + c16;                                                   \
  2563.       r5 = p0->y + c17;                                                   \
  2564.       r2 = r8 * c5 + r5 * c6;                                             \
  2565.       r7 = r5 * c5 - r8 * c6;                                             \
  2566.       r8 = p0->z + c18;                                                   \
  2567.       r5 = c0 / (r7 * c3 + r8 * c4 + c12);                                \
  2568.       r6 = r8 *  c3 - r7 * c4;                                            \
  2569.       r7 = c7 + (r6 * c1 - r2 * c2 + c13) * r5;                           \
  2570.       r8 = c9 - (r2 * c1 + r6 * c2 + c11) * r5
  2571.  
  2572. #define STEREOROTATE                                                      \
  2573.       REDROTATE;                                                          \
  2574.       r9 = r8 - c15 - r5 * c14
  2575.  
  2576. #endif
  2577.  
  2578.  
  2579. /* Set all the red clipping flags */
  2580.  
  2581. #define REDCLIPFLAGS                                                      \
  2582.      (r5 > 0) * ALLmask ^ (r7 < 0 | (r7 > c10) << ClipWithBottom |        \
  2583.       (r8 > c8) << RClipWithRight | (r8 <   0) << RClipWithLeft)
  2584.  
  2585. /* Set all the red and blue clipping flags */
  2586.  
  2587. #define STEREOCLIPFLAGS                                                   \
  2588.      (r5 > 0) * ALLmask ^ (r7 < 0 | (r7 > c10) << ClipWithBottom |        \
  2589.       (r8 > c8) << RClipWithRight | (r8 <   0) << RClipWithLeft  |        \
  2590.       (r9 > c8) << BClipWithRight | (r9 <   0) << BClipWithLeft)
  2591.  
  2592.  
  2593.  
  2594. static void rotate(o, g)
  2595. Oinfo *o;
  2596. Ginfo *g;
  2597. /******************************************************************************
  2598.    Rotate, project, and set the clipping flags for a list of points.
  2599. ******************************************************************************/
  2600. {
  2601. register number r2,r5,r6,r7,r8,r9;
  2602. register point *p0;
  2603. register number c1,c2,c3,c4,c5,c6;
  2604. register point  *p1;
  2605. register number c0,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18; 
  2606. register int    objClip;
  2607. register short  RX, BX;
  2608.  
  2609.    p0 = o->bounds; p1 = &(o->bounds[NUMBOUNDS]); c0 = (number)o->viewpointY;
  2610.    c1 = (number)(cos(o->Y) * TRIG_ADJ); c2 = (number)(sin(o->Y) * TRIG_ADJ);
  2611.    c3 = (number)(cos(o->X) * TRIG_ADJ); c4 = (number)(sin(o->X) * TRIG_ADJ);
  2612.    c5 = (number)(cos(o->Z) * TRIG_ADJ); c6 = (number)(sin(o->Z) * TRIG_ADJ);
  2613.    c7 = (number)g->winH;              c8 = (number)(2.0 * g->winH);
  2614.    c9 = (number)g->winV;             c10 = (number)(2.0 * g->winV);
  2615.   c11 = (number)o->tX;               c12 = (number)(o->tY - o->viewpointY);    
  2616.   c13 = (number)o->tZ;                       c14 = (number)o->BViewpointX;
  2617.   c15 = (number)(o->BViewpointX * o->focus); c16 = (number)-o->oX;
  2618.   c17 = (number)-o->oY;                      c18 = (number)-o->oZ;
  2619.  
  2620.    objClip = 0;
  2621.    o->Hmin2 = o->Hmin1; o->Vmin2 = o->Vmin1; 
  2622.    o->Hmax2 = o->Hmax1; o->Vmax2 = o->Vmax1; 
  2623.    o->Hmin1 = o->Hmin; o->Vmin1 = o->Vmin; 
  2624.    o->Hmax1 = o->Hmax; o->Vmax1 = o->Vmax; 
  2625.    o->Hmin = c8; o->Vmin = c10; 
  2626.    o->Hmax =  0; o->Vmax =  0; 
  2627.  
  2628. /* What happens to the bounding box? */
  2629.  
  2630.    while(p0 != p1){
  2631.       STEREOROTATE;
  2632.  
  2633.       if(STEREOCLIPFLAGS)
  2634.          objClip = 1;
  2635.  
  2636.       if((int)r7 < o->Vmin){ o->Vmin = (int)r7; }
  2637.       if((int)r7 > o->Vmax){ o->Vmax = (int)r7; }
  2638.  
  2639.       if((int)r8 < o->Hmin){ o->Hmin = (int)r8; }
  2640.       if((int)r8 > o->Hmax){ o->Hmax = (int)r8; }
  2641.  
  2642.       if((g->stereo) && (g->stereoBlue)){
  2643.          if((int)r9 < o->Hmin){ o->Hmin = (int)r9; }
  2644.          if((int)r9 > o->Hmax){ o->Hmax = (int)r9; }
  2645.          }
  2646.  
  2647.       p0++;
  2648.       }
  2649.  
  2650. /* Update screen clearing, pix copying variables */
  2651.  
  2652.    if((g->modeChanged) || (objClip)){
  2653.       o->Hmin = o->Hmin1 = o->Hmin2 = 0;
  2654.       o->Vmin = o->Vmin1 = o->Vmin2 = 0;
  2655.       o->Hmax = o->Hmax1 = o->Hmax2 = g->winX;
  2656.       o->Vmax = o->Vmax1 = o->Vmax2 = g->winY;
  2657.    }else{
  2658.       if(o->Hmin < 0){o->Hmin = 0;}
  2659.       if(o->Vmin < 0){o->Vmin = 0;}
  2660.       if(o->Hmax > c8){o->Hmax = c8;}
  2661.       if(o->Vmax > c10){o->Vmax = c10;}
  2662.  
  2663.       if(o->Hmin1 < o->Hmin2){o->Hmin2 = o->Hmin1;}
  2664.       if(o->Vmin1 < o->Vmin2){o->Vmin2 = o->Vmin1;}
  2665.       if(o->Hmax1 > o->Hmax2){o->Hmax2 = o->Hmax1;}
  2666.       if(o->Vmax1 > o->Vmax2){o->Vmax2 = o->Vmax1;}
  2667.       }
  2668.  
  2669.    o->fillX = o->Hmin2; o->fillY = o->Vmin2;
  2670.    o->fillWidth  = o->Hmax2 - o->Hmin2 + 1;
  2671.    o->fillHeight = o->Vmax2 - o->Vmin2 + 1;
  2672.  
  2673.    if(o->Hmin < o->Hmin2){o->Hmin2 = o->Hmin;}
  2674.    if(o->Vmin < o->Vmin2){o->Vmin2 = o->Vmin;}
  2675.    if(o->Hmax > o->Hmax2){o->Hmax2 = o->Hmax;}
  2676.    if(o->Vmax > o->Vmax2){o->Vmax2 = o->Vmax;}
  2677.  
  2678.    o->copyX = o->Hmin2; o->copyY = o->Vmin2;
  2679.    o->copyWidth  = o->Hmax2 - o->Hmin2 + 1;
  2680.    o->copyHeight = o->Vmax2 - o->Vmin2 + 1;
  2681.  
  2682.    o->objClip = objClip;
  2683.    p0 = o->points;
  2684.    p1 = &(o->points[o->numPoints]);
  2685.  
  2686.    if(objClip){
  2687.  
  2688. /* The object is not totally visible, do clipping */
  2689.  
  2690.       if((g->stereo) && (g->stereoBlue)){
  2691.          if(g->renderMode == WIREFRAME){
  2692.             while(p0 != p1){
  2693.                STEREOROTATE;
  2694.                p0->Y  = (float)r7;   p0->R.y = (short)r7;
  2695.                p0->RX = (float)r8;   p0->R.x = (short)r8;
  2696.                p0->BX = (float)r9;   p0->sBX = (short)r9;
  2697.                p0->ClipFlags = STEREOCLIPFLAGS;
  2698.                p0++;
  2699.                }
  2700.          }else{
  2701.  
  2702.             while(p0 != p1){
  2703.                STEREOROTATE;
  2704.                p0->dist = (float)r5;
  2705.                p0->Y  = (float)r7;   p0->R.y = (short)r7;
  2706.                p0->RX = (float)r8;   p0->R.x = (short)r8;
  2707.                p0->BX = (float)r9;   p0->sBX = (short)r9;
  2708.                p0->ClipFlags = STEREOCLIPFLAGS;
  2709.                p0++;
  2710.                }
  2711.             }
  2712.       }else{
  2713.          if(g->renderMode == WIREFRAME){
  2714.             while(p0 != p1){
  2715.                REDROTATE;
  2716.                p0->Y  = (float)r7;   p0->R.y = (short)r7;
  2717.                p0->RX = (float)r8;   p0->R.x = (short)r8;
  2718.                p0->ClipFlags = REDCLIPFLAGS;
  2719.                p0++;
  2720.                }
  2721.          }else{
  2722.  
  2723.             while(p0 != p1){
  2724.                REDROTATE;
  2725.                p0->dist = (float)r5;
  2726.                p0->Y  = (float)r7;   p0->R.y = (short)r7;
  2727.                p0->RX = (float)r8;   p0->R.x = (short)r8;
  2728.                p0->ClipFlags = REDCLIPFLAGS;
  2729.                p0++;
  2730.                }
  2731.             }
  2732.          }
  2733.    }else{
  2734.  
  2735. /* The object is totally visible, skip clipping */
  2736.  
  2737.       if((g->stereo) && (g->stereoBlue)){
  2738.          if(g->renderMode == WIREFRAME){
  2739.             while(p0 != p1){
  2740.                STEREOROTATE;
  2741.                p0->R.y = (short)r7;
  2742.                p0->R.x = (short)r8;
  2743.                p0->sBX = (short)r9;
  2744.                p0++;
  2745.                }
  2746.          }else{
  2747.  
  2748.             while(p0 != p1){
  2749.                STEREOROTATE;
  2750.                p0->dist = (float)r5;
  2751.                p0->R.y = (short)r7;
  2752.  
  2753.                RX = r8;
  2754.                p0->R.x = (float)RX;
  2755.  
  2756.                BX = r9;
  2757.                p0->sBX = (float)BX;
  2758.  
  2759.                p0++;
  2760.                }
  2761.             }
  2762.       }else{
  2763.          if(g->renderMode == WIREFRAME){
  2764.             while(p0 != p1){
  2765.                REDROTATE;
  2766.                p0->R.y = (short)r7;
  2767.                p0->R.x = (short)r8;
  2768.                p0++;
  2769.                }
  2770.          }else{
  2771.  
  2772.             while(p0 != p1){
  2773.                REDROTATE;
  2774.                p0->dist = (float)r5;
  2775.  
  2776.                p0->R.y = (short)r7;
  2777.                RX = (short)r8;
  2778.                p0->R.x = (float)RX;
  2779.             
  2780.                p0++;
  2781.                }
  2782.             }
  2783.          }
  2784.       }
  2785. }
  2786.  
  2787.  
  2788.  
  2789.  
  2790. static void DrawSegments(display, win, gc, segs, numSegs, g)
  2791. Display *display;
  2792. Window win;
  2793. GC gc;
  2794. XSegment segs[];
  2795. int numSegs;
  2796. Ginfo *g;
  2797. /******************************************************************************
  2798.    Thanks to Mark Cook for the suggestion to pay attention the the 
  2799.    maximum request size of the X server!
  2800. ******************************************************************************/
  2801. {
  2802. int requestSize, evenAmount, remainder, index;
  2803.     
  2804.    requestSize = g->requestSize;
  2805.    evenAmount = (numSegs / requestSize) * requestSize;
  2806.    remainder  = numSegs - evenAmount;
  2807.  
  2808.    index = 0; 
  2809.   
  2810.    while(index < evenAmount){
  2811.       XDrawSegments(display, win, gc, &segs[index], requestSize);
  2812.       index += requestSize;
  2813.       }
  2814.  
  2815.    if(remainder)
  2816.       XDrawSegments(display, win, gc, &segs[index], remainder);
  2817. }
  2818.  
  2819.  
  2820.  
  2821. static void DrawLines(o, g, mode)
  2822. Oinfo *o;
  2823. Ginfo *g;
  2824. int mode;
  2825. /******************************************************************************
  2826.    Draw lines for the three display modes.
  2827. ******************************************************************************/ 
  2828. {
  2829. Drawable dest;
  2830. long lastColor;
  2831. int lastChange, index;
  2832.  
  2833.    dest = g->dest;
  2834.  
  2835.    switch(mode){
  2836.  
  2837.       case BW:
  2838.          XSetForeground(g->dpy, g->gc, g->black);
  2839.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  2840.          o->fillWidth, o->fillHeight);
  2841.          XSetForeground(g->dpy, g->gc, g->white);
  2842.          DrawSegments  (g->dpy, dest,  g->gc, g->redSegments, g->numberRed, g);
  2843.          break;
  2844.  
  2845.       case STEREO:
  2846.  
  2847.          XSetForeground(g->dpy, g->gc,  (long)g->Black);
  2848.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  2849.          o->fillWidth, o->fillHeight);
  2850.  
  2851.          XSetForeground(g->dpy, g->gc, (long)g->Red);
  2852.          DrawSegments(g->dpy, dest, g->gc, g->redSegments, g->numberRed, g);
  2853.  
  2854.          if(g->stereoBlue){
  2855.  
  2856.             XSetFunction  (g->dpy, g->gc,  GXor);
  2857.  
  2858.             XSetForeground(g->dpy, g->gc,  (long)g->Blue);
  2859.             DrawSegments(g->dpy, dest, g->gc, g->blueSegments, g->numberBlue,
  2860.             g);
  2861.  
  2862.             XSetFunction (g->dpy, g->gc, GXcopy);
  2863.             }
  2864.  
  2865.          break;
  2866.  
  2867.       case COLOR:
  2868.  
  2869.          XSetForeground(g->dpy, g->gc, g->Black);
  2870.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  2871.          o->fillWidth, o->fillHeight);
  2872.  
  2873.          lastChange = 4;
  2874.          lastColor = g->redColors[lastChange];
  2875.  
  2876.          for(index = 5; index < g->numberRed; index++){
  2877.             if(g->redColors[index] != lastColor){
  2878.                XSetForeground(g->dpy, g->gc, lastColor);
  2879.                DrawSegments(g->dpy, dest,  g->gc, &(g->redSegments[lastChange]),
  2880.                index - lastChange, g);
  2881.                lastChange = index;
  2882.                lastColor = g->redColors[lastChange];
  2883.                }
  2884.             }
  2885.  
  2886.          XSetForeground(g->dpy, g->gc, lastColor);
  2887.          DrawSegments(g->dpy, dest,  g->gc, &(g->redSegments[lastChange]),
  2888.          g->numberRed - lastChange, g);
  2889.  
  2890.          break;
  2891.  
  2892.       default:
  2893.          break;
  2894.       }
  2895. }
  2896.  
  2897.  
  2898.  
  2899. static void DrawHiddenLines(o, g, mode)
  2900. Oinfo *o;
  2901. Ginfo *g;
  2902. int mode;
  2903. /******************************************************************************
  2904.    Draw polygon outlines using painter algorithm for the three display modes.
  2905. ******************************************************************************/ 
  2906. {
  2907. register int index, npoints, numPolys; 
  2908. register polygon *poly, **list;
  2909. register point  **pointPtr, **lastPointPtr;
  2910. Drawable dest;
  2911.  
  2912. XPoint points[512], *XPointPtr;
  2913.  
  2914.    dest = g->dest;
  2915.    numPolys = o->numPolys; 
  2916.    list     = o->list;
  2917.    
  2918.    sort(list, numPolys);
  2919.  
  2920.    switch(mode){
  2921.  
  2922.       case BW:
  2923.  
  2924.          XSetForeground(g->dpy, g->gc, g->black);
  2925.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  2926.          o->fillWidth, o->fillHeight);
  2927.  
  2928.          for(index = 0; index < numPolys; index++){
  2929.  
  2930.             poly = list[index];
  2931.             XPointPtr = points;
  2932.             npoints      =   poly->numPoints;
  2933.             pointPtr     =   poly->points; 
  2934.             lastPointPtr = &(poly->points[npoints]);
  2935.  
  2936.             while(pointPtr < lastPointPtr){
  2937.                *XPointPtr = (*pointPtr)->R;
  2938.                XPointPtr++;
  2939.                pointPtr++;
  2940.                }
  2941.  
  2942.             XSetForeground(g->dpy, g->gc, g->black);
  2943.             XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  2944.             CoordModeOrigin); 
  2945.             points[npoints] = points[0];
  2946.             XSetForeground(g->dpy, g->gc, g->white);
  2947.             XDrawLines(g->dpy, dest, g->gc, points, npoints + 1,
  2948.             CoordModeOrigin); 
  2949.             }
  2950.  
  2951.          XSetFillStyle(g->dpy, g->gc, FillSolid);
  2952.          break;
  2953.  
  2954.       case STEREO:
  2955.  
  2956.          XSetForeground(g->dpy, g->gc, g->stereoBlack);
  2957.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  2958.          o->fillWidth, o->fillHeight);
  2959.  
  2960.          XSetPlaneMask(g->dpy, g->gc, g->redMask);
  2961.  
  2962.          for(index = 0; index < numPolys; index++){
  2963.             poly = list[index];
  2964.             XPointPtr = points;
  2965.             npoints      =   poly->numPoints;
  2966.             pointPtr     =   poly->points; 
  2967.             lastPointPtr = &(poly->points[npoints]);
  2968.  
  2969.             while(pointPtr < lastPointPtr){
  2970.                *XPointPtr = (*pointPtr)->R;
  2971.                XPointPtr++;
  2972.                pointPtr++;
  2973.                }
  2974.  
  2975.             XSetForeground(g->dpy, g->gc, g->stereoBlack);
  2976.             XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  2977.             CoordModeOrigin); 
  2978.             points[npoints] = points[0];
  2979.             XSetForeground(g->dpy, g->gc, poly->color->stereoColor);
  2980.             XDrawLines(g->dpy, dest, g->gc, points, npoints + 1,
  2981.             CoordModeOrigin); 
  2982.             }
  2983.  
  2984.          if(g->stereoBlue){
  2985.             XSetPlaneMask(g->dpy, g->gc, g->blueMask);
  2986.  
  2987.             for(index = 0; index < numPolys; index++){
  2988.                poly = list[index];
  2989.                XPointPtr = points;
  2990.                npoints      =   poly->numPoints;
  2991.                pointPtr     =   poly->points; 
  2992.                lastPointPtr = &(poly->points[npoints]);
  2993.  
  2994.                while(pointPtr < lastPointPtr){
  2995.                   XPointPtr->x = (*pointPtr)->sBX;
  2996.                   XPointPtr->y = (*pointPtr)->R.y;
  2997.                   XPointPtr++;
  2998.                   pointPtr++;
  2999.                   }
  3000.  
  3001.                XSetForeground(g->dpy, g->gc, g->stereoBlack);
  3002.                XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  3003.                CoordModeOrigin); 
  3004.                points[npoints] = points[0];
  3005.                XSetForeground(g->dpy, g->gc, poly->color->stereoColor);
  3006.                XDrawLines(g->dpy, dest, g->gc, points, npoints + 1,
  3007.                CoordModeOrigin); 
  3008.                }
  3009.             }
  3010.             XSetPlaneMask(g->dpy, g->gc, AllPlanes);
  3011.          break;
  3012.  
  3013.       case COLOR:
  3014.  
  3015.          XSetForeground(g->dpy, g->gc, g->Black);
  3016.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  3017.          o->fillWidth, o->fillHeight);
  3018.  
  3019.          for(index = 0; index < numPolys; index++){
  3020.             poly = list[index];
  3021.             XPointPtr = points;
  3022.             npoints      =   poly->numPoints;
  3023.             pointPtr     =   poly->points; 
  3024.             lastPointPtr = &(poly->points[npoints]);
  3025.  
  3026.             while(pointPtr < lastPointPtr){
  3027.                *XPointPtr = (*pointPtr)->R;
  3028.                XPointPtr++;
  3029.                pointPtr++;
  3030.                }
  3031.  
  3032.             XSetForeground(g->dpy, g->gc, g->Black);
  3033.             XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  3034.             CoordModeOrigin); 
  3035.             points[npoints] = points[0];
  3036.             XSetForeground(g->dpy, g->gc, poly->color->value);
  3037.             XDrawLines(g->dpy, dest, g->gc, points, npoints + 1,
  3038.             CoordModeOrigin); 
  3039.             }
  3040.  
  3041.          break;
  3042.  
  3043.       default:
  3044.          break;
  3045.       }
  3046. }
  3047.  
  3048.  
  3049.  
  3050. static void DrawPolys(o, g, mode)
  3051. Oinfo *o;
  3052. Ginfo *g;
  3053. int mode;
  3054. /******************************************************************************
  3055.    Draw polygons using painter algorithm for the three display modes.
  3056. ******************************************************************************/ 
  3057. {
  3058. register int index, npoints, numPolys; 
  3059. register polygon *poly, **list;
  3060. register point  **pointPtr, **lastPointPtr;
  3061. Drawable dest;
  3062. XPoint points[512], *XPointPtr;
  3063. long lastColor;
  3064.  
  3065.    dest = g->dest;
  3066.    numPolys = o->numPolys; 
  3067.    list     = o->list;
  3068.    
  3069.    sort(list, numPolys);
  3070.  
  3071.    switch(mode){
  3072.  
  3073.       case BW:
  3074.  
  3075.          XSetForeground(g->dpy, g->gc, g->black);
  3076.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  3077.          o->fillWidth, o->fillHeight);
  3078.          XSetForeground(g->dpy, g->gc, g->white);
  3079.          XSetBackground(g->dpy, g->gc, g->black);
  3080.          XSetFillStyle(g->dpy, g->gc, FillOpaqueStippled);
  3081.  
  3082.          for(index = 0; index < numPolys; index++){
  3083.  
  3084.             poly = list[index];
  3085.             XPointPtr = points;
  3086.             XSetStipple(g->dpy, g->gc, g->stipple[poly->color->stipple]);
  3087.             npoints      =   poly->numPoints;
  3088.             pointPtr     =   poly->points; 
  3089.             lastPointPtr = &(poly->points[npoints]);
  3090.  
  3091.             while(pointPtr < lastPointPtr){
  3092.                *XPointPtr = (*pointPtr)->R;
  3093.                XPointPtr++;
  3094.                pointPtr++;
  3095.                }
  3096.  
  3097.             XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  3098.             CoordModeOrigin); 
  3099.             }
  3100.  
  3101.          XSetFillStyle(g->dpy, g->gc, FillSolid);
  3102.          break;
  3103.  
  3104.       case STEREO:
  3105.  
  3106.          XSetForeground(g->dpy, g->gc, g->stereoBlack);
  3107.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  3108.          o->fillWidth, o->fillHeight);
  3109.          lastColor = g->stereoBlack;
  3110.  
  3111.          XSetPlaneMask(g->dpy, g->gc, g->redMask);
  3112.  
  3113.          for(index = 0; index < numPolys; index++){
  3114.             poly = list[index];
  3115.             XPointPtr = points;
  3116.             if(poly->color->stereoColor != lastColor){
  3117.                XSetForeground(g->dpy, g->gc, poly->color->stereoColor);
  3118.                lastColor = poly->color->stereoColor;
  3119.                }
  3120.             npoints      =   poly->numPoints;
  3121.             pointPtr     =   poly->points; 
  3122.             lastPointPtr = &(poly->points[npoints]);
  3123.  
  3124.             while(pointPtr < lastPointPtr){
  3125.                *XPointPtr = (*pointPtr)->R;
  3126.                XPointPtr++;
  3127.                pointPtr++;
  3128.                }
  3129.  
  3130.             XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  3131.             CoordModeOrigin); 
  3132.             }
  3133.  
  3134.          if(g->stereoBlue){
  3135.             XSetPlaneMask(g->dpy, g->gc, g->blueMask);
  3136.  
  3137.             for(index = 0; index < numPolys; index++){
  3138.                poly = list[index];
  3139.                XPointPtr = points;
  3140.                if(poly->color->stereoColor != lastColor){
  3141.                   XSetForeground(g->dpy, g->gc, poly->color->stereoColor);
  3142.                   lastColor = poly->color->stereoColor;
  3143.                   }
  3144.                npoints      =   poly->numPoints;
  3145.                pointPtr     =   poly->points; 
  3146.                lastPointPtr = &(poly->points[npoints]);
  3147.  
  3148.                while(pointPtr < lastPointPtr){
  3149.                   XPointPtr->x = (*pointPtr)->sBX;
  3150.                   XPointPtr->y = (*pointPtr)->R.y;
  3151.                   XPointPtr++;
  3152.                   pointPtr++;
  3153.                   }
  3154.  
  3155.                XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  3156.                CoordModeOrigin); 
  3157.                }
  3158.             }
  3159.             XSetPlaneMask(g->dpy, g->gc, AllPlanes);
  3160.          break;
  3161.  
  3162.       case COLOR:
  3163.  
  3164.          XSetForeground(g->dpy, g->gc, g->Black);
  3165.          XFillRectangle(g->dpy, dest,  g->gc, o->fillX, o->fillY,
  3166.          o->fillWidth, o->fillHeight);
  3167.          lastColor = g->Black;
  3168.  
  3169.          for(index = 0; index < numPolys; index++){
  3170.             poly = list[index];
  3171.             XPointPtr = points;
  3172.             if(poly->color->value != lastColor){
  3173.                XSetForeground(g->dpy, g->gc, poly->color->value);
  3174.                lastColor = poly->color->value;
  3175.                }
  3176.             npoints      =   poly->numPoints;
  3177.             pointPtr     =   poly->points; 
  3178.             lastPointPtr = &(poly->points[npoints]);
  3179.  
  3180.             while(pointPtr < lastPointPtr){
  3181.                *XPointPtr = (*pointPtr)->R;
  3182.                XPointPtr++;
  3183.                pointPtr++;
  3184.                }
  3185.  
  3186.             XFillPolygon(g->dpy, dest, g->gc, points, npoints, Convex,
  3187.             CoordModeOrigin); 
  3188.             }
  3189.  
  3190.          break;
  3191.  
  3192.       default:
  3193.          break;
  3194.       }
  3195. }
  3196.  
  3197.  
  3198.  
  3199. static void BeginImage(o, g)
  3200. Oinfo *o;
  3201. Ginfo *g;
  3202. /******************************************************************************
  3203.    Prepare to draw some x3d objects.
  3204. ******************************************************************************/ 
  3205. {
  3206.  
  3207. /* Try to get rid of a few of the mode change glitches (several exist yet) */
  3208.  
  3209.    if(g->modeChanged){
  3210.       XSetPlaneMask(g->dpy, g->gc, AllPlanes);
  3211.       if((g->mono) || (g->depth == ONE)){
  3212.          XSetForeground(g->dpy, g->gc, g->black);
  3213.       }else{
  3214.          if(g->stereo){
  3215.             XSetForeground(g->dpy, g->gc,  (long)g->Black);
  3216.          }else{
  3217.             XSetForeground(g->dpy, g->gc, g->Black);
  3218.             }
  3219.          }
  3220.  
  3221.       XFillRectangle(g->dpy, g->pix,  g->gc, 0, 0, g->winX, g->winY);
  3222.       XFillRectangle(g->dpy, g->win,  g->gc, 0, 0, g->winX, g->winY);
  3223.       }
  3224.  
  3225.    if(g->buffer){
  3226.       if((g->mono) || (g->depth != EIGHT)){
  3227.          g->dest = g->pix;
  3228.       }else{
  3229.          if((g->numColors > BUFFER_CMAP) || (((g->renderMode == SOLID) ||
  3230.          (g->renderMode == HIDDENLINE)) && (g->stereo))){
  3231.             g->dest = g->pix;
  3232.          }else{
  3233.             g->dest = g->win;
  3234.  
  3235.             if(g->ColorSelect){
  3236.                XSetPlaneMask(g->dpy, g->gc, BUFFER1);
  3237.             }else{
  3238.                XSetPlaneMask(g->dpy, g->gc, BUFFER0);
  3239.                }
  3240.             }
  3241.          }
  3242.    }else{
  3243.       g->dest = g->win;
  3244.       }
  3245. }
  3246.  
  3247.  
  3248.  
  3249. static void DrawObject(o, g)
  3250. Oinfo *o;
  3251. Ginfo *g;
  3252. /******************************************************************************
  3253.    Draw an x3d objext to the screen.  Be sure to draw the objects back to
  3254.    front when calling this function.
  3255. ******************************************************************************/ 
  3256. {
  3257.  
  3258. /* rotate the object */
  3259.  
  3260.    rotate(o, g);
  3261.  
  3262. /* Clip against the screen edges */
  3263.  
  3264.    clip(o, g);
  3265.  
  3266. /* Draw in the proper render mode */
  3267.  
  3268.    switch(g->renderMode){
  3269.  
  3270.       case WIREFRAME:
  3271.          if((g->mono) || (g->depth == ONE)){
  3272.             DrawLines(o, g, BW);
  3273.          }else{
  3274.             if(g->stereo){
  3275.                DrawLines(o, g, STEREO);
  3276.             }else{
  3277.                DrawLines(o, g, COLOR);
  3278.                }
  3279.             }
  3280.          break; 
  3281.  
  3282.       case HIDDENLINE:
  3283.          if((g->mono) || (g->depth == ONE)){
  3284.             DrawHiddenLines(o, g, BW);
  3285.          }else{
  3286.             if(g->stereo){
  3287.                DrawHiddenLines(o, g, STEREO);
  3288.             }else{
  3289.                DrawHiddenLines(o, g, COLOR);
  3290.                }
  3291.             }
  3292.          break;
  3293.  
  3294.       case SOLID:
  3295.          if((g->mono) || (g->depth == ONE)){
  3296.             DrawPolys(o, g, BW);
  3297.          }else{
  3298.             if(g->stereo){
  3299.                DrawPolys(o, g, STEREO);
  3300.             }else{
  3301.                DrawPolys(o, g, COLOR);
  3302.                }
  3303.             }
  3304.          break;
  3305.  
  3306.       default :
  3307.          fprintf(stderr, "Unknown Render Mode!\n");
  3308.          exit(1);
  3309.          break; 
  3310.       }
  3311.  
  3312. /* Reset the number of lines (We always keep the purple rectangle) */
  3313.  
  3314.    g->numberRed  = 4;
  3315.    g->numberBlue = 4;
  3316.    g->numRedColors = 4;
  3317.    g->modeChanged = 0;
  3318. }
  3319.  
  3320.  
  3321.  
  3322. static void EndImage(o, g)
  3323. Oinfo *o;
  3324. Ginfo *g;
  3325. /******************************************************************************
  3326.    Finish drawing x3d objects.
  3327. ******************************************************************************/ 
  3328. {
  3329.  
  3330. /* Colormap double buffer? */
  3331.  
  3332.    if((g->depth == EIGHT) && (!(g->mono)) && (g->numColors <= BUFFER_CMAP) &&
  3333.    (!((g->stereo) && (g->renderMode == HIDDENLINE))) &&
  3334.    (!((g->stereo) && (g->renderMode == SOLID)))){
  3335.       g->ColorSelect = !g->ColorSelect;
  3336.  
  3337.       if((g->stereo) && (g->renderMode == WIREFRAME) && (!(g->modeChanged))){
  3338.          XStoreColors(g->dpy, g->colormap, g->wireframeColors[g->ColorSelect],
  3339.          12);
  3340.       }else{
  3341.          XStoreColors(g->dpy, g->colormap, g->cmapColors[g->ColorSelect], 256);
  3342.          }
  3343.    }else{
  3344.  
  3345. /* Stereo solid, wireframe? */
  3346.  
  3347.       if(g->depth == EIGHT){
  3348.          if(((g->renderMode == SOLID) || (g->renderMode == HIDDENLINE))
  3349.          && (g->stereo)){
  3350.             XStoreColors(g->dpy, g->colormap, g->cmapColors[2], 256);
  3351.          }else{
  3352.             XStoreColors(g->dpy, g->colormap, g->cmapColors[g->ColorSelect],
  3353.             256);
  3354.             }
  3355.          }
  3356.  
  3357. /* generic */
  3358.  
  3359.       if(g->buffer){
  3360.          XCopyArea(g->dpy, g->pix, g->win, g->gc, o->copyX, o->copyY,
  3361.          o->copyWidth, o->copyHeight, o->copyX, o->copyY);
  3362.          }
  3363.       }
  3364.  
  3365.    XFlush(g->dpy);
  3366. }
  3367.  
  3368. #ifndef DEBUG 
  3369.  
  3370. void main(argc, argv)
  3371. int argc;
  3372. char *argv[];
  3373. /******************************************************************************
  3374.    Parse the command line, read the object from a file, then for forever  
  3375.    drawObjects, update position ...
  3376. ******************************************************************************/
  3377. {
  3378. Ginfo *g;
  3379. Oinfo *o;
  3380. char  *filename;
  3381.  
  3382.    if((o = (Oinfo *)calloc(1, sizeof(Oinfo))) == NULL){
  3383. (void)fprintf(stderr, "Unable to allocate memory for Object\n"); exit(1);} 
  3384.    
  3385.    if((g = (Ginfo *)calloc(1, sizeof(Ginfo))) == NULL){
  3386. (void)fprintf(stderr, "Unable to allocate memory for Ginfo\n"); exit(1);}
  3387.  
  3388. /* Check the usage */
  3389.  
  3390.    ParseCommandLine(argc, argv, &filename, g);
  3391.  
  3392. /* Read in the points and segments from a file */
  3393.  
  3394.    readObjectFile(filename, &(g->colors), &(g->numColors), &(o->points),
  3395.    &(o->numPoints), &(o->segs), &(o->numSegs), &(o->polys),
  3396.    &(o->numPolys), &(o->list), &(o->bounds));
  3397.  
  3398. /* Define viewing parameters */
  3399.   
  3400.    o->BViewpointX = 100.0;
  3401.    o->tX  = 640.0; o->tY  = 6000.0; o->tZ  = 490.0;
  3402.    o->viewpointY  = -650.0;
  3403.    o->X = o->Y = o->Z = 0.0;
  3404.    o->dX = o->dY = o->dZ = 0.0;
  3405.    o->oX = o->oY = o->oZ = 0.0;
  3406.    o->focus = 0.2;
  3407.  
  3408. /* Initialize the display */
  3409.  
  3410.    InitDisplay(o, g);
  3411.  
  3412. /* Forever do... */
  3413.  
  3414.    while (1){
  3415.  
  3416. /* Draw object according to current position and rendering information */
  3417.  
  3418.       BeginImage(o, g);
  3419.       DrawObject(o, g);
  3420.       EndImage(o, g);
  3421.  
  3422. /* Get new position information */
  3423.  
  3424.       UpdatePosition(o, g);
  3425.    }
  3426. }
  3427.  
  3428.  
  3429. #else
  3430.  
  3431. void main(argc, argv)
  3432. int argc;
  3433. char *argv[];
  3434. /******************************************************************************
  3435.    Parse the command line, read the object from a file, then for forever  
  3436.    drawObjects, update position ...
  3437. ******************************************************************************/
  3438. {
  3439.  
  3440. char line[MAXLINE];
  3441.  
  3442. static char results[][MAXLINE] = {
  3443.    "Below",
  3444.    "Intersect",
  3445.    "Above",
  3446.    "Same",
  3447.    "Ends Intersect"
  3448. };
  3449.  
  3450. FILE *fd;
  3451. int lineNo;
  3452.  
  3453. int v1, v2, v3, v4;
  3454.  
  3455. point   mp, mq, np, nq, *pt;
  3456. segment m, n, *seg;
  3457. int x, y;
  3458.  
  3459.    if((fd = fopen(argv[1], "r")) == NULL){
  3460.       fprintf(stderr, "Unable to open %s\n", argv[1]);
  3461.       exit(1);
  3462.       }
  3463.  
  3464.    lineNo = 0;
  3465.  
  3466.    m.P = ∓
  3467.    m.Q = &mq;
  3468.    n.P = &np;
  3469.    n.Q = &nq;
  3470.  
  3471.    if(readLine(fd, line, &lineNo)){
  3472.       (void)fprintf(stderr, "Error reading line.\n");
  3473.       exit(1);
  3474.       }
  3475.  
  3476.    while(feof(fd) == 0){
  3477.  
  3478.       sscanf(line, "%d %d %d %d", &v1, &v2, &v3, &v4);
  3479.  
  3480.       mp.R.x = v1;
  3481.       mp.R.y = v2;
  3482.       mq.R.x = v3;
  3483.       mq.R.y = v4;
  3484.  
  3485.       if(readLine(fd, line, &lineNo)){
  3486.          (void)fprintf(stderr, "ERROR reading line.\n");
  3487.          exit(1);
  3488.          }
  3489.  
  3490.       sscanf(line, "%d %d %d %d", &v1, &v2, &v3, &v4);
  3491.  
  3492.       np.R.x = v1;
  3493.       np.R.y = v2;
  3494.       nq.R.x = v3;
  3495.       nq.R.y = v4;
  3496.  
  3497.       printf("M  %d %d %d %d\n", mp.R.x, mp.R.y, mq.R.x, mq.R.y); 
  3498.       printf("N  %d %d %d %d\n", np.R.x, np.R.y, nq.R.x, nq.R.y); 
  3499.  
  3500.       x = 0; y = 0;
  3501.  
  3502.       seg = &m;
  3503.  
  3504.       pt = seg->P;
  3505.       if(pt->R.y > seg->Q->R.y){
  3506.          seg->P = seg->Q;
  3507.          seg->Q = pt; 
  3508.          }
  3509.  
  3510.       seg = &n;
  3511.  
  3512.       pt = seg->P;
  3513.       if(pt->R.y > seg->Q->R.y){
  3514.          seg->P = seg->Q;
  3515.          seg->Q = pt; 
  3516.          }
  3517.  
  3518.       printf(" result %s ", results[1 +  compareSegments(&m, &n, &x, &y, 0)]);
  3519.       printf(" %d %d\n", x, y);
  3520.  
  3521.       readLine(fd, line, &lineNo);
  3522.       }
  3523.  
  3524.    fclose(fd);
  3525. }
  3526.  
  3527. #endif
  3528.