/***************************************************************************** * "Irit" - the 3d polygonal solid modeller. * * * * Written by: Gershon Elber Ver 0.2, Mar. 1990 * ****************************************************************************** * Module to handle the objects list - fetch, insert, delete etc... * *****************************************************************************/ /* #define DEBUG Output goes to stdout if defined. */ #include #include #include #include "program.h" #include "allocate.h" #include "dataprsr.h" #include "attribut.h" #include "geomat3d.h" #include "graphgen.h" #include "objects.h" #include "windows.h" static int GetDumpLevel(void); static PolygonStruct *GenAxesObjectPolylines(void); static void PrintOneLine(char *Line); /***************************************************************************** * Routine to set up all the predefined objects - objects that the system * * must have all the time, like global transformation matrix. * *****************************************************************************/ void SetUpPredefObjects(void) { RealType R; MatrixType Mat1, Mat2; ObjectStruct *PObj; /* 90 - 35.2644 = 54.7356 */ MatGenMatRotX1(DEG2RAD(-54.7356), Mat1); /* Generate default view trans. */ MatGenMatRotZ1(M_PI+M_PI/4, Mat2); /* which is isometric view. */ MatMultTwo4by4(Mat2, Mat2, Mat1); PObj = GenMatObject("VIEW_MAT", Mat2, NULL); InsertObject(PObj); MatGenUnitMat(Mat1); /* Generate default perspective trans. */ Mat1[2][2] = 0.1; Mat1[2][3] = -0.35; Mat1[3][2] = 0.35; PObj = GenMatObject("PRSP_MAT", Mat1, NULL); InsertObject(PObj); R = DEFAULT_RESOLUTION; PObj = GenNumObject("RESOLUTION", &R, NULL); InsertObject(PObj); R = DEFAULT_DRAW_CTLPT; PObj = GenNumObject("DRAWCTLPT", &R, NULL); InsertObject(PObj); R = DEFAULT_INTERNAL; PObj = GenNumObject("INTERNAL", &R, NULL); InsertObject(PObj); R = DEFAULT_INTERCRV; PObj = GenNumObject("INTERCRV", &R, NULL); InsertObject(PObj); R = DEFAULT_ECHOSRC; PObj = GenNumObject("ECHOSRC", &R, NULL); InsertObject(PObj); R = DEFAULT_DUMPLVL; PObj = GenNumObject("DUMPLVL", &R, NULL); InsertObject(PObj); R = 0; PObj = GenNumObject("FLAT4PLY", &R, NULL); InsertObject(PObj); R = MACHINE_UNIX; #if defined(__MSDOS__) || defined(DJGCC) R = MACHINE_MSDOS; #endif #if defined(sgi) R = MACHINE_SGI; #endif #if defined(hpbsd) || defined(hpux) R = MACHINE_HP; #endif #if defined(sun) R = MACHINE_SUN; #endif #if defined(apollo) R = MACHINE_APOLLO; #endif PObj = GenNumObject("MACHINE", &R, NULL); InsertObject(PObj); PObj = GenPolyObject("AXES", GenAxesObjectPolylines(), NULL); SET_POLYLINE_OBJ(PObj); /* Mark it as polyline object. */ InsertObject(PObj); } /***************************************************************************** * Routine to get the value to EchoSrc variable. * *****************************************************************************/ static int GetDumpLevel(void) { int DumpLvl; ObjectStruct *PObj = GetObject("DUMPLVL"); if (PObj == NULL || !IS_NUM_OBJ(PObj)) { WndwInputWindowPutStr("No numeric object name DumpLvl is defined"); DumpLvl = DEFAULT_DUMPLVL; } else DumpLvl = (int) (PObj -> U.R); return DumpLvl; } /***************************************************************************** * Generate an axes system with length of 1 on each axis. * *****************************************************************************/ static PolygonStruct *GenAxesObjectPolylines(void) { PolygonStruct *Pl, *PlHead; VertexStruct *V; Pl = PlHead = AllocPolygon(0, 0, NULL, NULL); /* X axis. */ Pl -> V = V = AllocVertex(0, 0, NULL, NULL); V -> Pt[0] = 0.0; V -> Pt[1] = 0.0; V -> Pt[2] = 0.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 1.0; V -> Pt[1] = 0.0; V -> Pt[2] = 0.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 1.0; V -> Pt[1] = 0.1; V -> Pt[2] = 0.1; Pl -> Pnext = AllocPolygon(0, 0, NULL, NULL); Pl = Pl -> Pnext; Pl -> V = V = AllocVertex(0, 0, NULL, NULL); V -> Pt[0] = 1.0; V -> Pt[1] = 0.1; V -> Pt[2] = 0.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 1.0; V -> Pt[1] = 0.0; V -> Pt[2] = 0.1; Pl -> Pnext = AllocPolygon(0, 0, NULL, NULL); Pl = Pl -> Pnext;/* Y axis.*/ Pl -> V = V = AllocVertex(0, 0, NULL, NULL); V -> Pt[0] = 0.0; V -> Pt[1] = 0.0; V -> Pt[2] = 0.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.0; V -> Pt[1] = 1.0; V -> Pt[2] = 0.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.0; V -> Pt[1] = 1.0; V -> Pt[2] = 0.06; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.04; V -> Pt[1] = 1.0; V -> Pt[2] = 0.1; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.0; V -> Pt[1] = 1.0; V -> Pt[2] = 0.06; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] =(-0.04);V -> Pt[1] = 1.0; V -> Pt[2] = 0.1; Pl -> Pnext = AllocPolygon(0, 0, NULL, NULL); Pl = Pl -> Pnext;/* Z axis.*/ Pl -> V = V = AllocVertex(0, 0, NULL, NULL); V -> Pt[0] = 0.0; V -> Pt[1] = 0.0; V -> Pt[2] = 0.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.0; V -> Pt[1] = 0.0; V -> Pt[2] = 1.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.1; V -> Pt[1] = 0.0; V -> Pt[2] = 1.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.0; V -> Pt[1] = 0.1; V -> Pt[2] = 1.0; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pt[0] = 0.1; V -> Pt[1] = 0.1; V -> Pt[2] = 1.0; return PlHead; } /***************************************************************************** * Get the nth object in a list. Object reference is properly updated. * *****************************************************************************/ ObjectStruct *GetNthList(ObjectStruct *ListObj, RealType *Rn) { int i, n = REAL_PTR_TO_INT(Rn); ObjectStruct *PObj; if (!IS_OLST_OBJ(ListObj)) { WndwInputWindowPutStr("None list object ignored."); return NULL; } if (n < 1 || n >= MAX_OBJ_LIST) { WndwInputWindowPutStr("Out of range of list."); return NULL; } for (i = 0; i < n; i++) if (ListObj -> U.PObjList[i] == NULL) { WndwInputWindowPutStr("Out of range of list."); return NULL; } PObj = CopyObject(NULL, ListObj -> U.PObjList[n - 1], FALSE); return PObj; } /***************************************************************************** * Append two lists. Object reference is properly updated. * *****************************************************************************/ ObjectStruct *AppendLists(ObjectStruct *ListObj1, ObjectStruct *ListObj2) { int i, j; ObjectStruct *PObj; if (!IS_OLST_OBJ(ListObj1) && !IS_OLST_OBJ(ListObj2)) { WndwInputWindowPutStr("None list object ignored."); return NULL; } PObj = AllocObject("", OBJ_LIST_OBJ, NULL); for (i = 0; ListObj1 -> U.PObjList[i] != NULL && i < MAX_OBJ_LIST; i++) { PObj -> U.PObjList[i] = ListObj1 -> U.PObjList[i]; PObj -> U.PObjList[i] -> Count++; } for (j = 0; ListObj2 -> U.PObjList[j] != NULL && i < MAX_OBJ_LIST; i++, j++) { PObj -> U.PObjList[i] = ListObj2 -> U.PObjList[j]; PObj -> U.PObjList[i] -> Count++; } if (i < MAX_OBJ_LIST) PObj -> U.PObjList[i] = NULL; return PObj; } /***************************************************************************** * Snoc (Cons to the end of the list, in place) the object to the list in * * the second argument. * *****************************************************************************/ void SnocList(ObjectStruct *PObj, ObjectStruct *ListObj) { int i; if (!IS_OLST_OBJ(ListObj)) { WndwInputWindowPutStr("None list object ignored."); return; } for (i = 0; ListObj -> U.PObjList[i] != NULL && i < MAX_OBJ_LIST - 2; i++); if (i < MAX_OBJ_LIST - 2) { ListObj -> U.PObjList[i] = CopyObject(NULL, PObj, FALSE); ListObj -> U.PObjList[i] -> Count = 1; ListObj -> U.PObjList[i + 1] = NULL; } } /***************************************************************************** * Get object by its name - scans the object linear list. * * Note the termination is also on 1000 objects (simple debugging aid in case * * the Object list became circular), and a fatal error is produced. * *****************************************************************************/ ObjectStruct *GetObject(char *ObjName) { int i = 0; ObjectStruct *PObj = GlblObjList; while (PObj) { if (strcmp(PObj -> Name, ObjName) == 0) { return PObj; } PObj = PObj -> Pnext; if (i++ >= 1000) FatalError("GetObject: Global Object list too big (>1000)\n"); } return NULL; } /***************************************************************************** * Free Object - delete it from global active list and free all it memory * *****************************************************************************/ void FreeObject(ObjectStruct *PObj) { /* Force free the object. Since the reference count should be actually */ /* two (second for the parsing tree reference) we decrement it here. */ if (PObj->Count == 2) { PObj->Count = 1; DeleteObject(PObj, TRUE); } else { /* Reduce the reference count by two - one for the parsing tree */ /* this routine was called from and one for the fact this object */ /* reference count is to be deleted since this routine was called. */ DeleteObject(PObj, FALSE); PObj->Count -= 2; } } /***************************************************************************** * Delete object by its pointer - scans the object linear list. * * Note the deleted record is free only if Free = TRUE. * *****************************************************************************/ void DeleteObject(ObjectStruct *PObj, int Free) { ObjectStruct *PObjScan = GlblObjList; if (GlblObjList == NULL) return; if (PObj == GlblObjList) { /* If it is the first one - special case. */ GlblObjList = GlblObjList->Pnext; if (Free) MyFree((char *) PObj, ALLOC_OBJECT); return; } while (PObjScan->Pnext) { if (PObj == PObjScan->Pnext) { PObjScan->Pnext = PObjScan->Pnext->Pnext;/* Delete it from list. */ if (Free) MyFree((char *) PObj, ALLOC_OBJECT); /* And free it. */ return; } PObjScan = PObjScan->Pnext; } } /***************************************************************************** * Insert object by its pointer - as first in object linear list. * * Note it is assumed the object is not in the object list allready. * *****************************************************************************/ void InsertObject(ObjectStruct *PObj) { PObj -> Pnext = GlblObjList; GlblObjList = PObj; } /***************************************************************************** * Print one line. * *****************************************************************************/ static void PrintOneLine(char *Line) { WndwInputWindowPutStr(Line); } /***************************************************************************** * Print some usefull info on the given object. * *****************************************************************************/ void PrintObject(ObjectStruct *PObj) { int Count = PObj -> Count; CagdRType DumpLvl = GetDumpLevel(); char Line[LINE_LEN_LONG], *Name = (int) strlen(PObj -> Name) > 0 ? PObj -> Name : "NONE"; switch (PObj->ObjType) { case UNDEF_OBJ: sprintf(Line, "%-10s (%d) - Undefined type", Name, Count); PrintOneLine(Line); break; case POLY_OBJ: sprintf(Line, "%-10s (%d) - Poly type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 3) DataPrsrPutObject(NULL, PObj); break; case NUMERIC_OBJ: sprintf(Line, "%-10s (%d) - Numeric type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 1) DataPrsrPutObject(NULL, PObj); break; case VECTOR_OBJ: sprintf(Line, "%-10s (%d) - Vector type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 1) DataPrsrPutObject(NULL, PObj); break; case CTLPT_OBJ: sprintf(Line, "%-10s (%d) - CtlPt type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 1) DataPrsrPutObject(NULL, PObj); break; case MATRIX_OBJ: sprintf(Line, "%-10s (%d) - Matrix type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 1) DataPrsrPutObject(NULL, PObj); break; case STRING_OBJ: sprintf(Line, "%-10s (%d) - String type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 1) DataPrsrPutObject(NULL, PObj); break; case OBJ_LIST_OBJ: sprintf(Line, "%-10s (%d) - Object List type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 4) DataPrsrPutObject(NULL, PObj); break; case CURVE_OBJ: sprintf(Line, "%-10s (%d) - Curve type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 2) { CagdSetCagdFprintf(PrintOneLine); DataPrsrPutObject(NULL, PObj); CagdSetCagdFprintf(NULL); } break; case SURFACE_OBJ: sprintf(Line, "%-10s (%d) - Surface type", Name, Count); PrintOneLine(Line); if (DumpLvl >= 2) { CagdSetCagdFprintf(PrintOneLine); DataPrsrPutObject(NULL, PObj); CagdSetCagdFprintf(NULL); } break; default: sprintf(Line, "%-10s (%d) - Obj type error, type = %d", Name, Count, PObj->ObjType); PrintOneLine(Line); break; } } /***************************************************************************** * Print some usefull info on all the given objects. * *****************************************************************************/ void PrintObjectList(ObjectStruct *PObj) { PrintOneLine(""); while (PObj != NULL) { PrintObject(PObj); PObj = PObj -> Pnext; } } /***************************************************************************** * Generate one polygonal object: * *****************************************************************************/ ObjectStruct *GenPolyObject(char *Name, PolygonStruct *Pl, ObjectStruct *Pnext) { ObjectStruct *PObj; PObj = AllocObject(Name, POLY_OBJ, Pnext); ResetObjectAttribs(PObj); /* Initialize attributes. */ RST_POLYLINE_OBJ(PObj); /* Default - not polyline object. */ PObj -> U.Pl.P = Pl; /* Link the union part of it... */ return PObj; } /***************************************************************************** * Generate one curve object: * *****************************************************************************/ ObjectStruct *GenCrvObject(char *Name, CagdCrvStruct *Crv, ObjectStruct *Pnext) { ObjectStruct *PObj; PObj = AllocObject(Name, CURVE_OBJ, Pnext); ResetObjectAttribs(PObj); /* Initialize attributes. */ PObj -> U.Crv.Crv = Crv; /* Link the union part of it... */ PObj -> U.Crv.PLPolys = NULL; PObj -> U.Crv.CtlPoly = NULL; return PObj; } /***************************************************************************** * Generate one surface object: * *****************************************************************************/ ObjectStruct *GenSrfObject(char *Name, CagdSrfStruct *Srf, ObjectStruct *Pnext) { ObjectStruct *PObj; PObj = AllocObject(Name, SURFACE_OBJ, Pnext); ResetObjectAttribs(PObj); /* Initialize attributes. */ PObj -> U.Srf.Srf = Srf; /* Link the union part of it... */ PObj -> U.Srf.PLPolys = NULL; PObj -> U.Srf.CtlMesh = NULL; PObj -> U.Srf.Polygons = NULL; return PObj; } /***************************************************************************** * Generate one control point object: * * Only one of CagdCoords/Coords should be specified. * *****************************************************************************/ ObjectStruct *GenCtlPtObject(char *Name, CagdPointType PtType, CagdRType *CagdCoords, RealType *Coords, ObjectStruct *Pnext) { int i; CagdBType IsNotRational = !CAGD_IS_RATIONAL_PT(PtType); ObjectStruct *PObj; RealType *t; PObj = AllocObject(Name, CTLPT_OBJ, Pnext); PObj -> U.CtlPt.PtType = PtType; t = PObj -> U.CtlPt.Coords; if (CagdCoords != NULL) for (i = IsNotRational; i <= CAGD_NUM_OF_PT_COORD(PtType); i++) t[i] = CagdCoords[i]; else for (i = IsNotRational; i <= CAGD_NUM_OF_PT_COORD(PtType); i++) t[i] = Coords[i]; return PObj; } /***************************************************************************** * Generate one numeric object: * *****************************************************************************/ ObjectStruct *GenNumObject(char *Name, RealType *R, ObjectStruct *Pnext) { ObjectStruct *PObj; PObj = AllocObject(Name, NUMERIC_OBJ, Pnext); PObj -> U.R = *R; /* Link the union part of it... */ return PObj; } /***************************************************************************** * Generate one vector object: * *****************************************************************************/ ObjectStruct *GenVecObject(char *Name, RealType *Vec0, RealType *Vec1, RealType *Vec2, ObjectStruct *Pnext) { ObjectStruct *PObj; PObj = AllocObject(Name, VECTOR_OBJ, Pnext); PObj -> U.Vec[0] = *Vec0; /* Link the union part of it... */ PObj -> U.Vec[1] = *Vec1; PObj -> U.Vec[2] = *Vec2; return PObj; } /***************************************************************************** * Generate one matrix object: * *****************************************************************************/ ObjectStruct *GenMatObject(char *Name, MatrixType Mat, ObjectStruct *Pnext) { int i, j; ObjectStruct *PObj; PObj = AllocObject(Name, MATRIX_OBJ, Pnext); for (i = 0; i < 4; i++) /* Link the union part of it... */ for (j = 0; j < 4; j++) PObj -> U.Mat[i][j] = Mat[i][j]; return PObj; } /***************************************************************************** * Routine to create a whole new copy of an object Src into Dest. * * if Dest is NULL, new object is allocated, otherwise Dest itself is updated * * If CopyAll then all the record is copied, otherwise, only its variant * * element (i.e. no Name/Pnext coping) is been copied. * *****************************************************************************/ ObjectStruct *CopyObject(ObjectStruct *Dest, ObjectStruct *Src, int CopyAll) { int index; char Line[LINE_LEN]; if (Dest == NULL) Dest = AllocObject("", Src->ObjType, NULL); else { Dest->ObjType = Src->ObjType; } if (Dest == Src) return Dest; /* Called with same object - ignore. */ if (CopyAll) { strcpy(Dest->Name, Src->Name); Dest->Pnext = Src->Pnext; /* Maybe assigning NULL is better!? */ } switch (Src->ObjType) { case POLY_OBJ: Dest->U.Pl.P = CopyPolygonList(Src->U.Pl.P); CopyGeomAttrib(Dest, Src); Dest->U.Pl.IsPolyline = Src->U.Pl.IsPolyline; break; case NUMERIC_OBJ: Dest->U.R = Src->U.R; break; case VECTOR_OBJ: PT_COPY(Dest->U.Vec, Src->U.Vec); break; case CTLPT_OBJ: GEN_COPY(&Dest->U.CtlPt, &Src->U.CtlPt, CAGD_MAX_PT_SIZE * sizeof(RealType)); break; case MATRIX_OBJ: MAT_COPY(Dest->U.Mat, Src->U.Mat); break; case STRING_OBJ: strcpy(Dest->U.Str, Src->U.Str); break; case OBJ_LIST_OBJ: GEN_COPY(Dest->U.PObjList, Src->U.PObjList, MAX_OBJ_LIST * sizeof(ObjectStruct *)); index = 0; while (index < MAX_OBJ_LIST && Dest -> U.PObjList[index] != NULL) Dest -> U.PObjList[index++] -> Count++; /* Inc. # of ref. */ break; case CURVE_OBJ: Dest->U.Crv.Crv = CagdCrvCopy(Src->U.Crv.Crv); Dest->U.Crv.PLPolys = NULL; Dest->U.Crv.CtlPoly = NULL; CopyGeomAttrib(Dest, Src); break; case SURFACE_OBJ: Dest->U.Srf.Srf = CagdSrfCopy(Src->U.Srf.Srf); Dest->U.Srf.PLPolys = NULL; Dest->U.Srf.CtlMesh = NULL; Dest->U.Srf.Polygons = NULL; CopyGeomAttrib(Dest, Src); break; default: sprintf(Line, "CopyObject Attemp to copy undefined object %s type %d\n", Src->Name, Src->ObjType); FatalError(Line); } return Dest; } /***************************************************************************** * Routine to generate a new copy of an object polygon list. * *****************************************************************************/ PolygonStruct *CopyPolygonList(PolygonStruct *Src) { PolygonStruct *Phead, *Ptail; if (Src == NULL) return NULL; /* Prepare the header of the new polygon list: */ Phead = Ptail = AllocPolygon(1, Src->Tags, CopyVList(Src->V), NULL); PLANE_COPY(Ptail -> Plane, Src -> Plane); Src = Src -> Pnext; while (Src != NULL) { Ptail -> Pnext = AllocPolygon(Src->Count, Src->Tags, CopyVList(Src->V), NULL); Ptail = Ptail -> Pnext; PLANE_COPY(Ptail -> Plane, Src -> Plane); Src = Src -> Pnext; } return Phead; } /***************************************************************************** * Routine to generate a new copy of a polygon vertices list. * *****************************************************************************/ VertexStruct *CopyVList(VertexStruct *Src) { VertexStruct *Phead, *Ptail, *SrcFirst = Src; if (Src == NULL) return NULL; /* Prepare the header of the new vertex list: */ Phead = Ptail = AllocVertex(Src -> Count, Src -> Tags, NULL, NULL); PT_COPY(Phead -> Pt, Src -> Pt); PT_COPY(Phead -> Normal, Src -> Normal); Src = Src -> Pnext; while (Src != SrcFirst && Src != NULL) { Ptail -> Pnext = AllocVertex(Src -> Count, Src -> Tags, NULL, NULL); Ptail = Ptail -> Pnext; PT_COPY(Ptail -> Pt, Src -> Pt); PT_COPY(Ptail -> Normal, Src -> Normal); Src = Src -> Pnext; } if (Src == SrcFirst) Ptail -> Pnext = Phead;/* Make vertex list circular.*/ return Phead; }