home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / IRIT / POLY3DS.ZIP / VIEWOBJ.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-05  |  24.4 KB  |  679 lines

  1. /*****************************************************************************
  2. * Module to handle viewing of objects in the ViewWindow.             *
  3. *                                         *
  4. * Written by:  Gershon Elber            IBM PC Ver 1.0,    Jan. 1989    *
  5. *****************************************************************************/
  6.  
  7. #include <stdio.h>
  8. #include <conio.h>
  9. #include <graphics.h>
  10. #include <math.h>
  11. #include <setjmp.h>
  12. #include <string.h>
  13. #include "Program.h"
  14. #include "PostScrp.h"
  15. #include "GenMat.h"
  16. #include "Parser.h"
  17. #include "ViewObjL.h"
  18. #include "ViewObjG.h"
  19. #include "GraphGnG.h"
  20. #include "MouseDrv.h"
  21. #include "Gif_Lib.h"
  22.  
  23. static FILE *PSFile = NULL;           /* Used to save PostScript text file. */
  24. static jmp_buf LongJumpBuffer;              /* Used in control C trapping. */
  25.  
  26. /* Interactive mode menu set up structure is define below (See ViewObjL.H): */
  27. InteractWindowStruct InteractMenu = {
  28.     { { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.40, RED,   "Rotate" },
  29.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.72, GREEN, "Translate" },
  30.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.04, CYAN,  "Scale" },
  31.     },
  32.     { { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.1,  BROWN,  TRUE,  "Screen Coords." },
  33.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.22, BLUE,   TRUE,  "Perspectiv" },
  34.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.3,  BLUE,   FALSE, "Z" },
  35.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.46, RED,    FALSE, "X" }, /* Rot */
  36.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.54, RED,    FALSE, "Y" },
  37.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.62, RED,    FALSE, "Z" },
  38.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.78, GREEN,  FALSE, "X" }, /* Trans */
  39.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.86, GREEN,  FALSE, "Y" },
  40.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.94, GREEN,  FALSE, "Z" },
  41.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.1,  CYAN,   FALSE, "" },  /* Scale */
  42.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.26, MAGENTA,TRUE,  "Depth cue" },
  43.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.42, YELLOW, TRUE,  "Save GIF" },
  44.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.5,  YELLOW, TRUE,  "Save PS" },
  45.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.62, YELLOW, TRUE,  "Save Matrix" },
  46.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.7,  YELLOW, TRUE,  "Reset Matrix" },
  47.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.85, WHITE,  TRUE,  "Quit" },
  48.     }
  49. };
  50.  
  51. /* We support depth cues iff DepthCueFlag is TRUE: */
  52. #define MY_DOTTED_LINE  (GlblDepthCue ? DOTTED_LINE : SOLID_LINE)
  53.  
  54. /*****************************************************************************
  55. *  Routine to interactively display geometric object(s) PObjList on the View *
  56. * window enable rotating/translating/scaling it using the Input Device.      *
  57. *****************************************************************************/
  58. void InteractGeomObject(FileDescription **FD, int NumOfObjects,    char **Objects)
  59. {
  60.     switch (GlblTransformMode) {
  61.     case TRANS_SCREEN:
  62.         InteractMenu.SubWindows[0].Str = "Screen Coords.";
  63.         break;
  64.     case TRANS_OBJECT:
  65.         InteractMenu.SubWindows[0].Str = "Object Coords.";
  66.         break;
  67.     }
  68.  
  69.     switch (GlblViewMode) {
  70.     case VIEW_PERSPECTIVE:
  71.         InteractMenu.SubWindows[1].Str = "Perspective";
  72.         break;
  73.     case VIEW_ORTHOGRAPHIC:
  74.         InteractMenu.SubWindows[1].Str = "Orthographic";
  75.         break;
  76.     }
  77.  
  78.     if (GlblDepthCue)
  79.      InteractMenu.SubWindows[10].Str = "Depth Cue";
  80.     else InteractMenu.SubWindows[10].Str = "No Depth Cue";
  81.  
  82.     InteractDrawMenu();                /* Draw the transformation menu. */
  83.     /* Get data from input device, interpret it, and display interactively:  */
  84.     InteractHandleInput(FD, NumOfObjects, Objects);
  85. }
  86.  
  87. /*****************************************************************************
  88. *  Routine to draw the Interactive Menu in the Menu window, using the        *
  89. * InteractiveMenu structure defined above.                     *
  90. *  It is assumed that string not inside of SubWindow will be of length 1.    *
  91. *****************************************************************************/
  92. static void InteractDrawMenu(void)
  93. {
  94.     int i;
  95.     struct textsettingstype oldtext;
  96.  
  97.     gettextsettings(&oldtext);
  98.     settextjustify(CENTER_TEXT, CENTER_TEXT);       /* Draw strings centered. */
  99.  
  100.     GGClearMenuArea();                   /* Clear the menu window. */
  101.  
  102.     for (i=0; i<INTERACT_NUM_OF_STRINGS; i++) {/* Draw the strings of struct.*/
  103.         GGMySetColor(InteractMenu.Strings[i].Color);
  104.         GGXYPutStr(InteractMenu.Strings[i].X,
  105.            InteractMenu.Strings[i].Y,
  106.            InteractMenu.Strings[i].Str);
  107.     }
  108.  
  109.     for (i=0; i<INTERACT_NUM_OF_SUB_WINDOWS; i++) {/* Draw strct sub windows.*/
  110.         GGMySetColor(InteractMenu.SubWindows[i].Color);
  111.     /* Draw the frame of the SubWindow: */
  112.     GGMyMove(InteractMenu.SubWindows[i].X - INTERACT_SUB_WINDOW_WIDTH,
  113.          InteractMenu.SubWindows[i].Y - INTERACT_SUB_WINDOW_HEIGHT);
  114.     GGMyDraw(InteractMenu.SubWindows[i].X + INTERACT_SUB_WINDOW_WIDTH,
  115.          InteractMenu.SubWindows[i].Y - INTERACT_SUB_WINDOW_HEIGHT);
  116.     GGMyDraw(InteractMenu.SubWindows[i].X + INTERACT_SUB_WINDOW_WIDTH,
  117.          InteractMenu.SubWindows[i].Y + INTERACT_SUB_WINDOW_HEIGHT);
  118.     GGMyDraw(InteractMenu.SubWindows[i].X - INTERACT_SUB_WINDOW_WIDTH,
  119.          InteractMenu.SubWindows[i].Y + INTERACT_SUB_WINDOW_HEIGHT);
  120.     GGMyDraw(InteractMenu.SubWindows[i].X - INTERACT_SUB_WINDOW_WIDTH,
  121.          InteractMenu.SubWindows[i].Y - INTERACT_SUB_WINDOW_HEIGHT);
  122.  
  123.     /* Now the strings inside (and if outside, a middle vertical line): */
  124.     if (InteractMenu.SubWindows[i].TextInside)
  125.         GGXYPutStr(InteractMenu.SubWindows[i].X,
  126.                InteractMenu.SubWindows[i].Y,
  127.                InteractMenu.SubWindows[i].Str);
  128.     else {
  129.         GGXYPutStr(InteractMenu.SubWindows[i].X -
  130.                 INTERACT_SUB_WINDOW_WIDTH - 0.025,
  131.                InteractMenu.SubWindows[i].Y,
  132.                InteractMenu.SubWindows[i].Str);
  133.         GGMyMove(InteractMenu.SubWindows[i].X,
  134.              InteractMenu.SubWindows[i].Y -
  135.                 INTERACT_SUB_WINDOW_HEIGHT);
  136.         GGMyDraw(InteractMenu.SubWindows[i].X,
  137.              InteractMenu.SubWindows[i].Y +
  138.                 INTERACT_SUB_WINDOW_HEIGHT);
  139.     }
  140.     }
  141.  
  142.     settextjustify(oldtext.horiz, oldtext.vert);
  143. }
  144.  
  145. /*****************************************************************************
  146. *  Routine to handle data from the input device (keyboard, mouse etc.) -     *
  147. * clip it against the sub windows of the interactive menu and perform the    *
  148. * required transfomation, by updating the global view matrix object VIEW_MAT *
  149. *  The input data in the Rotation/Translation/Scaling sub windows is used    *
  150. * (horizontal distance from sub window center) to set amount of change.         *
  151. *****************************************************************************/
  152. static void InteractHandleInput(FileDescription **FD, int NumOfObj,
  153.                             char **Objects)
  154. {
  155.     int i, UpdateView;
  156.     double x, y, ChangeFactor;
  157.     char *p, GifFileName[FILE_NAME_LEN];
  158.     static char GifFileCount = '0';
  159.     MatrixType Mat, OrigViewMat, OrigPerspMat;
  160.  
  161.     /* Save copy of original matrix, so we can recover if reset is requeired.*/
  162.     GEN_COPY(OrigViewMat,  GlblViewMat,  sizeof(MatrixType));
  163.     GEN_COPY(OrigPerspMat, GlblPerspMat, sizeof(MatrixType));
  164.     switch (GlblViewMode) {             /* Update the current view. */
  165.     case VIEW_ORTHOGRAPHIC:
  166.         GEN_COPY(CrntViewMat, GlblViewMat, sizeof(MatrixType));
  167.         break;
  168.     case VIEW_PERSPECTIVE:
  169.         MultTwo4by4(CrntViewMat, GlblViewMat, GlblPerspMat);
  170.         break;
  171.     }
  172.  
  173.     GGClearViewArea();                   /* Clear the view window. */
  174.     ViewGeomObjectList(FD, NumOfObj, Objects); /* Display it for first time. */
  175.  
  176.     while (TRUE) {
  177.     MouseFlushBuffer();      /* Flush out any duplicated points picked. */
  178.     GGGetPoint(&x, &y);        /* Get coordinates from pick device. */
  179.  
  180.     for (i=0; i<INTERACT_NUM_OF_SUB_WINDOWS; i++)/* Test all sub windows.*/
  181.         if (ABS(InteractMenu.SubWindows[i].Y - y) <
  182.                         INTERACT_SUB_WINDOW_HEIGHT &&
  183.             ABS(InteractMenu.SubWindows[i].X - x) <
  184.                         INTERACT_SUB_WINDOW_WIDTH)
  185.         break;              /* The picked point is in this window! */
  186.  
  187.     ChangeFactor = (x - InteractMenu.SubWindows[i].X) //* Between -1..1. */
  188.                         INTERACT_SUB_WINDOW_WIDTH;
  189.     if (i >= INTERACT_NUM_OF_SUB_WINDOWS) {
  190.         GGTone(1000, 100);
  191.         GGTone(1500, 100);
  192.         GGTone(1000, 100);
  193.         continue;
  194.     }
  195.  
  196.     UpdateView = TRUE;
  197.     GenUnitMat(Mat);                /* No transformation by default! */
  198.  
  199.     switch (i) {
  200.         case 0:               /* Its Coordinate system - toggle it. */
  201.         switch (GlblTransformMode) {
  202.             case TRANS_SCREEN:
  203.             InteractUpdateMenu("Object Coords.", 0);
  204.             GlblTransformMode = TRANS_OBJECT;
  205.             break;
  206.             case TRANS_OBJECT:
  207.             InteractUpdateMenu("Screen Coords.", 0);
  208.             GlblTransformMode = TRANS_SCREEN;
  209.             break;
  210.         }
  211.         UpdateView = FALSE;
  212.         break;
  213.         case 1:            /* Toggle Perspective/Orthographic view. */
  214.         switch (GlblViewMode) {
  215.             case VIEW_PERSPECTIVE:
  216.             InteractUpdateMenu("Orthographic", 1);
  217.             GlblViewMode = VIEW_ORTHOGRAPHIC;
  218.             break;
  219.             case VIEW_ORTHOGRAPHIC:
  220.             InteractUpdateMenu("Perspective", 1);
  221.             GlblViewMode = VIEW_PERSPECTIVE;
  222.             break;
  223.         }
  224.         break;
  225.         case 2:              /* Set Perspective Screen Z point. */
  226.         if (GlblViewMode != VIEW_PERSPECTIVE) {
  227.             GGTone(1000, 100);               /* Do some noise! */
  228.             UpdateView = FALSE;
  229.             break;
  230.         }
  231.         /* Make it between 0.5 and 1.5: */
  232.         ChangeFactor = ChangeFactor / 2.0 + 1.0;
  233.         GlblPerspMat[2][2] *= ChangeFactor;
  234.         GlblPerspMat[2][3] *= ChangeFactor;
  235.         GlblPerspMat[3][2] *= ChangeFactor;
  236.         break;
  237.         case 3:               /* Its rotation along the X axis. */
  238.         GenMatRotX1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
  239.         break;
  240.         case 4:               /* Its rotation along the Y axis. */
  241.         GenMatRotY1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
  242.         break;
  243.         case 5:               /* Its rotation along the Z axis. */
  244.         GenMatRotZ1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
  245.         break;
  246.         case 6:            /* Its translation along the X axis. */
  247.         GenMatTrans(ChangeFactor * MAX_TRANSLATE_FACTOR, 0.0, 0.0,
  248.                                     Mat);
  249.         break;
  250.         case 7:            /* Its translation along the Y axis. */
  251.         GenMatTrans(0.0, ChangeFactor * MAX_TRANSLATE_FACTOR, 0.0,
  252.                                     Mat);
  253.         break;
  254.         case 8:            /* Its translation along the Z axis. */
  255.         GenMatTrans(0.0, 0.0, ChangeFactor * MAX_TRANSLATE_FACTOR,
  256.                                     Mat);
  257.         break;
  258.         case 9:                  /* Its scaling along all axes. */
  259.         if (ChangeFactor > 0.0)              /* Make it around 1... */
  260.              ChangeFactor = ChangeFactor * MAX_SCALE_FACTOR + 1.0;
  261.         else ChangeFactor = 1.0 /
  262.             (-ChangeFactor * MAX_SCALE_FACTOR + 1.0);
  263.         GenMatScale(ChangeFactor, ChangeFactor, ChangeFactor, Mat);
  264.         break;
  265.         case 10:                     /* Toggle depth cueing. */
  266.         GlblDepthCue = !GlblDepthCue;
  267.         InteractUpdateMenu(GlblDepthCue ? "Depth Cue" : "No Depth Cue",
  268.                    10);
  269.         break;
  270.         case 11:                /* Generate GIF file from screen. */
  271.         strcpy(GifFileName, GENERIC_GIF_FILE);
  272.         if ((p = strchr(GifFileName, '#')) != NULL) {
  273.             *p = GifFileCount;
  274.             if (GifFileCount++ == '9') GifFileCount = '0';
  275.         }
  276.         if (DumpScreen(GifFileName, GraphDriver, GGGraphMode) != 0) {
  277.             /* Something went wrong - let the user know about it. */
  278.             GGTone(400, 300);
  279.             GGTone(100, 300);
  280.         }
  281.         else GGTone(1000, 100);
  282.         UpdateView = FALSE;
  283.         break;
  284.         case 12:                /* Save view as PostScript file. */
  285.         SavePostScript(FD, NumOfObj, Objects);
  286.         UpdateView = FALSE;
  287.         break;
  288.         case 13:                  /* Save transformation matrix. */
  289.         SaveCurrentMat();
  290.         UpdateView = FALSE;
  291.         break;
  292.         case 14:                 /* Reset transformation matrix. */
  293.         GEN_COPY(GlblViewMat,  OrigViewMat,  sizeof(MatrixType));
  294.         GEN_COPY(GlblPerspMat, OrigPerspMat, sizeof(MatrixType));
  295.         break;
  296.         case 15:
  297.         return;                        /* Its Quit. */
  298.         default:
  299.         GGTone(1000, 100);               /* Do some noise! */
  300.         UpdateView = FALSE;
  301.         break;
  302.     }
  303.     if (UpdateView) {
  304.         GGClearViewArea();               /* Clear the view window. */
  305.  
  306.         switch (GlblTransformMode) {/* Udpate the global viewing matrix. */
  307.         case TRANS_SCREEN:
  308.             MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
  309.             break;
  310.         case TRANS_OBJECT:
  311.             MultTwo4by4(GlblViewMat, Mat, GlblViewMat);
  312.             break;
  313.         }
  314.  
  315.         switch (GlblViewMode) {         /* Update the current view. */
  316.         case VIEW_ORTHOGRAPHIC:
  317.             GEN_COPY(CrntViewMat, GlblViewMat, sizeof(MatrixType));
  318.             break;
  319.         case VIEW_PERSPECTIVE:
  320.             MultTwo4by4(CrntViewMat, GlblViewMat, GlblPerspMat);
  321.             break;
  322.         }
  323.  
  324.         ViewGeomObjectList(FD, NumOfObj, Objects);    /* And display it... */
  325.     }
  326.     }
  327. }
  328.  
  329. /*****************************************************************************
  330. *  Routine to update entry Entry with a new string Str.                 *
  331. *****************************************************************************/
  332. static void InteractUpdateMenu(char *Str, int Entry)
  333. {
  334.     struct textsettingstype oldtext;
  335.     struct viewporttype    view;
  336.  
  337.     gettextsettings(&oldtext);
  338.     settextjustify(CENTER_TEXT, CENTER_TEXT);       /* Draw strings centered. */
  339.  
  340.     getviewsettings(&view);
  341.     GGViewPortMenuArea();
  342.  
  343.     GGMySetColor(BLACK);                /* Erase the old string. */
  344.     GGXYPutStr(InteractMenu.SubWindows[Entry].X,
  345.            InteractMenu.SubWindows[Entry].Y,
  346.            InteractMenu.SubWindows[Entry].Str);
  347.  
  348.     InteractMenu.SubWindows[Entry].Str = Str;           /* Update to new one. */
  349.  
  350.     GGMySetColor(InteractMenu.SubWindows[Entry].Color); /* And draw the new. */
  351.     GGXYPutStr(InteractMenu.SubWindows[Entry].X,
  352.            InteractMenu.SubWindows[Entry].Y,
  353.            InteractMenu.SubWindows[Entry].Str);
  354.  
  355.     settextjustify(oldtext.horiz, oldtext.vert);
  356.     setviewport(view.left, view.top, view.right, view.bottom, view.clip);
  357. }
  358.  
  359. /*****************************************************************************
  360. * Routine to draw NumOfObjects given in    Objects    from FileDescription FD         *
  361. * according to view matrix Mat.    If NumOfObjects    == 0 then all the objects    *
  362. * are drawn. If NumEdges != 0 only the first NumEdges edges in each polygon  *
  363. * are drawn. If InterFlag then INTERNAL edges (created by IRIT solid         *
  364. * modeller) are also drawn.                             *
  365. *****************************************************************************/
  366. static void ViewGeomObjectList(FileDescription **FD, int NumOfObjects,
  367.                                 char **Objects)
  368. {
  369.     int    i;
  370.     ObjectStruct *PObject;
  371.     struct linesettingstype savetype;
  372.  
  373.     getlinesettings(&savetype);              /* Save original line setting. */
  374.  
  375.     GGMySetColor(RED);                    /* Make default color - RED. */
  376.  
  377.     if (setjmp(LongJumpBuffer) == 0)          /* Its the setjmp itself call! */
  378.     if (NumOfObjects > 0)       /* There was something on command line... */
  379.         for (i=0; i<NumOfObjects; i++) {
  380.         if ((PObject = SearchObject(FD, *Objects)) ==
  381.                             (ObjectStruct *) NULL)
  382.             printf("Given Object %s not found in data files\n",
  383.                                     *Objects);
  384.         else ViewOneObject(PObject);
  385.         Objects++;
  386.         }
  387.     else {
  388.         /* Draw all objects not in other object by scanning object trees.*/
  389.         DrawAllObjects(FD);        /* and drawing ones with Reference == 0. */
  390.     }
  391.  
  392.     setlinestyle(savetype.linestyle, savetype.upattern, savetype.thickness);
  393. }
  394.  
  395. /*****************************************************************************
  396. * Routine to save the current view trans. GlblViewMat to a generic mat file  *
  397. *****************************************************************************/
  398. static void SaveCurrentMat(void)
  399. {
  400.     int    i, j;
  401.     FILE *f;
  402.     char *p, FileName[FILE_NAME_LEN];
  403.     static char FileCount = '0';
  404.  
  405.     strcpy(FileName, GENERIC_MAT_FILE);
  406.     if ((p = strchr(FileName, '#')) != NULL) {
  407.     *p = FileCount;
  408.     if (FileCount++ == '9') FileCount = '0';
  409.     }
  410.     if ((f = fopen(FileName, "wt")) == NULL) {
  411.     GGTone(700, 200);
  412.     return;
  413.     }
  414.  
  415.     for    (i=0; i<4; i++)    {
  416.     for (j=0; j<4; j++) fprintf(f, "%12lf ", GlblViewMat[i][j]);
  417.     fprintf(f, "\n");
  418.     }
  419.  
  420.     if (GlblViewMode == VIEW_PERSPECTIVE) {
  421.     fprintf(f, "\n");
  422.     for (i=0; i<4; i++) {
  423.         for (j=0; j<4; j++) fprintf(f, "%12lf ", GlblPerspMat[i][j]);
  424.         fprintf(f, "\n");
  425.     }
  426.     }
  427.  
  428.     fclose(f);
  429. }
  430.  
  431. /*****************************************************************************
  432. * Routine to search for    an object in the File descriptions FD. Note that if  *
  433. * an object exists more    than once only the first will be returned. If none   *
  434. * is found then    NULL is    returned, else a pointer to that object    struct.         *
  435. *****************************************************************************/
  436. static ObjectStruct *SearchObject(FileDescription **FD, char *Object)
  437. {
  438.      BinTree *PBinTree;
  439.  
  440.      while (*FD) {
  441.       if ((PBinTree    = GetBinTree(Object, (*FD++) -> ObjectPointer)) !=
  442.                          (BinTree *) NULL)
  443.       return PBinTree -> Data.PObject;
  444.      }
  445.      return (ObjectStruct *) NULL;
  446. }
  447.  
  448. /*****************************************************************************
  449. * Routine to draw all the objects not in other objects...             *
  450. * by scanning all the object trees and drawing the objects with    Reference==0 *
  451. * meaning nobody referred to them yet...                     *
  452. *****************************************************************************/
  453. static void DrawAllObjects(FileDescription **FD)
  454. {
  455.     while (*FD)    VisitObjectTree((*FD++) -> ObjectPointer);
  456. }
  457.  
  458. /*****************************************************************************
  459. * Routine to draw all the objects not in other objects...             *
  460. * by scanning all the object in    tree PBinTree and drawing the objects with   *
  461. * Reference==0,    meaning    nobody referred    to them    yet...                 *
  462. *****************************************************************************/
  463. static void VisitObjectTree(BinTree *PBinTree)
  464. {
  465.     if (PBinTree == (BinTree *)    NULL) return;
  466.  
  467.     VisitObjectTree(PBinTree -> right);
  468.  
  469.     if (MoreFlag == 1)
  470.     printf("Drawing object %s\n", PBinTree -> Name);
  471.     ViewOneObject(PBinTree -> Data.PObject);
  472.  
  473.     VisitObjectTree(PBinTree -> left);
  474. }
  475.  
  476. /*****************************************************************************
  477. * Routine to draw one object Object, using the Matrix transform    Mat.         *
  478. *****************************************************************************/
  479. static void ViewOneObject(ObjectStruct *PObject)
  480. {
  481.     PolygonStruct *PList = PObject -> PPolygon;
  482.  
  483.     SetDrawColor(PObject -> Color);            /* Default color for object. */
  484.  
  485.     while (PList) {
  486.     ViewOnePolygon(PList);
  487.     PList =    PList -> Pnext;
  488.     }
  489. }
  490.  
  491. /*****************************************************************************
  492. * Routine to draw one polygon, using the Matrix    transform Mat.             *
  493. * Note this is the routine that    makes the real drawing...             *
  494. *****************************************************************************/
  495. static void ViewOnePolygon(PolygonStruct *PPolygon)
  496. {
  497.     int    i, Count, DrawNextEdge, NumOfVertices;
  498.     float MappedNormal[3], PolyNormal[3];
  499.     VertexStruct *PList = PPolygon -> PVertex;
  500.  
  501.     TestQuitView();
  502.  
  503.     Count = NumEdges;
  504.  
  505.     if (PList == NULL) return;
  506.  
  507.     switch (PPolygon -> PolyType) {
  508.     case POINTLIST:
  509.         while (PList) {
  510.         MyMoveTo(PList -> Coord);
  511.         MyDrawTo(PList -> Coord);
  512.         PList = PList -> Pnext;
  513.         }
  514.         break;
  515.     case POLYLINE:
  516.         MyMoveTo(PList -> Coord);
  517.         DrawNextEdge = !PList -> Internal;
  518.         PList = PList -> Pnext;
  519.  
  520.         while (PList) {
  521.         if (DrawNextEdge || InterFlag)
  522.             MyDrawTo(PList -> Coord);
  523.         else MyMoveTo(PList -> Coord);
  524.  
  525.         if (DrawVNormalsFlag && PList -> HasNormal) {
  526.             for (i=0; i<3; i++) MappedNormal[i] =
  527.                     PList -> Coord[i] + PList -> Normal[i];
  528.             MyDrawTo(MappedNormal);
  529.             MyMoveTo(PList -> Coord);
  530.         }
  531.         DrawNextEdge = !PList -> Internal;
  532.         PList = PList -> Pnext;
  533.         }
  534.         break;
  535.     case POLYGON:
  536.         if (DrawPNormalsFlag && PPolygon->HasPlane)
  537.         {
  538.         for (i=0; i<3; i++) PolyNormal[i] = PList -> Coord[i];
  539.         NumOfVertices = 1;
  540.         }
  541.  
  542.         MyMoveTo(PList -> Coord);
  543.         DrawNextEdge = !PList -> Internal;
  544.         PList = PList -> Pnext;
  545.  
  546.         while (PList) {
  547.         if (DrawNextEdge || InterFlag)
  548.             MyDrawTo(PList -> Coord);
  549.         else MyMoveTo(PList -> Coord);
  550.  
  551.         if (DrawVNormalsFlag && PList -> HasNormal) {
  552.             for (i=0; i<3; i++) MappedNormal[i] =
  553.                     PList -> Coord[i] + PList -> Normal[i];
  554.             i = ClosedObject;
  555.             ClosedObject = FALSE;
  556.             MyDrawTo(MappedNormal);
  557.             MyMoveTo(PList -> Coord);
  558.             ClosedObject = i;
  559.         }
  560.  
  561.         if (DrawPNormalsFlag && PPolygon->HasPlane)
  562.         {
  563.             for (i=0; i<3; i++) PolyNormal[i] += PList -> Coord[i];
  564.             NumOfVertices++;
  565.         }
  566.         /* If -e option specified #Edges to draw. */
  567.         if (!(--Count)) return;
  568.         DrawNextEdge = !PList -> Internal;
  569.         PList = PList -> Pnext;
  570.         }
  571.  
  572.         /* Close polygon by drawing a line to first vertex. */
  573.         if (DrawNextEdge || InterFlag)
  574.         MyDrawTo(PPolygon -> PVertex -> Coord);
  575.  
  576.         if (DrawPNormalsFlag && PPolygon->HasPlane)
  577.         {
  578.         for (i=0; i<3; i++) PolyNormal[i] /= NumOfVertices;
  579.         MyMoveTo(PolyNormal);
  580.         for (i=0; i<3; i++) PolyNormal[i] += PPolygon->Plane[i];
  581.         i = ClosedObject;
  582.         ClosedObject = FALSE;
  583.         MyDrawTo(PolyNormal);
  584.         ClosedObject = i;
  585.         }
  586.         break;
  587.     }
  588. }
  589.  
  590. static double LastCoord[3];    /* Used to store last point we moved/draw to. */
  591.  
  592. /*****************************************************************************
  593. * Routine to mave to 3D    point given as Coord[3], using Mat transform.         *
  594. *****************************************************************************/
  595. static void MyMoveTo(float Coord[3])
  596. {
  597.     MultVecby4by4(LastCoord, Coord, CrntViewMat);   /* Set last point coord. */
  598. }
  599.  
  600. /*****************************************************************************
  601. * Routine to draw to 3D    point given as Coord[3], using Mat transform, from   *
  602. * the last point we moved to.                             *
  603. *****************************************************************************/
  604. static void MyDrawTo(float Coord[3])
  605. {
  606.     double NewCoord[3], MiddleCoord[3], t;
  607.  
  608.     MultVecby4by4(NewCoord, Coord, CrntViewMat);    /* Set last point coord. */
  609.     if (ClosedObject && NewCoord[2] < LastCoord[2]) {
  610.     GEN_COPY(LastCoord, NewCoord, 3 * sizeof(double));
  611.     return;
  612.     }
  613.  
  614.     /* Implementation of simple depth cue - if line is >Z or <Z ... */
  615.     if (LastCoord[2] <= 0.0 && NewCoord[2] <= 0.0) {
  616.     setlinestyle(MY_DOTTED_LINE, 0, NORM_WIDTH);
  617.     GGMyMove(LastCoord[0], LastCoord[1]);
  618.     GGMyDraw(NewCoord[0], NewCoord[1]);                /* DRAW! */
  619.     }
  620.     else
  621.     if (LastCoord[2] >= 0.0 && NewCoord[2] >= 0.0 ||
  622.     ABS(LastCoord[2] - NewCoord[2]) < EPSILON) {
  623.     setlinestyle(SOLID_LINE, 0, NORM_WIDTH);
  624.     GGMyMove(LastCoord[0], LastCoord[1]);
  625.     GGMyDraw(NewCoord[0], NewCoord[1]);                /* DRAW! */
  626.     }
  627.     else {                      /* Line intersect Z = 0 plane. */
  628.     t = LastCoord[2] / (LastCoord[2] - NewCoord[2]);
  629.     MiddleCoord[0] = LastCoord[0] * (1.0 - t) + NewCoord[0] * t;
  630.     MiddleCoord[1] = LastCoord[1] * (1.0 - t) + NewCoord[1] * t;
  631.     setlinestyle(SOLID_LINE, 0, NORM_WIDTH);    /* Draw the >Z part: */
  632.     if (LastCoord[2] > 0.0) {
  633.         GGMyMove(LastCoord[0], LastCoord[1]);
  634.         GGMyDraw(MiddleCoord[0], MiddleCoord[1]);            /* DRAW! */
  635.     }
  636.     else {
  637.         GGMyMove(MiddleCoord[0], MiddleCoord[1]);
  638.         GGMyDraw(NewCoord[0], NewCoord[1]);                /* DRAW! */
  639.     }
  640.     setlinestyle(MY_DOTTED_LINE, 0, NORM_WIDTH);    /* Draw the <Z part: */
  641.     if (LastCoord[2] < 0.0) {
  642.         GGMyMove(LastCoord[0], LastCoord[1]);
  643.         GGMyDraw(MiddleCoord[0], MiddleCoord[1]);            /* DRAW! */
  644.     }
  645.     else {
  646.         GGMyMove(MiddleCoord[0], MiddleCoord[1]);
  647.         GGMyDraw(NewCoord[0], NewCoord[1]);                /* DRAW! */
  648.     }
  649.     }
  650.  
  651.     GEN_COPY(LastCoord, NewCoord, 3 * sizeof(double)); /* Set current point. */
  652. }
  653.  
  654. /*****************************************************************************
  655. * Routine to set current drawing color to given    RGB values:             *
  656. * Currently only 8 colors are supported:                     *
  657. *****************************************************************************/
  658. static void SetDrawColor(int Color)
  659. {
  660.     GGMySetColor(Color);
  661. }
  662.  
  663. /*****************************************************************************
  664. *  Routine to test if quit display event - occured - SPACE was hit on         *
  665. * keyboard or right button was clicked on mouse.                 *
  666. *****************************************************************************/
  667. static void TestQuitView(void)
  668. {
  669.     int x, y, Buttons;
  670.  
  671.     if (kbhit() && getch() == ' ')
  672.     longjmp(LongJumpBuffer, 1);                   /* Jump to... */
  673.  
  674.     if (MouseExists && MouseQueryBuffer()) {
  675.     MouseGetBuffer(&x, &y, &Buttons);
  676.     if (Buttons & 0x02) longjmp(LongJumpBuffer, 1);           /* Jump to... */
  677.     }
  678. }
  679.