home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / REND386 / CONVERT / IRIT2PLG / IRIT2PLG.C < prev    next >
C/C++ Source or Header  |  1992-04-29  |  18KB  |  580 lines

  1. /* Here it is. Assuming you have irit 3.0, cd to the iritfltr directory, edit
  2.    makefile.tc, insert an entry irit2plg similar to irit2ray, and
  3.    'make -f makefile.tc'
  4.  
  5.                                      Gershon
  6.  */
  7.  
  8. /*****************************************************************************
  9. * Filter to convert IRIT data files to REND386 (IBMPC only) Plg format.         *
  10. *                                         *
  11. * Written by:  Gershon Elber                Ver 1.0, Sep 1991    *
  12. *****************************************************************************/
  13.  
  14. #ifdef __MSDOS__
  15. #include <dos.h>
  16. #include <alloc.h>
  17. #endif /* __MSDOS__ */
  18.  
  19. #include <stdio.h>
  20. #include <math.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #include "irit_sm.h"
  24. #include "iritprsr.h"
  25. #include "getarg.h"
  26. #include "genmat.h"
  27.  
  28. #define GLOBAL_SCALE    200.0  /* Scale obj space -1..1 to -200..200 pixels. */
  29. #define CONVEX_EPSILON  1e-3
  30.  
  31. #ifdef __MSDOS__
  32. extern unsigned int _stklen = 32766;         /* Increase default stack size. */
  33. #endif /* __MSDOS__ */
  34.  
  35. #ifdef NO_CONCAT_STR
  36. static char *VersionStr =
  37.     "Irit2Plg        Version 3.0,    Gershon Elber,\n\
  38.      (C) Copyright 1989/90/91/92 Gershon Elber, Non commercial use only.";
  39. #else
  40. static char *VersionStr = "Irit2Plg    " VERSION ",    Gershon Elber,    "
  41.     __DATE__ ",   " __TIME__ "\n"
  42.     "(C) Copyright 1989/90/91/92 Gershon Elber, Non commercial use only.";
  43. #endif /* NO_CONCAT_STR */
  44.  
  45. static char
  46.     *CtrlStr = "irit2Plg l%- 4%- f%-FineNess!d z%- DFiles!*s";
  47.  
  48. static int
  49.     GlblFineNess = 5,
  50.     FourPerFlat = FALSE;
  51.  
  52. static MatrixType CrntViewMat;            /* This is the current view! */
  53.  
  54. static int TransColorTable[][4] = {
  55.     { /* BLACK        */ 0,    0,   0,   0 },
  56.     { /* BLUE        */ 1,    0,   0, 255 },
  57.     { /* GREEN        */ 2,    0, 255,   0 },
  58.     { /* CYAN        */ 3,    0, 255, 255 },
  59.     { /* RED        */ 4,  255,   0,   0 },
  60.     { /* MAGENTA     */ 5,  255,   0, 255 },
  61.     { /* BROWN        */ 6,   50,   0,   0 },
  62.     { /* LIGHTGRAY    */ 7,  127, 127, 127 },
  63.     { /* DARKGRAY    */ 8,   63,  63,  63 },
  64.     { /* LIGHTBLUE    */ 9,    0,   0, 255 },
  65.     { /* LIGHTGREEN    */ 10,   0, 255,   0 },
  66.     { /* LIGHTCYAN    */ 11,   0, 255, 255 },
  67.     { /* LIGHTRED    */ 12, 255,   0,   0 },
  68.     { /* LIGHTMAGENTA    */ 13, 255,   0, 255 },
  69.     { /* YELLOW        */ 14, 255, 255,   0 },
  70.     { /* WHITE        */ 15, 255, 255, 255 },
  71.     { /* BROWN        */ 20,  50,   0,   0 },
  72.     { /* DARKGRAY    */ 56,  63,  63,  63 },
  73.     { /* LIGHTBLUE    */ 57,   0,   0, 255 },
  74.     { /* LIGHTGREEN    */ 58,   0, 255,   0 },
  75.     { /* LIGHTCYAN    */ 59,   0, 255, 255 },
  76.     { /* LIGHTRED    */ 60, 255,   0,   0 },
  77.     { /* LIGHTMAGENTA    */ 61, 255,   0, 255 },
  78.     { /* YELLOW        */ 62, 255, 255,   0 },
  79.     { /* WHITE        */ 63, 255, 255, 255 },
  80.     {               -1,   0,   0,   0 }
  81. };
  82.  
  83. static int PlgColorTable[16] = {
  84.     /* IRIT     PLG   */
  85.     15, /* BLOCK -> WHITE */
  86.     11, /* BLUE */
  87.     7,  /* GREEN */
  88.     8,  /* CYAN */
  89.     1,  /* RED */
  90.     13, /* MAGENTA */
  91.     2,  /* BROWN */
  92.     14, /* LIGHTGRAY */
  93.     14, /* DARKGRAY */
  94.     10, /* LIGHT BLUE */
  95.     9,  /* LIGHT GREEN */
  96.     8,  /* LIGHT CYAN */
  97.     1,  /* LIGHT RED */
  98.     13, /* LIGHT MAGENTA */
  99.     6,  /* YELLOW */
  100.     15, /* WHITE */    
  101. };
  102.  
  103. static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
  104.                     int NumOfDataFiles);
  105. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
  106.                                 int FineNess);
  107. static void DumpDataForPlg(IPObjectStruct *PObjects);
  108. static void DumpOneObject(FILE *f, IPObjectStruct *PObject,
  109.                       int DumpVertices, int *IncVertices);
  110. static void DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon,
  111.                 int Color, int DumpVertices, int *IncVertices);
  112. static int IsConvexPolygon(IPPolygonStruct *Pl);
  113. static RealType *MapPoint(RealType *Pt);
  114. static void MyExit(int ExitCode);
  115.  
  116. /*****************************************************************************
  117. * Main routine - Read Parameter    line and do what you need...             *
  118. *****************************************************************************/
  119. void main(int argc, char **argv)
  120. {
  121.     int Error,
  122.     FineNessFlag = FALSE,
  123.     LinearOnePolyFlag = FALSE,
  124.     VerFlag = FALSE,
  125.     NumFiles = 0;
  126.     char
  127.     **FileNames = NULL;
  128.     IPObjectStruct *PObjects;
  129.  
  130. #ifdef __MSDOS__
  131.     ctrlbrk((int (*)()) MyExit);              /* Kill process if ^C. */
  132. #endif /* __MSDOS__ */
  133.  
  134.     if ((Error = GAGetArgs (argc, argv, CtrlStr, &LinearOnePolyFlag,
  135.                 &FourPerFlat, &FineNessFlag, &GlblFineNess,
  136.                 &VerFlag, &NumFiles, &FileNames)) != 0) {
  137.     GAPrintErrMsg(Error);
  138.     GAPrintHowTo(CtrlStr);
  139.     MyExit(1);
  140.     }
  141.  
  142.     if (VerFlag) {
  143.     fprintf(stderr, "\n%s\n\n", VersionStr);
  144.     GAPrintHowTo(CtrlStr);
  145.     MyExit(0);
  146.     }
  147.  
  148.     if (LinearOnePolyFlag) {
  149.     fprintf(stderr, "Linear patch side will have a single polygon.\n");
  150.     CagdSetLinear2Poly(CAGD_ONE_POLY_PER_COLIN);
  151.     }
  152.     else
  153.         CagdSetLinear2Poly(CAGD_REG_POLY_PER_LIN);
  154.  
  155.     fprintf(stderr, "%s triangles per flat will be created.\n",
  156.         FourPerFlat ? "Four" : "Two");
  157.  
  158.     if (!NumFiles) {
  159.     fprintf(stderr, "No data file names where given, exit.\n");
  160.     GAPrintHowTo(CtrlStr);
  161.     MyExit(1);
  162.     }
  163.  
  164.     /* Get the data files: */
  165.     IritPrsrPolyListCirc = FALSE;
  166.     PObjects = MainGetDataFiles(FileNames, NumFiles);
  167.  
  168.     if (IritPrsrWasPrspMat)
  169.     MultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
  170.     else
  171.     GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));
  172.  
  173.     DumpDataForPlg(PObjects);
  174.  
  175.     MyExit(0);
  176. }
  177.  
  178. /*****************************************************************************
  179. * Main routine to read the data    description files:                 *
  180. * Returns pointer to pointers on FileDescription structures (one per file).  *
  181. *****************************************************************************/
  182. static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
  183.                     int NumOfDataFiles)
  184. {
  185.     int    i;
  186.     FILE *f;
  187.     char
  188.     *ErrorMsg = NULL;
  189.     IPObjectStruct *PObj, *PObjTail,
  190.     *PObjHead = NULL;
  191.  
  192.     for    (i = 0; i < NumOfDataFiles; i++) {
  193. #ifdef __MSDOS__
  194.     if ((f = fopen(*DataFileNames, "rt")) == NULL) {   /* Open the file. */
  195. #else
  196.     if ((f = fopen(*DataFileNames, "r")) == NULL) {    /* Open the file. */
  197. #endif /* __MSDOS__ */
  198.         fprintf(stderr, "Can't open data file %s\n", *DataFileNames);
  199.         MyExit(1);
  200.     }
  201.  
  202.     if ((PObj = IritPrsrGetObjects(f)) != NULL) {  /* Get the data file. */
  203.         PObjTail = PObj;
  204.         while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext;
  205.         PObjTail -> Pnext = PObjHead;
  206.         PObjHead = PObj;
  207.     }
  208.  
  209.     fclose(f);                      /* Close the file. */
  210.  
  211.     if (IritPrsrParseError(&ErrorMsg)) {
  212.         fprintf(stderr, "Parse error in \"%s\":\n%s\n", *DataFileNames, ErrorMsg);
  213.         MyExit(1);
  214.     }
  215.  
  216.     DataFileNames++;              /* Skip to next file name. */
  217.     }
  218.  
  219.     if (PObjHead == NULL) {
  220.     fprintf(stderr, "No data found.\n");
  221.     MyExit(1);
  222.     }
  223.  
  224.     return PObjHead;
  225. }
  226.  
  227. /*****************************************************************************
  228. * Routine to convert all surfaces/curves into polylines as follows:         *
  229. * Curves are converted to single polyline with SamplesPerCurve samples.         *
  230. * Surface are converted into GlblNumOfIsolines curves in each axes, each     *
  231. * handled as Curves above. The curves and surfaces are then deleted.         *
  232. *****************************************************************************/
  233. IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
  234.                     IPObjectStruct *SrfObjs)
  235. {
  236.     int LocalFourPerFlat;
  237.     float RelativeFineNess;
  238.     CagdCrvStruct *Crvs;
  239.     CagdSrfStruct *Srf, *Srfs;
  240.     IPObjectStruct *PObj, *PObjNext;
  241.     IPPolygonStruct *PPolygon, *PPolygonTemp;
  242.  
  243.     if (CrvObjs == NULL && SrfObjs == NULL) return NULL;
  244.  
  245.     /* Make sure requested format is something reasonable. */
  246.     if (GlblFineNess < 2) {
  247.     GlblFineNess = 2;
  248.     fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n");
  249.     }
  250.  
  251.     if (CrvObjs) {
  252.     /* Curves are not rendered at this time and they are ignored. */
  253.     for (PObj = CrvObjs; PObj != NULL;) {
  254.         Crvs = PObj -> U.PCrvs;
  255.         CagdCrvFreeList(Crvs);
  256.         PObjNext = PObj -> Pnext;
  257.         free((VoidPtr) PObj);
  258.         PObj = PObjNext;
  259.     }
  260.     CrvObjs = NULL;
  261.     }
  262.  
  263.     if (SrfObjs) {
  264.     for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
  265.         char *p;
  266.  
  267.         Srfs = PObj -> U.PSrfs;
  268.         PObj -> U.PPolygon = NULL;
  269.         PObj -> Type = IP_OBJ_POLY;
  270.  
  271.         RelativeFineNess = 1.0;
  272.         LocalFourPerFlat = FourPerFlat;
  273.  
  274.         if (IritPrsrGetStrAttrib(PObj, "twoperflat"))
  275.         LocalFourPerFlat = FALSE;
  276.         if (IritPrsrGetStrAttrib(PObj, "fourperflat"))
  277.         LocalFourPerFlat = TRUE;
  278.  
  279.         if ((p = IritPrsrGetStrAttrib(PObj, "resolution")) != NULL &&
  280.         sscanf(p, "%f", &RelativeFineNess) != 1)
  281.         RelativeFineNess = 1.0;
  282.  
  283.         for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
  284.         PPolygon = PPolygonTemp =
  285.             Surface2Polygons(Srf, LocalFourPerFlat,
  286.                      (int) (RelativeFineNess * GlblFineNess));
  287.         while (PPolygonTemp -> Pnext)
  288.             PPolygonTemp = PPolygonTemp -> Pnext;
  289.         PPolygonTemp -> Pnext = PObj -> U.PPolygon;
  290.         PObj -> U.PPolygon = PPolygon;
  291.         }
  292.         CagdSrfFreeList(Srfs);
  293.     }
  294.     }
  295.  
  296.     return SrfObjs;
  297. }
  298.  
  299. /*****************************************************************************
  300. * Routine to convert a single surface into a polylines with SamplesPerCurve  *
  301. * samples, NumOfIsolines isolines into a polyline object list.             *
  302. *****************************************************************************/
  303. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
  304.                      int FineNess)
  305. {
  306.     int i, j;
  307.     IPVertexStruct *V, *VHead,
  308.     *VTail = NULL;
  309.     IPPolygonStruct *P,
  310.     *PHead = NULL;
  311.     CagdPolygonStruct *CagdPolygon,
  312.     *CagdPolygonHead = CagdSrf2Polygons(Srf, FineNess, TRUE, FourPerFlat);
  313.  
  314.     for (CagdPolygon = CagdPolygonHead, VHead = NULL;
  315.      CagdPolygon != NULL;
  316.      CagdPolygon = CagdPolygon -> Pnext) {
  317.     /* All polygons are triangles! */
  318.  
  319.     for (i = 0, VHead = NULL; i < 3; i++) {         /* Convert to vertices. */
  320.         V = IritPrsrNewVertexStruct();
  321.         IP_SET_VRTX_NORMAL(V);             /* This vertex has normal. */
  322.  
  323.         for (j = 0; j < 3; j++)                /* Convert to our format. */
  324.            V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
  325.         for (j = 0; j < 3; j++)
  326.            V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
  327.  
  328.         if (VHead) {
  329.         VTail -> Pnext = V;
  330.         VTail = V;
  331.         }
  332.         else
  333.         VHead = VTail = V;
  334.     }
  335.  
  336.     P = IritPrsrNewPolygonStruct();
  337.     P -> PVertex = VHead;
  338.     P -> Type = IP_POLYGON;
  339.     P -> Pnext = PHead;
  340.  
  341.     PHead = P;
  342.     }
  343.  
  344.     CagdPolygonFreeList(CagdPolygonHead);
  345.  
  346.     return PHead;
  347. }
  348.  
  349. /*****************************************************************************
  350. * Dumps the data for REND386 Plg into stdout.                     *
  351. *****************************************************************************/
  352. static void DumpDataForPlg(IPObjectStruct *PObjects)
  353. {
  354.     int IncVertices,
  355.         TotalVertices = 0,
  356.     TotalPolys = 0;
  357.     char
  358.     *Name = NULL;
  359.     IPVertexStruct *PVertex;
  360.     IPPolygonStruct *PPoly;
  361.     IPObjectStruct *PObj,
  362.     *PObjHead = NULL;
  363.     FILE *f = stdout;           /* Change it if you want it into "real" file. */
  364.     
  365.     /* Reverse object list since it was loaded in reverse by iritprsr module.*/
  366.     while (PObjects != NULL) {
  367.     PObj = PObjects;
  368.     PObjects = PObjects -> Pnext;
  369.     PObj -> Pnext = PObjHead;
  370.     PObjHead = PObj;
  371.     }
  372.     PObjects = PObjHead;
  373.  
  374.     /* Count how many polygons/vertices we have in this data set and print. */
  375.     for (PObj = PObjects; PObj != NULL; PObj = PObj -> Pnext) {
  376.     if (PObj -> Type != IP_OBJ_POLY) {
  377.         fprintf(stderr, "Wrong input, a poly was expected.\n");
  378.         exit(1);
  379.     }
  380.     if (Name == NULL && strlen(PObj -> Name) > 0) Name = PObj -> Name;
  381.  
  382.     for (PPoly = PObj -> U.PPolygon;
  383.          PPoly != NULL;
  384.          PPoly = PPoly -> Pnext) {
  385.         if (PPoly -> Type != IP_POLYGON) continue;
  386.  
  387.         TotalPolys++;
  388.  
  389.         for (PVertex = PPoly -> PVertex;
  390.          PVertex != NULL;
  391.          PVertex = PVertex -> Pnext) {
  392.         TotalVertices++;
  393.         }
  394.     }
  395.     }
  396.  
  397.     if (Name != NULL)
  398.         fprintf(f, "IRIT %d %d\n", TotalVertices, TotalPolys);
  399.     else
  400.     fprintf(f, "%s_IRIT %d %d\n", Name, TotalVertices, TotalPolys);
  401.  
  402.     for (IncVertices = 0, PObj = PObjects; PObj != NULL; PObj = PObj -> Pnext)
  403.     DumpOneObject(f, PObjects, TRUE, &IncVertices);
  404.     if (IncVertices != TotalVertices) {
  405.     fprintf(stderr, "Inconsistent vertices count.\n");
  406.     exit(1);
  407.     }
  408.  
  409.     for (IncVertices = 0, PObj = PObjects; PObj != NULL; PObj = PObj -> Pnext)
  410.     DumpOneObject(f, PObjects, FALSE, &IncVertices);
  411.     if (IncVertices != TotalVertices) {
  412.     fprintf(stderr, "Inconsistent vertices count.\n");
  413.     exit(1);
  414.     }
  415.  
  416.     fclose(f);
  417. }
  418.  
  419. /*****************************************************************************
  420. * Routine to dump one object PObject.                         *
  421. *****************************************************************************/
  422. static void DumpOneObject(FILE *f, IPObjectStruct *PObject,
  423.                       int DumpVertices, int *IncVertices)
  424. {
  425.     int i, Color;
  426.     IPPolygonStruct
  427.     *PList = PObject -> U.PPolygon;
  428.  
  429.     if (IP_HAS_OBJ_COLOR(PObject)) {
  430.     for (i = 0; TransColorTable[i][0] >= 0; i++) {
  431.         if (TransColorTable[i][0] == PObject -> Color) {
  432.         Color = PlgColorTable[i];
  433.         break;
  434.         }
  435.     }
  436.     }
  437.     else
  438.         Color = 15;                     /* Default to white. */
  439.  
  440.     while (PList) {
  441.     DumpOnePolygon(f, PList, Color, DumpVertices, IncVertices);
  442.     PList =    PList -> Pnext;
  443.     }
  444. }
  445.  
  446. /*****************************************************************************
  447. * Routine to dump one polygon, using global Matrix transform CrntViewMat.    *
  448. *****************************************************************************/
  449. static void DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon,
  450.                 int Color, int DumpVertices, int *IncVertices)
  451. {
  452.     int CountVertices;
  453.     RealType *MappedPoint;
  454.     IPVertexStruct *V,
  455.     *VList = PPolygon -> PVertex;
  456.  
  457.     if (VList == NULL) return;
  458.  
  459.     if (DumpVertices && !IsConvexPolygon(PPolygon)) {
  460.     static int Printed = FALSE;
  461.  
  462.     if (!Printed) {
  463.         fprintf(stderr,
  464.             "Non convex polygon(s) may be in data (see CONVEX in IRIT).\n");
  465.         Printed = TRUE;
  466.     }
  467.     }
  468.  
  469.     switch (PPolygon -> Type) {
  470.     case IP_POLYGON:
  471.         if (DumpVertices) {
  472.             for (V = VList; V != NULL; V = V -> Pnext) {
  473.             MappedPoint = MapPoint(V -> Coord);
  474.             fprintf(f, "%4d %4d %4d\n",
  475.                 (int) (MappedPoint[0] * GLOBAL_SCALE),
  476.                 (int) (MappedPoint[1] * GLOBAL_SCALE),
  477.                     (int) (MappedPoint[2] * GLOBAL_SCALE));
  478.             (*IncVertices)++;
  479.         }
  480.         }
  481.         else {
  482.         for (CountVertices = 0, V = VList; V != NULL; V = V -> Pnext)
  483.             CountVertices++;
  484.         fprintf(f, "0x%02xff %d", Color | 0x0010, CountVertices);
  485.             while (CountVertices-- > 0)
  486.             fprintf(f, " %d", (*IncVertices)++);
  487.         fprintf(f, "\n");
  488.         }
  489.         break;
  490.     }
  491. }
  492.  
  493. /*****************************************************************************
  494. *   Routine to test if the given polygon is convex or not.             *
  495. * Algorithm: The polygon is convex iff the normals generated from cross      *
  496. * products of two consecutive edges points to the same direction. The same   *
  497. * direction is tested by a positive dot product.                 *
  498. *****************************************************************************/
  499. static int IsConvexPolygon(IPPolygonStruct *Pl)
  500. {
  501.     RealType Size, V1[3], V2[3], LastNormal[3], Normal[3];
  502.     IPVertexStruct *VNext, *VNextNext,
  503.     *V = Pl -> PVertex;
  504.  
  505.     LastNormal[0] = LastNormal[1] = LastNormal[2] = 0.0;
  506.  
  507.     do {
  508.     if ((VNext = V -> Pnext) == NULL)
  509.         VNext = Pl -> PVertex;
  510.     if ((VNextNext = VNext -> Pnext) == NULL)
  511.         VNextNext = Pl -> PVertex;
  512.  
  513.     PT_SUB(V1, VNext -> Coord, V -> Coord);
  514.     if ((Size = PT_LENGTH(V1)) > EPSILON) {
  515.         Size = 1.0 / Size;
  516.         PT_SCALE(V1, Size);
  517.     }
  518.     PT_SUB(V2, VNextNext -> Coord, VNext -> Coord);
  519.     if ((Size = PT_LENGTH(V2)) > EPSILON) {
  520.         Size = 1.0 / Size;
  521.         PT_SCALE(V2, Size);
  522.     }
  523.     CROSS_PROD(Normal, V1, V2);
  524.  
  525.     if (V != Pl -> PVertex) {
  526.         if (PT_LENGTH(Normal) > CONVEX_EPSILON &&
  527.         DOT_PROD(Normal, LastNormal) < -CONVEX_EPSILON)
  528.         return FALSE;
  529.     }
  530.  
  531.     PT_COPY(LastNormal, Normal);
  532.  
  533.     V = VNext;
  534.     }
  535.     while (V != Pl -> PVertex && V != NULL);
  536.  
  537.     return TRUE;
  538. }
  539.  
  540. /*****************************************************************************
  541. * Maps the given E3 point using the CrntViewMat.                 *
  542. *****************************************************************************/
  543. static RealType *MapPoint(RealType *Pt)
  544. {
  545.     static RealType MappedPt[3];
  546.  
  547.     MultVecby4by4(MappedPt, Pt, CrntViewMat);
  548.  
  549.     return MappedPt;
  550. }
  551.  
  552. /*****************************************************************************
  553. * Trap Cagd_lib errors right here.                         *
  554. *****************************************************************************/
  555. void CagdFatalError(CagdFatalErrorType ErrID)
  556. {
  557.     char
  558.     *ErrorMsg = CagdDescribeError(ErrID);
  559.  
  560.     fprintf(stderr, "CAGD_LIB: %s", ErrorMsg);
  561.  
  562.     exit(-1);
  563. }
  564.  
  565. /*****************************************************************************
  566. * MyExit routine. Note it might call to CloseGraph without calling         *
  567. * InitGraph(), or call MouseClose() without MouseInit() etc. and it is the   *
  568. * responsibility of the individual modules to do nothing in these cases.     *
  569. *****************************************************************************/
  570. static void MyExit(int ExitCode)
  571. {
  572. #ifdef __MSDOS__
  573.     fprintf(stderr,
  574.         "\nIrit2Plg: Core left %ldk.\n", coreleft() / 1024);
  575. #endif /* __MSDOS__ */
  576.  
  577.     exit(ExitCode);
  578. }
  579.  
  580.