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

  1. /*****************************************************************************
  2. *   "Irit" - the 3d polygonal solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. * Module to handle viewing of objects in the ViewWindow.             *
  7. *****************************************************************************/
  8.  
  9. #ifdef __MSDOS__
  10. #include <graphics.h>
  11. #include <conio.h>
  12. #endif /* __MSDOS__ */
  13.  
  14. #include <stdio.h>
  15. #include <math.h>
  16. #include "program.h"
  17. #include "windowsl.h"
  18. #include "windowsg.h"
  19. #include "viewobjl.h"
  20. #include "viewobjg.h"
  21. #include "graphgng.h"
  22. #include "objects.h"
  23. #include "geomat3d.h"
  24.  
  25. #ifdef __MSDOS__
  26. #include "mousedrv.h"
  27. #else
  28. #include "xgraphic.h"
  29. #endif /* __MSDOS__ */
  30.  
  31. static int ViewNormals = FALSE, NormalsColor = 1, /* View normals to object. */
  32.        QuitView = FALSE;
  33. static RealType NormalsSize = 0.1;
  34.  
  35. /* Interactive mode menu set up structure is define below (See ViewObjL.H):  */
  36. InteractWindowStruct InteractMenu = {
  37.     { { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.2, RED, "Rotate" },
  38.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.6, GREEN, "Translate" },
  39.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.0, CYAN, "Scale" },
  40.     },
  41.     { { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.1, YELLOW, TRUE, "Screen Coords." },
  42.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.3, RED,  FALSE, "X" },    /* Rot */
  43.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.4, RED,  FALSE, "Y" },
  44.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.5, RED,  FALSE, "Z" },
  45.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.7, GREEN,  FALSE, "X" }, /* Trans */
  46.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.8, GREEN,  FALSE, "Y" },
  47.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 0.9, GREEN,  FALSE, "Z" },
  48.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.1, CYAN,   FALSE, "" }, /* Scale */
  49.       { (SW_MIN_X + SW_MAX_X) / 2.0, SW_MAX_Y - 1.25, WHITE,  TRUE, "Quit" },
  50.     }
  51. };
  52.  
  53. /*****************************************************************************
  54. *  Routine to interactively display geometric object(s) PObjList on the View *
  55. * window enable rotating/translating/scaling it using the Input Device.      *
  56. *****************************************************************************/
  57. void InteractGeomObject(ObjectStruct *PObjList, RealType *UpdateGlblMat)
  58. {
  59.     struct ObjectStruct *ViewMat;
  60.     MatrixType ViewMatCopy;     /* Save original transformation to recover. */
  61.  
  62.     if (!IS_OLST_OBJ(PObjList))
  63.     FatalError("InteractGeomObject: Not object list object!\n");
  64.  
  65.     if ((ViewMat = GetObject("VIEW_MAT")) == NULL) {
  66.     WndwInputWindowPutStr(
  67.         "No view transformation matrix VIEW_MAT!", RED);
  68.     return;
  69.     }
  70.     else if (!IS_MAT_OBJ(ViewMat)) {
  71.     WndwInputWindowPutStr(
  72.         "VIEW_MAT object was modified (not matrix object)", RED);
  73.     return;
  74.     }
  75.     MAT_COPY(ViewMatCopy, ViewMat -> U.Mat);
  76.  
  77. #ifdef __MSDOS__
  78.     WndwClaimStatus();      /* Gain control on status window - interac menu! */
  79. #endif /* __MSDOS__ */
  80.  
  81.     InteractDrawMenu();                /* Draw the transformation menu. */
  82.     /* Get data from input device, interpret it, and display interactively:  */
  83.     InteractHandleInput(PObjList, ViewMat -> U.Mat);
  84.  
  85.     if (!APX_EQ(*UpdateGlblMat, 0.0))
  86.     MAT_COPY(ViewMat -> U.Mat, ViewMatCopy);         /* Recover. */
  87.  
  88. #ifdef __MSDOS__
  89.     WndwReclaimStatus();  /* Status window is not needed - free and recover. */
  90.     WndwStatusWindowDraw();
  91. #endif /* __MSDOS__ */
  92. }
  93.  
  94. /*****************************************************************************
  95. *  Routine to draw the Interactive Menu in the Status window, using the      *
  96. * InteractiveMenu structure defined above.                     *
  97. *  It is assumed that string not inside of SubWindow will be of length 1.    *
  98. *****************************************************************************/
  99. static void InteractDrawMenu(void)
  100. {
  101.     int i;
  102. #ifdef __MSDOS__
  103.     struct textsettingstype oldtext;
  104.  
  105.     gettextsettings(&oldtext);
  106.     settextjustify(CENTER_TEXT, CENTER_TEXT);       /* Draw strings centered. */
  107.  
  108.     WndwClearWindow(GlblStatusWindow);         /* Clear the status window. */
  109. #endif /* __MSDOS__ */
  110.  
  111.     for (i=0; i<INTERACT_NUM_OF_STRINGS; i++) {   /* Draw strings of struct. */
  112.         GGMySetColor(InteractMenu.Strings[i].Color);
  113.         GGXYPutStr(InteractMenu.Strings[i].X,
  114.            InteractMenu.Strings[i].Y,
  115.            InteractMenu.Strings[i].Str);
  116.     }
  117.  
  118.     for (i=0; i<INTERACT_NUM_OF_SUB_WINDOWS; i++) {    /* Draw sub windows. */
  119.         GGMySetColor(InteractMenu.SubWindows[i].Color);
  120.     /* Draw the frame of the SubWindow: */
  121.     GGMyMove(InteractMenu.SubWindows[i].X - INTERACT_SUB_WINDOW_WIDTH,
  122.          InteractMenu.SubWindows[i].Y - INTERACT_SUB_WINDOW_HEIGHT);
  123.     GGMyDraw(InteractMenu.SubWindows[i].X + INTERACT_SUB_WINDOW_WIDTH,
  124.          InteractMenu.SubWindows[i].Y - INTERACT_SUB_WINDOW_HEIGHT);
  125.     GGMyDraw(InteractMenu.SubWindows[i].X + INTERACT_SUB_WINDOW_WIDTH,
  126.          InteractMenu.SubWindows[i].Y + INTERACT_SUB_WINDOW_HEIGHT);
  127.     GGMyDraw(InteractMenu.SubWindows[i].X - INTERACT_SUB_WINDOW_WIDTH,
  128.          InteractMenu.SubWindows[i].Y + INTERACT_SUB_WINDOW_HEIGHT);
  129.     GGMyDraw(InteractMenu.SubWindows[i].X - INTERACT_SUB_WINDOW_WIDTH,
  130.          InteractMenu.SubWindows[i].Y - INTERACT_SUB_WINDOW_HEIGHT);
  131.  
  132.     /* Now the strings inside (and if outside, a middle vertical line): */
  133.     if (InteractMenu.SubWindows[i].TextInside)
  134.         GGXYPutStr(InteractMenu.SubWindows[i].X,
  135.                InteractMenu.SubWindows[i].Y,
  136.                InteractMenu.SubWindows[i].Str);
  137.     else {
  138.         GGXYPutStr(InteractMenu.SubWindows[i].X -
  139.                 INTERACT_SUB_WINDOW_WIDTH - 0.025,
  140.                InteractMenu.SubWindows[i].Y,
  141.                InteractMenu.SubWindows[i].Str);
  142.         GGMyMove(InteractMenu.SubWindows[i].X,
  143.              InteractMenu.SubWindows[i].Y -
  144.                 INTERACT_SUB_WINDOW_HEIGHT);
  145.         GGMyDraw(InteractMenu.SubWindows[i].X,
  146.              InteractMenu.SubWindows[i].Y +
  147.                 INTERACT_SUB_WINDOW_HEIGHT);
  148.     }
  149.     }
  150.  
  151. #ifdef __MSDOS__
  152.     settextjustify(oldtext.horiz, oldtext.vert);
  153. #endif /* __MSDOS__ */
  154. }
  155.  
  156. /*****************************************************************************
  157. *  Routine to handle data from the input device (keyboard, mouse etc.) -     *
  158. * clip it against the sub windows of the interactive menu and perform the    *
  159. * required transfomation, by updating the global view matrix object VIEW_MAT *
  160. *  The input data in the Rotation/Translation/Scaling sub windows is used    *
  161. * (horizontal distance from sub window center) to set amount of change.         *
  162. *****************************************************************************/
  163. static void InteractHandleInput(ObjectStruct *PObjList, MatrixType GlblViewMat)
  164. {
  165.     int i, UpdateView, ScreenCoord;
  166.     double x, y, ChangeFactor;
  167.     MatrixType Mat;
  168.  
  169.     ScreenCoord = (InteractMenu.SubWindows[0].Str[0] == 'S');
  170.  
  171.     WndwClearWindow(GlblViewWindow);           /* Clear the view window. */
  172.     QuitView = FALSE;
  173.     ViewGeomObjectList(PObjList);       /* Display it for the first time. */
  174.  
  175.     while (TRUE) {
  176.     QuitView = FALSE;
  177. #ifdef __MSDOS__
  178.     while (kbhit()) getch();      /* Flush out any keyboard key strokes. */
  179. #endif /* __MSDOS__ */
  180.     MouseFlushBuffer();      /* Flush out any duplicated points picked. */
  181.     GGGetPoint(&x, &y);        /* Get coordinates from pick device. */
  182.  
  183.     for (i=0; i<INTERACT_NUM_OF_SUB_WINDOWS; i++)/* Test all sub windows.*/
  184.         if (ABS(InteractMenu.SubWindows[i].Y - y) <
  185.                         INTERACT_SUB_WINDOW_HEIGHT &&
  186.         ABS(InteractMenu.SubWindows[i].X - x) <
  187.                         INTERACT_SUB_WINDOW_WIDTH)
  188.         break;              /* The picked point is in this window! */
  189.  
  190.     ChangeFactor = (x - InteractMenu.SubWindows[i].X) / /* Between -1..1.*/
  191.                         INTERACT_SUB_WINDOW_WIDTH;
  192.  
  193.     if (i >= INTERACT_NUM_OF_SUB_WINDOWS) {
  194.         GGTone(1000, 100);
  195.         GGTone(1500, 100);
  196.         GGTone(1000, 100);
  197.         continue;
  198.     }
  199.  
  200.     UpdateView = TRUE;
  201.  
  202.     switch (i) {
  203.         case 0:               /* Its Coordinate system - toggle it. */
  204.         if (ScreenCoord) {
  205.             InteractMenu.SubWindows[0].Str = "Object Coords.";
  206.             ScreenCoord = FALSE;
  207.         }
  208.         else {
  209.             InteractMenu.SubWindows[0].Str = "Screen Coords.";
  210.             ScreenCoord = TRUE;
  211.         }
  212.         InteractDrawMenu();      /* Must update the menu on screen. */
  213.         UpdateView = FALSE;
  214.         break;
  215.         case 1:               /* Its rotation along the X axis. */
  216.         MatGenMatRotX1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
  217.         break;
  218.         case 2:               /* Its rotation along the Y axis. */
  219.         MatGenMatRotY1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
  220.         break;
  221.         case 3:               /* Its rotation along the Z axis. */
  222.         MatGenMatRotZ1(DEG2RAD(ChangeFactor * MAX_ROTATE_ANGLE), Mat);
  223.         break;
  224.         case 4:            /* Its translation along the X axis. */
  225.         MatGenMatTrans(ChangeFactor * MAX_TRANSLATE_FACTOR, 0.0, 0.0,
  226.                                     Mat);
  227.         break;
  228.         case 5:            /* Its translation along the Y axis. */
  229.         MatGenMatTrans(0.0, ChangeFactor * MAX_TRANSLATE_FACTOR, 0.0,
  230.                                     Mat);
  231.         break;
  232.         case 6:            /* Its translation along the Z axis. */
  233.         MatGenMatTrans(0.0, 0.0, ChangeFactor * MAX_TRANSLATE_FACTOR,
  234.                                     Mat);
  235.         break;
  236.         case 7:                  /* Its scaling along all axes. */
  237.         if (ChangeFactor > 0.0)              /* Make it around 1... */
  238.              ChangeFactor = ChangeFactor * MAX_SCALE_FACTOR + 1.0;
  239.         else ChangeFactor = 1.0 /
  240.             (-ChangeFactor * MAX_SCALE_FACTOR + 1.0);
  241.         MatGenMatScale(ChangeFactor, ChangeFactor, ChangeFactor, Mat);
  242.         break;
  243.         case 8:
  244.         return;                        /* Its Quit. */
  245.         default:
  246.         FatalError("InteractHandleInput: Undefine input type, exit\n");
  247.     }
  248.     if (UpdateView) {
  249.         if (ScreenCoord)        /* Udpate the global viewing matrix. */
  250.          MatMultTwo4by4(GlblViewMat, GlblViewMat, Mat);
  251.         else MatMultTwo4by4(GlblViewMat, Mat, GlblViewMat);
  252.         WndwClearWindow(GlblViewWindow);       /* Clear the view window. */
  253.         ViewGeomObjectList(PObjList);        /* And display it... */
  254.     }
  255.     }
  256. }
  257.  
  258. /*****************************************************************************
  259. *  Routine to display the geometric objects in PObjList, by simply calling   *
  260. * ViewGeomObject on all of them. PObjList must be of type OBJ_LIST_OBJ.         *
  261. *****************************************************************************/
  262. static void ViewGeomObjectList(ObjectStruct *PObjList)
  263. {
  264.     int Param = 0;
  265.     struct ObjectStruct *PObj;
  266.     char Line[LINE_LEN];
  267.  
  268.     while ((PObj = PObjList -> U.PObjList[Param]) != NULL &&
  269.        Param++ < MAX_OBJ_LIST && !QuitView) {
  270.     if (!IS_GEOM_OBJ(PObj)) {
  271.         sprintf(Line, "Cannt display none geometric object %s, ignored",
  272.         PObj -> Name);
  273.         WndwInputWindowPutStr(Line, RED);
  274.         continue;
  275.     }
  276.     ViewGeomObject(PObj);
  277.     }
  278. }
  279.  
  280. /*****************************************************************************
  281. *  Routine to fetch the internal parameter from the INTERNAL object.         *
  282. *****************************************************************************/
  283. static int GetInternal(void)
  284. {
  285.     int Internal;
  286.     struct ObjectStruct *PObj = GetObject("INTERNAL");
  287.  
  288.     if (PObj == NULL || !IS_NUM_OBJ(PObj)) {
  289.     WndwInputWindowPutStr("No numeric object name INTERNAL is defined",
  290.                                     RED);
  291.     Internal = DEFAULT_INTERNAL;
  292.     }
  293.     else Internal = !APX_EQ((PObj -> U.R), 0.0);
  294.  
  295.     return Internal;
  296. }
  297.  
  298. /*****************************************************************************
  299. *  Routine to display the geometric object PObj on the View Window:         *
  300. * Uses the global view transformation matrix ViewMat as view point.         *
  301. *****************************************************************************/
  302. void ViewGeomObject(ObjectStruct *PObj)
  303. {
  304.     int Color, ShowNormals, ViewInternal = GetInternal();
  305.     struct PolygonStruct *Pl;
  306.     struct ObjectStruct *ViewMat;
  307.  
  308.     QuitView = FALSE;
  309. #ifdef __MSDOS__
  310.     while (kbhit()) getch();          /* Flush out any keyboard key strokes. */
  311. #endif /* __MSDOS__ */
  312.     MouseFlushBuffer();          /* Flush out any duplicated points picked. */
  313.  
  314.     if (!IS_GEOM_OBJ(PObj))
  315.     FatalError("ViewGeomObject: Not geometric object!\n");
  316.  
  317.     GGWindowViewPort(GlblViewWindow -> MinX, GlblViewWindow -> MinY,
  318.              GlblViewWindow -> MaxX, GlblViewWindow -> MaxY,
  319.              (int) VIEW_WINDOW_NAME);
  320.  
  321.     Pl = PObj -> U.Pl;
  322.  
  323.     if ((ViewMat = GetObject("VIEW_MAT")) == NULL) {
  324.     WndwInputWindowPutStr(
  325.         "No view transformation matrix VIEW_MAT!", RED);
  326.     return;
  327.     }
  328.     else if (!IS_MAT_OBJ(ViewMat)) {
  329.     WndwInputWindowPutStr(
  330.         "VIEW_MAT object was modified (not matrix object)\n", RED);
  331.     return;
  332.     }
  333.  
  334.     Color = GET_OBJECT_COLOR(PObj);
  335.     ShowNormals = (ViewNormals && !IS_POLYLINE_GEOM_OBJ(PObj));
  336.  
  337.     while (Pl && !QuitView) {
  338.     ViewPolygon(Pl, Color, ShowNormals, ViewMat -> U.Mat, ViewInternal);
  339.     Pl = Pl -> Pnext;
  340.     TestQuitView();       /* if break display in the middle - Set QuitView. */
  341.     }
  342. }
  343.  
  344. /*****************************************************************************
  345. *  Routine to test if quit display event - occured - SPACE was hit on         *
  346. * keyboard or right button was clicked on mouse.                 *
  347. *****************************************************************************/
  348. static void TestQuitView(void)
  349. {
  350.     int x, y, Buttons;
  351.  
  352. #ifdef __MSDOS__
  353.     if (kbhit() && getch() == ' ') QuitView = TRUE;
  354. #endif /* __MSDOS__ */
  355.     if (MouseExists && MouseQueryBuffer()) {
  356.     MouseGetBuffer(&x, &y, &Buttons);
  357.     QuitView = (Buttons & 0x02);
  358.     }
  359. }
  360.  
  361. /*****************************************************************************
  362. *  Routine to display one polygon on the view window using the matrix Mat as *
  363. * a transformation matrix.                             *
  364. *****************************************************************************/
  365. static void ViewPolygon(PolygonStruct *Pl, int Color, int ShowNormals,
  366.                     MatrixType Mat, int ViewInternal)
  367. {
  368.     int NumOfPoints, DontDraw;
  369.     RealType CenterX, CenterY;
  370.     PointType P, CenterP;
  371.     struct VertexStruct *V, *VStart;
  372.  
  373.     CenterX = (GlblViewWindow -> MinX + GlblViewWindow -> MaxX) / 2.0;
  374.     CenterY = (GlblViewWindow -> MinY + GlblViewWindow -> MaxY) / 2.0;
  375.  
  376.     V = VStart = Pl -> V;
  377.     if (V == NULL) FatalError("ViewPolygon: Empty polygon to view\n");
  378.  
  379.     MatMultVecby4by4(P, V -> Pt, Mat);           /* Transform the first point. */
  380.     GGMyMove(CenterX + P[0], CenterY + P[1]);
  381.     DontDraw = IS_INTERNAL_EDGE(V) && !ViewInternal;      /* Draw next edge? */
  382.     GGMySetColor(Color);
  383.  
  384.     if (ShowNormals) {            /* If display of normal is required. */
  385.     NumOfPoints = 0;
  386.     PT_CLEAR(CenterP);
  387.     }
  388.  
  389.     do {
  390.     V = V -> Pnext;
  391.     if (ShowNormals) {
  392.         NumOfPoints++;
  393.         PT_ADD(CenterP, CenterP, V -> Pt);
  394.     }
  395.     MatMultVecby4by4(P, V -> Pt, Mat);
  396.     /* If edge is INTERNAL (Irit.h) and not ViewInternal - dont draw: */
  397.     if (DontDraw)
  398.          GGMyMove(CenterX + P[0], CenterY + P[1]);
  399.     else GGMyDraw(CenterX + P[0], CenterY + P[1]);
  400.  
  401.     DontDraw = IS_INTERNAL_EDGE(V) && !ViewInternal;  /* Draw next edge? */
  402.     } while (V != VStart && V -> Pnext != NULL);
  403.  
  404.     if (ShowNormals) {
  405.     PT_SCALE(CenterP, 1.0/NumOfPoints);        /* Estimate for normals. */
  406.     MatMultVecby4by4(P, CenterP, Mat);     /* Transform the first point. */
  407.     GGMyMove(CenterX + P[0], CenterY + P[1]);
  408.     PT_COPY(P, Pl -> Plane);
  409.     PT_SCALE(P, NormalsSize);
  410.     PT_ADD(CenterP, CenterP, P);
  411.     MatMultVecby4by4(P, CenterP, Mat);    /* Transform the second point. */
  412.     GGMySetColor(NormalsColor);
  413.     GGMyDraw(CenterX + P[0], CenterY + P[1]);
  414.     }
  415. }
  416.  
  417. /*****************************************************************************
  418. *  Routine to set the normals default values:                     *
  419. *****************************************************************************/
  420. void ViewSetNormals(RealType *Active, RealType *Size, RealType *Color)
  421. {
  422.     ViewNormals = !APX_EQ(*Active, 0.0);
  423.     NormalsSize = *Size;
  424.     NormalsColor = (int) *Color;
  425. }
  426.