\begin{verbatim}
/*****************************************************************************
*   Computes the importance of vertices and dump as vertex list + polygons   *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Gershon Elber                                Ver 1.0, June 1995   *
*****************************************************************************/

#include "irit_sm.h"
#include "allocate.h"
#include "iritprsr.h"
#include "geom_lib.h"
#include "misc_lib.h"
#include "ip_cnvrt.h"

STATIC_DATA char
    *CtrlStr = "Imprtnc h%- DFiles!*s";
STATIC_DATA int GlblVrtxImportanceCount;
STATIC_DATA RealType GlblVrtxImportanceVal;
STATIC_DATA IPVertexStruct *GlblVrtxImportance;

static void DumpOneTraversedObject(IPObjectStruct *PObj, MatrixType Mat);
static void DumpOneObjData(IPObjectStruct *PObj);
static void ProcessVertexImportance(IPVertexStruct *V1,
                                    IPVertexStruct *V2,
                                    IPPolygonStruct *Pl1,
                                    IPPolygonStruct *Pl2);
static void GenPolyImportance(IPObjectStruct *PObj);

void main(int argc, char **argv)
{
    int NumFiles, Error,
        HelpFlag = FALSE;
    char **FileNames;
    IPObjectStruct *PObjects;
    MatrixType CrntViewMat;

    if ((Error = GAGetArgs(argc, argv, CtrlStr,
                           &HelpFlag, &NumFiles, &FileNames)) != 0) {
        GAPrintErrMsg(Error);
        GAPrintHowTo(CtrlStr);
        exit(1);
    }

    if (HelpFlag) {
        fprintf(stderr, "This is Importance testing...\n");
        GAPrintHowTo(CtrlStr);
        exit(0);
    }

    /* Get the data files: */
    IPSetFlattenObjects(FALSE);
    if ((PObjects = IPGetDataFiles(FileNames, NumFiles, TRUE, FALSE)) == NULL)
        exit(1);
    PObjects = IPResolveInstances(PObjects);

    if (IPWasPrspMat)
        MatMultTwo4by4(CrntViewMat, IPViewMat, IPPrspMat);
    else
        GEN_COPY(CrntViewMat, IPViewMat, sizeof(MatrixType));

    /* Here some useful parameters to play with in tesselating freeforms: */
    IPFFCState.FineNess = 5;  /* Resolution of tesselation, larger is finer. */
    IPFFCState.ComputeUV = TRUE;       /* Wants UV coordinates for textures. */
    IPFFCState.FourPerFlat = TRUE;/* 4 polygons per ~flat patch, 2 otherwise.*/
    IPFFCState.LinearOnePolyFlag = TRUE;   /* Linear srf generates one poly. */

    IPTraverseObjListHierarchy(PObjects, CrntViewMat, DumpOneTraversedObject);

    IPFreeObjectList(PObjects);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Call back function of IPTraverseObjListHierarchy. Called on every non    *
* list object found in hierarchy.                                            *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:       Non list object to handle.                                   *
*   Mat:        Transformation matrix to apply to this object.               *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpOneTraversedObject(IPObjectStruct *PObj, MatrixType Mat)
{
    IPObjectStruct *PObjs;

    if (IP_IS_FFGEOM_OBJ(PObj))
        PObjs = IPConvertFreeForm(PObj, &IPFFCState);
    else
        PObjs = PObj;

    for (PObj = PObjs; PObj != NULL; PObj = PObj -> Pnext) {
        if (IP_IS_POLY_OBJ(PObj))
            DumpOneObjData(PObj);
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Convert the polygonal mesh into a vertex list with importance and the    *
* polygons as indices into this list.                                        *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:   A polygonal mesh to dump.                                        *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpOneObjData(IPObjectStruct *PObj)
{
    IPPolyVrtxIdxStruct
        *PVIdx = IPCnvPolyToPolyVrtxIdxStruct(PObj);
    int        i,
        **Polygons = PVIdx -> Polygons;
    IPVertexStruct
        **Vertices = PVIdx -> Vertices;

    /* Compute importance for the vertices as "Imprt" attributes.  Note the */
    /* PVIdx data structure points on the original vertices so we are fine. */
    GenPolyImportance(PObj);

    /* Dump the vertices: */
    fprintf(stderr, "OBJECT \"%s\" - VERTICES:\n", PObj -> Name);
    for (i = 0; Vertices[i] != NULL; i++) {
        RealType R;
        float *uv;

        printf("%3d:  %6.3f %6.3f %6.3f", i,
               Vertices[i] -> Coord[0], 
               Vertices[i] -> Coord[1], 
               Vertices[i] -> Coord[2]);
        if (IP_HAS_NORMAL_VRTX(Vertices[i]))
            printf(" [%6.3f %6.3f %6.3f]",
                   Vertices[i] -> Normal[0], 
                   Vertices[i] -> Normal[1], 
                   Vertices[i] -> Normal[2]);
        if ((uv = AttrGetUVAttrib(Vertices[i] -> Attr, "uvvals")) != NULL)
            printf(" {%6.3f %6.3f}", uv[0], uv[1]);

        R = AttrGetRealAttrib(Vertices[i] -> Attr, "Imprt");
        if (!IP_ATTR_IS_BAD_REAL(R))
            printf(" (%6.3f)", R);
        printf("\n");
    }

    /* Dump the polygons: */
    fprintf(stderr, "OBJECT \"%s\" - POLYGONS:\n", PObj -> Name);
    for (i = 0; Polygons[i] != NULL; i++) {
        int *Pl = Polygons[i];

        while (*Pl >= 0)
            fprintf(stderr, " %5d", *Pl++);

        fprintf(stderr, "    -1\n");
    }

    IPPolyVrtxIdxFree(PVIdx);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Call back function for GMPolyAdjacncyVertex to process every edge of a   *
* given vertex.  The edge is provided as (V, V -> Pnext)                     *
*                                                                            *
* PARAMETERS:                                                                *
*   V1, V2:    Two vertices defining this edge.  Note the vertices are NOT   *
*               necessarily chained together into a list.                     *
*   Pl1, Pl2:  The two polygons that share this edge.  The edge (V1, V2) is  *
*               in both Pl1 and Pl2, with not necessarily the exact pointers  *
*               IPVertexStruct of V1 and V2.                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void ProcessVertexImportance(IPVertexStruct *V1,
                                    IPVertexStruct *V2,
                                    IPPolygonStruct *Pl1,
                                    IPPolygonStruct *Pl2)
{
    if (!PT_APX_EQ_EPS(V1 -> Coord, GlblVrtxImportance -> Coord, IRIT_EPS) &&
        !PT_APX_EQ_EPS(V2 -> Coord, GlblVrtxImportance -> Coord, IRIT_EPS))
        fprintf(stderr, "Edge does not match the given vertex - adj error!\n");

    if (Pl1 != NULL && Pl2 != NULL) {
        GlblVrtxImportanceCount++;
        GlblVrtxImportanceVal += acos(DOT_PROD(Pl1 -> Plane, Pl2 -> Plane));
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Computes importance for each vertex in the given polygonal mesh.         *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:         Polygonal model to process for importance.                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void GenPolyImportance(IPObjectStruct *PObj)
{
    VoidPtr
        PAdj = GMPolyAdjacncyGen(PObj, IRIT_EPS);
    IPPolygonStruct *Pl;

    for (Pl = PObj -> U.Pl; Pl != NULL; Pl = Pl -> Pnext) {
        int PlImportanceCount = 0;
        RealType
            PlImportanceVal = 0.0;
        IPVertexStruct *V;

        for (V = Pl -> PVertex; V != NULL; V = V -> Pnext) {
            GlblVrtxImportanceVal = 0.0;
            GlblVrtxImportanceCount = 0;
            GlblVrtxImportance = V;

            GMPolyAdjacncyVertex(V, PAdj, ProcessVertexImportance);

            if (GlblVrtxImportanceCount > 0) {
                GlblVrtxImportanceVal /= (GlblVrtxImportanceCount * M_PI);

                AttrSetRealAttrib(&V -> Attr, "Imprt", GlblVrtxImportanceVal);
            }
            else
                fprintf(stderr, "Failed to compute Importance for vertex\n");
        }
    }

    GMPolyAdjacncyFree(PAdj);
}
\end{verbatim}
