/*****************************************************************************
*   Default surface drawing routine common to graphics drivers.		     *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Gershon Elber				Ver 0.1, June 1993.  *
*****************************************************************************/

#include "irit_sm.h"
#include "iritprsr.h"
#include "allocate.h"
#include "attribut.h"
#include "cagd_lib.h"
#include "symb_lib.h"
#include "ip_cnvrt.h"
#include "iritgrap.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
* Draw a single surface object using current modes and transformations.	     M
*   Piecewise linear approximation is cashed under "_isoline" and "_ctlmesh" M
* attributes of PObj. Polygonal approximation is saved under "_polygons".    M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     A surface object to draw.                                      M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGDrawSurface                                                            M
*****************************************************************************/
void IGDrawSurface(IPObjectStruct *PObj)
{
    IPObjectStruct *PObjPolylines, *PObjCtlMesh, *PObjPolygons;
    IPPolygonStruct *PPolylines, *PCtlMesh, *PPolygons, *PPolygonTemp;

    if (IGGlblDrawSurfacePoly || IGGlblDrawSolid) {
	if ((PObjPolygons = AttrGetObjectObjAttrib(PObj, "_polygons"))
								    == NULL) {
	    CagdSrfStruct *Srf,
	        *Srfs = PObj -> U.Srfs;
	    RealType RelativeFineNess;

	    PObjPolygons = IPAllocObject("", IP_OBJ_POLY, NULL);
	    PObjPolygons -> Attrs = AttrCopyAttributes(PObj -> Attrs);
	    IP_SET_POLYGON_OBJ(PObjPolygons);

	    if ((RelativeFineNess = AttrGetObjectRealAttrib(PObj,
					   "resolution")) >= IP_ATTR_BAD_REAL)
		RelativeFineNess = 1.0;

	    for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
		RealType t;

		if ((t = AttrGetObjectRealAttrib(PObjPolygons, "u_resolution"))
							    < IP_ATTR_BAD_REAL)
		    AttrSetRealAttrib(&Srf -> Attr, "u_resolution", t);
		if ((t = AttrGetObjectRealAttrib(PObjPolygons, "v_resolution"))
							    < IP_ATTR_BAD_REAL)
		    AttrSetRealAttrib(&Srf -> Attr, "v_resolution", t);

		PPolygons = IritSurface2Polygons(Srf, IGGlblFourPerFlat,
						 RelativeFineNess *
						     IGGlblFineNess,
						 FALSE, TRUE,
						 IGGlblPolygonOptiApprox);

		if (PPolygons != NULL) {
		    if (PPolygons) {
			for (PPolygonTemp = PPolygons;
			     PPolygonTemp -> Pnext;
			     PPolygonTemp = PPolygonTemp -> Pnext);
			PPolygonTemp -> Pnext = PObjPolygons -> U.Pl;
			PObjPolygons -> U.Pl = PPolygons;
		    }
		}
	    }
	    if (IGGlblCacheGeom)
		AttrSetObjectObjAttrib(PObj, "_polygons", PObjPolygons, FALSE);
	}

        if (PObjPolygons != NULL) {
	    IGDrawPoly(PObjPolygons);

	    if (!IGGlblCacheGeom)
		IPFreeObject(PObjPolygons);
	}
    }
    else {
	if ((PObjPolylines = AttrGetObjectObjAttrib(PObj, "_isoline")) == NULL &&
	    IGGlblNumOfIsolines > 0) {
	    CagdSrfStruct *Srf,
		*Srfs = PObj -> U.Srfs;

	    PObjPolylines = IPAllocObject("", IP_OBJ_POLY, NULL);
	    PObjPolylines -> Attrs = AttrCopyAttributes(PObj -> Attrs);
	    IP_SET_POLYLINE_OBJ(PObjPolylines);
	    for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
		int NumOfIso[2];

		NumOfIso[0] = -IGGlblNumOfIsolines;
		NumOfIso[1] = -IGGlblNumOfIsolines;
		PPolylines = IritSurface2Polylines(Srf, NumOfIso,
						   IGGlblSamplesPerCurve,
						   IGGlblPolylineOptiApprox);

		if (PPolylines != NULL) {
		    for (PPolygonTemp = PPolylines;
			 PPolygonTemp -> Pnext;
			 PPolygonTemp = PPolygonTemp -> Pnext);
		    PPolygonTemp -> Pnext = PObjPolylines -> U.Pl;
		    PObjPolylines -> U.Pl = PPolylines;
		}
	    }
	    if (IGGlblCacheGeom)
		AttrSetObjectObjAttrib(PObj, "_isoline", PObjPolylines, FALSE);
	}

        if (PObjPolylines != NULL) {
	    IGDrawPoly(PObjPolylines);

	    if (!IGGlblCacheGeom)
		IPFreeObject(PObjPolylines);
	}
    }

    if (IGGlblDrawSurfaceMesh) {
	if ((PObjCtlMesh = AttrGetObjectObjAttrib(PObj, "_ctlmesh"))
								== NULL) {
	    CagdSrfStruct *Srf,
		*Srfs = PObj -> U.Srfs;

	    PObjCtlMesh = IPAllocObject("", IP_OBJ_POLY, NULL);
	    PObjCtlMesh -> Attrs = AttrCopyAttributes(PObj -> Attrs);
	    IP_SET_POLYLINE_OBJ(PObjCtlMesh);
	    for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
		PCtlMesh = IritSurface2CtlMesh(Srf);

		for (PPolygonTemp = PCtlMesh;
		     PPolygonTemp -> Pnext;
		     PPolygonTemp = PPolygonTemp -> Pnext);
		PPolygonTemp -> Pnext = PObjCtlMesh -> U.Pl;
		PObjCtlMesh -> U.Pl = PCtlMesh;
	    }
	    if (IGGlblCacheGeom)
		AttrSetObjectObjAttrib(PObj, "_ctlmesh", PObjCtlMesh, FALSE);
	}

        if (PObjCtlMesh != NULL) {
	    IGDrawPoly(PObjCtlMesh);

	    if (!IGGlblCacheGeom)
		IPFreeObject(PObjCtlMesh);
	}
    }
}
