/***************************************************************************** * Program to draw 3D object as wireframe after removing the hidden lines. * * This porgram works in object space, and if redirect stdout to a file, dump * * the visible polylines into it instead of drawing them on current device. * * This may be used to display the results on any device (a plotter !?) later.* * * * Options: * * 1. -b : Delete back facing polygons. * * 2. -e #Edges : If the edges are order is specific way (like in DrawFn3D) * * and only the k first edges of each polygons are to be displayed * * use this option as -e k. * * 3. -i : Internal edges. IRIT solid modeller may generate edges, which one * * may not want to see (default). -i will draw all of them. * * 4. -m : More flag, to print more imformation on input/errors. * * 5. -f FineNess : log based 2 of the fineness control of surfaces subdiv. * * 6. -4 : Four per flat bilinear, otherwise two. * * 7. -z : Print current version, and some helpfull data. * * * * Note some of those options may be permanently set to a different default * * using the configuration file "Poly3D-H.cfg" * * * * Usage: Poly3D-H [-b] [-i] [-m] [-e #Edges] [-f FineNess] [-4] [-z] DFiles. * * * * Written by: Gershon Elber Ver 3.0, Aug. 1990 * *****************************************************************************/ #ifdef __MSDOS__ #include #include #include #include #include #include #endif /* __MSDOS__ */ #include #include #include #include "program.h" #include "getarg.h" #include "genmat.h" #include "iritprsr.h" #include "config.h" #ifdef __TURBOC__ /* Malloc debug routine - only on TC++ 1.0 and above. */ #define __DEBUG_MALLOC__ #endif /* __TURBOC__ */ #ifdef __MSDOS__ /* This huge stack is mainly from second phase - the segment intersections */ /* which may cause recursive calls - a lot... */ extern unsigned int _stklen = 32766; #endif /* __MSDOS__ */ #ifdef NO_CONCAT_STR static char *VersionStr = "Poly3D-H Version 3.0, Gershon Elber,\n\ (C) Copyright 1989/90/91 Gershon Elber, Non commercial use only."; #else static char *VersionStr = "Poly3D-H " VERSION ", Gershon Elber, " __DATE__ ", " __TIME__ "\n" "(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only."; #endif /* NO_CONCAT_STR */ static char *CtrlStr = "poly3d-h b%- m%- i%- e%-#Edges!d f%-FineNess!d 4%- z%- DFiles!*s"; static long SaveTotalTime; static int GlblFourPerFlat = FALSE; int NumOfPolygons = 0; /* Total number of polygons to handle. */ MatrixType GlblViewMat; /* Current view of object. */ /* Data structures used by the hidden line modules: */ int EdgeCount = 0; EdgeStruct *EdgeHashTable[EDGE_HASH_TABLE_SIZE]; IPPolygonStruct *PolyHashTable[POLY_HASH_TABLE_SIZE]; /* The following are setable variables (via configuration file poly3d-h.cfg).*/ int GlblMore = FALSE, GlblNumEdge = 0, GlblBackFacing = FALSE, GlblInternal = FALSE, GlblFineNess = DEFAULT_FINENESS; static ConfigStruct SetUp[] = { { "Internal", (VoidPtr) &GlblInternal, SU_BOOLEAN_TYPE }, { "BackFacing", (VoidPtr) &GlblBackFacing, SU_BOOLEAN_TYPE }, { "More", (VoidPtr) &GlblMore, SU_BOOLEAN_TYPE }, { "FourPerFlat", (VoidPtr) &GlblFourPerFlat, SU_BOOLEAN_TYPE }, { "FineNess", (VoidPtr) &GlblFineNess, SU_INTEGER_TYPE }, { "NumOfEdges", (VoidPtr) &GlblNumEdge, SU_INTEGER_TYPE } }; #define NUM_SET_UP (sizeof(SetUp) / sizeof(ConfigStruct)) static IPPolygonStruct *Curve2Polylines(CagdCrvStruct *Crv); static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf); static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles); /***************************************************************************** * Main routine - Read Parameter line and do what you need... * *****************************************************************************/ void #ifdef __MSDOS__ cdecl /* So we can use -rp in Borland 3.0 (parameters in registers.). */ #endif /* __MSDOS__ */ main(int argc, char **argv) { int EdgesFlag = FALSE, VerFlag = FALSE, NumFiles = FALSE, FineNessFlag = FALSE, Error; char **FileNames = NULL; IPObjectStruct *PObjects; SaveTotalTime = time(NULL); /* Save starting time. */ #ifdef __MSDOS__ ctrlbrk((int cdecl (*)()) MyExit); /* Kill this program if ^C... */ #endif /* __MSDOS_ */ Config("poly3d-h", SetUp, NUM_SET_UP); /* Read config. file if exists. */ if ((Error = GAGetArgs (argc, argv, CtrlStr, &GlblBackFacing, &GlblMore, &GlblInternal, &EdgesFlag, &GlblNumEdge, &FineNessFlag, &GlblFineNess, &GlblFourPerFlat, &VerFlag, &NumFiles, &FileNames)) != 0) { GAPrintErrMsg(Error); GAPrintHowTo(CtrlStr); MyExit(1); } if (VerFlag) { fprintf(stderr, "\n%s\n\n", VersionStr); GAPrintHowTo(CtrlStr); ConfigPrint(SetUp, NUM_SET_UP); MyExit(0); } if (!NumFiles) { fprintf(stderr, "No data file names were given, exit\n"); GAPrintHowTo(CtrlStr); MyExit(1); } /* Get the data files: */ IritPrsrPolyListCirc = FALSE; PObjects = MainGetDataFiles(FileNames, NumFiles); /* And update the global viewing matrix: */ if (IritPrsrWasPrspMat) MultTwo4by4(GlblViewMat, IritPrsrViewMat, IritPrsrPrspMat); else GEN_COPY(GlblViewMat, IritPrsrViewMat, sizeof(MatrixType)); /* Prepare data structures to be able to decide on visibility: */ PrepareViewData(PObjects); OutVisibleEdges(); /* Scan all sub-edges output visible. */ MyExit(0); } /***************************************************************************** * Main routine to read the data description files: * * Returns pointer to pointers on FileDescription structures (one per file). * *****************************************************************************/ static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles) { int i; char *ErrorMsg; FILE *f; long SaveTime = time(NULL); IPObjectStruct *PObj, *PObjTail, *PObjHead = NULL; fprintf(stderr, "Reading data file(s).\n"); for (i = 0; i < NumOfDataFiles; i++) { if (GlblMore) fprintf(stderr, "Reading %s.\n", *DataFileNames); #ifdef __MSDOS__ if ((f = fopen(*DataFileNames, "rt")) == NULL) { /* Open the file. */ #else if ((f = fopen(*DataFileNames, "r")) == NULL) { /* Open the file. */ #endif /* __MSDOS__ */ fprintf(stderr, "Can't open data file %s.\n", *DataFileNames); MyExit(1); } if ((PObj = IritPrsrGetObjects(f)) != NULL) { /* Get the data file. */ PObjTail = PObj; while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext; PObjTail -> Pnext = PObjHead; PObjHead = PObj; } if (GlblMore && IritPrsrParseError(&ErrorMsg)) fprintf(stderr, "File %s, %s\n", *DataFileNames, ErrorMsg); fclose(f); /* Close the file. */ DataFileNames++; /* Skip to next file name. */ } if (PObjHead == NULL) { fprintf(stderr, "No data found.\n"); MyExit(1); } fprintf(stderr, "Done reading, %ld seconds.", time(NULL) - SaveTime); return PObjHead; } /***************************************************************************** * Routine to convert all surfaces/curves into polylines as follows: * * Curves are converted to single polyline with SamplesPerCurve samples. * * Surface are converted into GlblNumOfIsolines curves in each axes, each * * handled as Curves above. The curves and surfaces are then deleted. * *****************************************************************************/ IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs, IPObjectStruct *SrfObjs) { CagdCrvStruct *Crv, *Crvs; CagdSrfStruct *Srf, *Srfs; IPObjectStruct *PObj; IPPolygonStruct *PPolygon, *PPolygonTemp; if (CrvObjs == NULL && SrfObjs == NULL) return NULL; /* Make sure requested format is something reasonable. */ if (GlblFineNess < 2) { GlblFineNess = 2; if (GlblMore) fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n"); } if (CrvObjs) { for (PObj = CrvObjs; PObj != NULL; PObj = PObj -> Pnext) { Crvs = PObj -> U.PCrvs; PObj -> U.PPolygon = NULL; for (Crv = Crvs; Crv != NULL; Crv = Crv -> Pnext) { PPolygon = PPolygonTemp = Curve2Polylines(Crv); while (PPolygonTemp -> Pnext) PPolygonTemp = PPolygonTemp -> Pnext; PPolygonTemp -> Pnext = PObj -> U.PPolygon; PObj -> U.PPolygon = PPolygon; } CagdCrvFreeList(Crvs); } } if (SrfObjs) { for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) { Srfs = PObj -> U.PSrfs; PObj -> U.PPolygon = NULL; for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) { PPolygon = PPolygonTemp = Surface2Polygons(Srf); while (PPolygonTemp -> Pnext) PPolygonTemp = PPolygonTemp -> Pnext; PPolygonTemp -> Pnext = PObj -> U.PPolygon; PObj -> U.PPolygon = PPolygon; } CagdSrfFreeList(Srfs); } } if (SrfObjs == NULL) return CrvObjs; else if (CrvObjs == NULL) return SrfObjs; else { for (PObj = SrfObjs; PObj -> Pnext != NULL; PObj = PObj -> Pnext); PObj -> Pnext = CrvObjs; return SrfObjs; } } /***************************************************************************** * Routine to convert a single curve into a polyline with SamplesPerCurve * * samples, into a polyline object. * *****************************************************************************/ static IPPolygonStruct *Curve2Polylines(CagdCrvStruct *Crv) { int i, j; IPVertexStruct *V, *VHead = NULL; IPPolygonStruct *P; CagdPolylineStruct *CagdPoly = CagdCrv2Polyline(Crv, GlblFineNess); for (i = 0; i < CagdPoly -> Length; i++) { if (VHead == NULL) VHead = V = IritPrsrNewVertexStruct(); else { V -> Pnext = IritPrsrNewVertexStruct(); V = V -> Pnext; } for (j = 0; j < 3; j++) /* Convert to our format. */ V -> Coord[j] = CagdPoly -> Polyline[i].Pt[j]; } V -> Pnext = NULL; P = IritPrsrNewPolygonStruct(); P -> PVertex = VHead; P -> Type = IP_POLYLINE; CagdPolylineFree(CagdPoly); return P; } /***************************************************************************** * Routine to convert a single surface into a polygons with 2^GlblFineNess * * as fineness measure. * *****************************************************************************/ static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf) { int i, j; IPVertexStruct *V, *VHead; IPPolygonStruct *P, *PHead = NULL; CagdPolygonStruct *CagdPolygon, *CagdPolygonHead = NULL; CagdPolygonHead = CagdSrf2Polygons(Srf, 1 << GlblFineNess, FALSE, GlblFourPerFlat); for (CagdPolygon = CagdPolygonHead; CagdPolygon != NULL; CagdPolygon = CagdPolygon -> Pnext) { /* All polygons are triangles! */ VHead = NULL; for (i = 0; i < 3; i++) { /* Convert to vertices. */ if (VHead == NULL) VHead = V = IritPrsrNewVertexStruct(); else { V -> Pnext = IritPrsrNewVertexStruct(); V = V -> Pnext; } for (j = 0; j < 3; j++) /* Convert to our format. */ V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j]; } V -> Pnext = NULL; P = IritPrsrNewPolygonStruct(); P -> PVertex = VHead; P -> Type = IP_POLYGON; P -> Pnext = PHead; PHead = P; } CagdPolygonFreeList(CagdPolygonHead); return PHead; } #ifdef __DEBUG_MALLOC__ /***************************************************************************** * My Routine to allocate dynamic memory. All program requests must call this * * routine (no direct call to malloc). Dies if no memory. * *****************************************************************************/ static void AllocError(const char *Msg, VoidPtr *p) { fprintf(stderr, "%s, Ptr = %p\n", Msg, p); MyExit(3); } #endif /* __DEBUG_MALLOC__ */ /***************************************************************************** * My Routine to allocate dynamic memory. All program requests must call this * * routine (no direct call to malloc). Dies if no memory. * *****************************************************************************/ VoidPtr MyMalloc(unsigned size) { VoidPtr p; if ((p = malloc(size)) != NULL) return p; fprintf(stderr, "Not enough memory, exit.\n"); MyExit(2); return NULL; /* Make warnings silent. */ } /***************************************************************************** * My Routine to free dynamic memory. All program requests must call this * * routine (no direct call to free). * *****************************************************************************/ void MyFree(VoidPtr p) { #ifdef __DEBUG_MALLOC__ switch (heapchecknode(p)) { case _HEAPCORRUPT: AllocError("Heap is corrupted", p); break; case _BADNODE: AllocError("Attempt to free a bogus pointer", p); break; case _FREEENTRY: AllocError("Attempt to free an already freed pointer", p); break; case _USEDENTRY: break; default: AllocError("Allocation error", p); break; } #endif /* __DEBUG_MALLOC__ */ free(p); } /***************************************************************************** * Trap Cagd_lib errors right here. * *****************************************************************************/ void CagdFatalError(CagdFatalErrorType ErrID) { char *ErrorMsg = CagdDescribeError(ErrID); fprintf(stderr, "CAGD_LIB: %s", ErrorMsg); exit(-1); } /***************************************************************************** * MyExit routine. Note it might call to CloseGraph without calling * * InitGraph(), or call MouseClose() without MouseInit(), or call * * RestoreCtrlBrk() without SetUpCtrlBrk() and it is the responsibility * * of the individual modules to do nothing in these cases. * *****************************************************************************/ void MyExit(int ExitCode) { #ifdef __MSDOS__ fprintf(stderr, "\nPoly3D-H: Total RealTime %ld seconds, Core left %ldk.\n", time(NULL) - SaveTotalTime, coreleft() / 1024); #else fprintf(stderr, "\nPoly3D-H: Total RealTime %ld seconds.\n", time(NULL) - SaveTotalTime); #endif /* __MSDOS__ */ exit(ExitCode); }