home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Program to draw 3D object as solid objects in GIF image file format. *
- * *
- * Options: *
- * 1. -a ambient : Ratio of the ambient color. *
- * 2. -c n : Number of bit ber pixel (2^n is number of colors possible). *
- * 3. -l x y z : Light source direction vector. *
- * 4. -2 : Force 2 light sources at opposite direction of light vectors. *
- * 5. -m : More flag, to print more imformation on input/errors. *
- * 6. -s x y : Specify new dimensions to generate the resulting image. *
- * 7. -S SubSample : specifies dimension of pixel sub sampling (1..4). *
- * 8. -g : Use gouraud shading. *
- * 9. -b : Delete Back facing polygons. *
- * 10. -M Mask : Create boolean Mask (coverage) image as well. *
- * 11. -z : Print current version, and some helpfull data. *
- * 12. -f FineNess : log based 2 of the surface to polygons subdiv, fineness. *
- * *
- * Note some of those options may be permanently set to a different default *
- * using the configuration file "Poly3D-R.cfg" *
- * *
- * Usage: poly3d-r [-a Ambient] [-c N] [-l X Y Z] [-2] [-m] [-s Xsize Ysize] *
- * [-S SubSample] [-g] [-b] [-M Mask] [-z] [-f FineNess] DFiles *
- * *
- * Written by: Gershon Elber Ver 3.0, Aug 1990 *
- *****************************************************************************/
-
- #ifdef __MSDOS__
- #include <stdlib.h>
- #include <string.h>
- #include <conio.h>
- #include <io.h>
- #include <dos.h>
- #include <alloc.h>
- #endif /* __MSDOS__ */
- #include <stdio.h>
- #include <math.h>
- #include <time.h>
- #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-R Version 3.0, Gershon Elber,\n\
- (C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
- #else
- static char *VersionStr = "Poly3D-R " VERSION ", Gershon Elber, "
- __DATE__ ", " __TIME__ "\n"
- "(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
- #endif /* NO_CONCAT_STR */
-
- static char *CtrlStr =
- #ifdef __MSDOS__
- "poly3d-r a%-Ambient!f c%-N!d l%-X|Y|Z!f!f!f 2%- m%- s%-Xsize|Ysize!d!d S%-SubSample!d g%- b%- M%-Mask!s z%- f%-FineNess!d DFiles!*s";
- #else
- "poly3d-r a%-Ambient!F c%-N!d l%-X|Y|Z!F!F!F 2%- m%- s%-Xsize|Ysize!d!d S%-SubSample!d g%- b%- M%-Mask!s z%- f%-FineNess!d DFiles!*s";
- #endif /* __MSDOS__ */
-
- static long SaveTotalTime;
- static GifColorType MaskColorMap[2] = { /* Boolean mask GIF file color map. */
- { 0, 0, 0 },
- { 255, 255, 255 }
- };
- /* Fineness surface subdivision control. */
- static int GlblFineNess = DEFAULT_FINENESS;
-
- int GlblNumOfPolys = 0; /* Total number of polygons scan converted. */
- int GlblNumOfVerts = 0; /* Total number of vertices. */
- MatrixType GlblViewMat; /* Current view of object. */
-
- /* Amount scene was scaled up from normalized [-1..1] size on both X & Y: */
- RealType GlblScaleUpFctr = 0.0;
-
- /* The following are setable variables (via configuration file poly3d-h.cfg).*/
- int GlblMore = FALSE;
-
- ShadeInfoStruct GlblShadeInfo = {
- 1, /* Sub samples per pixel. */
- DEFAULT_BITS_PER_PIXEL,
- 0,
- DEFAULT_COLOR,
- DEFAULT_BACK_GROUND_COLOR,
- FALSE, /* No two light sources. */
- DEFAULT_SCREEN_XSIZE,
- DEFAULT_SCREEN_YSIZE,
- FALSE, /* No Gouraud shading. */
- FALSE, /* No back facing deletion. */
- NULL,
- NULL, /* No color map yet. */
- DEFAULT_LIGHT_SOURCE,
- DEFAULT_AMBIENT,
- DEFAULT_NORMAL_AVG_DEGREE
- };
-
- static ConfigStruct SetUp[] = {
- { "Ambient", (VoidPtr) &GlblShadeInfo.Ambient, SU_REAL_TYPE },
- { "LightSrcX", (VoidPtr) &GlblShadeInfo.LightSource[0],SU_REAL_TYPE },
- { "LightSrcY", (VoidPtr) &GlblShadeInfo.LightSource[1],SU_REAL_TYPE },
- { "LightSrcZ", (VoidPtr) &GlblShadeInfo.LightSource[2],SU_REAL_TYPE },
- { "AvgDegree", (VoidPtr) &GlblShadeInfo.NrmlAvgDegree, SU_REAL_TYPE },
- { "TwoSources", (VoidPtr) &GlblShadeInfo.TwoSources, SU_BOOLEAN_TYPE },
- { "Gouraud", (VoidPtr) &GlblShadeInfo.Gouraud, SU_BOOLEAN_TYPE },
- { "backFacing", (VoidPtr) &GlblShadeInfo.BackFacing, SU_BOOLEAN_TYPE },
- { "SubSample", (VoidPtr) &GlblShadeInfo.SubSamplePixel,SU_INTEGER_TYPE },
- { "BitsPerPixel", (VoidPtr) &GlblShadeInfo.BitsPerPixel, SU_INTEGER_TYPE },
- { "Color", (VoidPtr) &GlblShadeInfo.DefaultColor, SU_INTEGER_TYPE },
- { "BackGroundColor", (VoidPtr) &GlblShadeInfo.BackGroundColor,SU_INTEGER_TYPE },
- { "Xsize", (VoidPtr) &GlblShadeInfo.ScrnXSize, SU_INTEGER_TYPE },
- { "Ysize", (VoidPtr) &GlblShadeInfo.ScrnYSize, SU_INTEGER_TYPE },
- { "FineNess", (VoidPtr) &GlblFineNess, SU_INTEGER_TYPE },
- { "More", (VoidPtr) &GlblMore, SU_BOOLEAN_TYPE }
- };
- #define NUM_SET_UP (sizeof(SetUp) / sizeof(ConfigStruct))
-
- /* All polygons to be scan convert will be inserted into this hash table */
- /* during the preprocessing (PrepareXXXX functions). */
- IPPolygonStruct **PolyHashTable;
-
-
- static IPObjectStruct *MainGetDataFiles(char **DataFileNames, int NumOfDataFiles);
- static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf);
-
- /*****************************************************************************
- * 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 AmbientFlag = FALSE,
- ColorFlag = FALSE,
- LightSrcFlag = FALSE,
- GifMaskFlag = FALSE,
- VerFlag = FALSE,
- NumFiles = 0,
- ImageSizeFlag = FALSE,
- SubSampleFlag = FALSE,
- FineNessFlag = FALSE,
- Error;
- char *GifMaskName,
- **FileNames = NULL;
- RealType Size, Scale;
- MatrixType Mat;
- IPObjectStruct *PObjects;
- GifFileType *GifFile,
- *GifMask = NULL;
-
- SaveTotalTime = time(NULL); /* Save starting time. */
- #ifdef __MSDOS__
- ctrlbrk((int cdecl (*)()) MyExit); /* Kill this program if ^C... */
- #endif /* __MSDOS__ */
-
- Config("poly3d-r", SetUp, NUM_SET_UP); /* Read config. file if exists. */
-
- if ((Error = GAGetArgs (argc, argv, CtrlStr,
- &AmbientFlag, &GlblShadeInfo.Ambient,
- &ColorFlag, &GlblShadeInfo.BitsPerPixel, &LightSrcFlag,
- &GlblShadeInfo.LightSource[0],
- &GlblShadeInfo.LightSource[1],
- &GlblShadeInfo.LightSource[2],
- &GlblShadeInfo.TwoSources, &GlblMore, &ImageSizeFlag,
- &GlblShadeInfo.ScrnXSize, &GlblShadeInfo.ScrnYSize,
- &SubSampleFlag, &GlblShadeInfo.SubSamplePixel,
- &GlblShadeInfo.Gouraud, &GlblShadeInfo.BackFacing,
- &GifMaskFlag, &GifMaskName,
- &VerFlag, &FineNessFlag, &GlblFineNess,
- &NumFiles, &FileNames)) != 0) {
- GAPrintErrMsg(Error);
- GAPrintHowTo(CtrlStr);
- MyExit(1);
- }
-
- if (GlblShadeInfo.Ambient < 0.0 || GlblShadeInfo.Ambient > 1.0) {
- fprintf(stderr,
- "Ambient light specified not in [0.0..1.0] range, %lf selected instead.\n",
- DEFAULT_AMBIENT);
- GlblShadeInfo.Ambient = DEFAULT_AMBIENT;
- }
- if (GlblShadeInfo.BitsPerPixel < 1 || GlblShadeInfo.BitsPerPixel > 8) {
- fprintf(stderr,
- "PitsPerPixel not in [1..8] range, %d selected instead.\n",
- DEFAULT_BITS_PER_PIXEL);
- GlblShadeInfo.BitsPerPixel = DEFAULT_BITS_PER_PIXEL;
- }
-
- Size = sqrt(SQR(GlblShadeInfo.LightSource[0]) +
- SQR(GlblShadeInfo.LightSource[1]) +
- SQR(GlblShadeInfo.LightSource[2]));
- if (ABS(Size) < EPSILON) {
- fprintf(stderr, "Light source vector is zero, Z axis selected instead.\n");
- GlblShadeInfo.LightSource[0] =
- GlblShadeInfo.LightSource[1] = 0.0;
- GlblShadeInfo.LightSource[2] = 1.0;
- }
- else {
- GlblShadeInfo.LightSource[0] /= Size;
- GlblShadeInfo.LightSource[1] /= Size;
- GlblShadeInfo.LightSource[2] /= Size;
- }
-
- 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);
- }
-
- if (SubSampleFlag) {
- if (GlblShadeInfo.SubSamplePixel < 1 || GlblShadeInfo.SubSamplePixel > 4) {
- fprintf(stderr, "Sub sampling can be 1 to 4 only (1x1 to 4x4).\n");
- GAPrintHowTo(CtrlStr);
- MyExit(1);
- }
- }
-
- /* Get the data files: */
- IritPrsrPolyListCirc = FALSE;
- PObjects = MainGetDataFiles(FileNames, NumFiles);
-
- /* Compute the viewing matrices and related data: */
- if (IritPrsrWasPrspMat)
- MultTwo4by4(GlblViewMat, IritPrsrViewMat, IritPrsrPrspMat);
- else
- GEN_COPY(GlblViewMat, IritPrsrViewMat, sizeof(MatrixType));
-
- /* Now its time to scale the normalized image (+/-1 on both X & Y) to */
- /* size specified by the image dimensions. We scale up to the SMALLER */
- /* dimension, and put the center at the image center. */
- /* Also, as the GIF image starts at the top, we must flip the image */
- /* along Y axis. */
- GlblScaleUpFctr = Scale = MIN(GlblShadeInfo.ScrnXSize *
- GlblShadeInfo.SubSamplePixel,
- GlblShadeInfo.ScrnYSize *
- GlblShadeInfo.SubSamplePixel) / 2.0;
- GenMatScale(Scale, -Scale, Scale, Mat);
- MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
- GenMatTrans(GlblShadeInfo.ScrnXSize * GlblShadeInfo.SubSamplePixel / 2.0,
- GlblShadeInfo.ScrnYSize * GlblShadeInfo.SubSamplePixel / 2.0,
- 0.0, Mat);
- MultTwo4by4(GlblViewMat, GlblViewMat, Mat);
-
- /* Prepare data structures of objects themselves: */
- PrepareViewData(PObjects);
-
- /* Into shadingInfo global structure: */
- PrepareColorTable(PObjects);
-
- EvalVrtxColors(PObjects);
-
- #ifndef DEBUG_NO_GIF
-
- /* Open stdout for the GIF image file: */
- if ((GifFile = EGifOpenFileHandle(1)) == NULL ||
- EGifPutScreenDesc(GifFile,
- GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
- GlblShadeInfo.BitsPerPixel, 0,
- GlblShadeInfo.BitsPerPixel, GlblShadeInfo.PColorMap) ==
- GIF_ERROR ||
- EGifPutImageDesc(GifFile,
- 0, 0, GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize, FALSE,
- GlblShadeInfo.BitsPerPixel, NULL) == GIF_ERROR)
- QuitGifError();
- /* Open special mask file if required: */
- if (GifMaskFlag &&
- ((GifMask = EGifOpenFileName(GifMaskName, FALSE)) == NULL ||
- EGifPutScreenDesc(GifMask,
- GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
- 1, 0, 1, MaskColorMap) == GIF_ERROR ||
- EGifPutImageDesc(GifMask, 0, 0,
- GlblShadeInfo.ScrnXSize, GlblShadeInfo.ScrnYSize,
- FALSE, 1, NULL) == GIF_ERROR))
- QuitGifError();
-
- #endif /* DEBUG_NO_GIF */
-
- ScanConvertData(GifFile, GifMask); /* Do the real interesting stuff... */
-
- #ifndef DEBUG_NO_GIF
-
- EGifCloseFile(GifFile);
- if (GifMask) EGifCloseFile(GifMask);
-
- #endif /* DEBUG_NO_GIF */
-
- 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 *Crvs;
- CagdSrfStruct *Srf, *Srfs;
- IPObjectStruct *PObj, *PObjNext;
- 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) {
- /* Curves are not rendered at this time and they are ignored. */
- for (PObj = CrvObjs; PObj != NULL;) {
- Crvs = PObj -> U.PCrvs;
- CagdCrvFreeList(Crvs);
- PObjNext = PObj -> Pnext;
- free(PObj);
- PObj = PObjNext;
- }
- CrvObjs = NULL;
- }
-
- 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);
- }
- }
-
- return SrfObjs;
- }
-
- /*****************************************************************************
- * Routine to convert a single surface into a polygons with GlblFineNess *
- * samples as the subdivision 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, TRUE, TRUE);
-
- for (CagdPolygon = CagdPolygonHead;
- CagdPolygon != NULL;
- CagdPolygon = CagdPolygon -> Pnext) {
- /* All polygons are triangles! */
-
- for (i = 0, VHead = NULL; i < 3; i++) { /* Convert to vertices. */
- if (VHead == NULL)
- VHead = V = IritPrsrNewVertexStruct();
- else {
- V -> Pnext = IritPrsrNewVertexStruct();
- V = V -> Pnext;
- }
- IP_SET_VRTX_NORMAL(V); /* Vertex has normal. */
-
- for (j = 0; j < 3; j++) /* Convert to our format. */
- V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
- for (j = 0; j < 3; j++)
- V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
-
- }
-
- 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-R: Total RealTime %ld seconds, Core left %ldk.\n",
- time(NULL) - SaveTotalTime, coreleft() / 1024);
- #else
- fprintf(stderr,
- "\nPoly3D-R: Total RealTime %ld seconds.\n",
- time(NULL) - SaveTotalTime);
- #endif /* __MSDOS__ */
-
- exit(ExitCode);
- }
-
- /******************************************************************************
- * Close output file (if open), and exit. *
- ******************************************************************************/
- void QuitGifError(void)
- {
- PrintGifError();
- MyExit('G');
- }
-