/*****************************************************************************
* programm that parses IRIT data files and output it in WaveFront .obj	     *
* file format.								     *
*									     *
* Written by:  Gershon Elber				Ver 1.0, Feb 1993    *
* Changed by:  Kariv Michael				Ver 1.0, Aug 1993    *
*****************************************************************************/

#ifdef USE_VARARGS
#include <varargs.h>
#else
#include <stdarg.h>
#endif /* USE_VARARGS */
#include <stdio.h>
/* #include <stdlib.h>  */
#include <math.h>
#include <string.h>
#include <time.h>
#include "irit_sm.h"
#include "iritprsr.h"
#include "attribut.h"
#include "getarg.h"
#include "genmat.h"
#include "ffcnvrt.h"

static MatrixType CrntViewMat;			/* This is the current view! */
static int GlblFineNess = 10;

/* ADDED */

static int GlblVertices = 0;

static void PrintData(IPObjectStruct *PObj, int Indent);
static char *Real2Str(RealType R);

/*****************************************************************************
* Main routine - Read Parameter	line and do what you need...		     *
*****************************************************************************/
void main(int argc, char **argv)
{
    IPObjectStruct *PObjects, *PObj;

    /* Get the data files: */
    IritPrsrSetPolyListCirc(FALSE);
    IritPrsrSetFlattenObjects(TRUE);

    if (argc == 1) {
	char
	    *TmpStr = "-";

	PObjects = IritPrsrGetDataFiles(&TmpStr, 1, TRUE, FALSE);
    }
    else
	PObjects = IritPrsrGetDataFiles(argv + 1, argc - 1, TRUE, FALSE);

    if (IritPrsrWasPrspMat)
        MatMultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
    else
	GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));

    FFCState.LinearOnePolyFlag = TRUE;
    FFCState.FourPerFlat = TRUE;
    FFCState.OptimalPolygons = 0;
    FFCState.FineNess = 10;
    FFCState.OptimalPolylines = 0;
    FFCState.SamplesPerCurve = 64;
    FFCState.DrawFFMesh = FALSE;
    FFCState.CubicCrvsAprox = FALSE;
    FFCState.Talkative = TRUE;
    FFCState.ShowInternal = FALSE;
    FFCState.DrawFFGeom = TRUE;
    FFCState.DumpObjsAsPolylines = FALSE;

    for (PObj = PObjects; PObj != NULL; PObj = PObj -> Pnext) {
	if (IP_IS_FFGEOM_OBJ(PObj))
	    ProcessFreeForm(PObj, &FFCState);

	PrintData(PObj, 4);
    }
}

/*****************************************************************************
* Routine to print the data from given geometry object.			     *
*****************************************************************************/
static void PrintData(IPObjectStruct *PObj, int Indent)
{
    int i, ii, j, NVertices, NNormals;
    char
	*ErrStr = NULL;
    CagdRType *Coords;
    IPPolygonStruct *PPolygon;
    IPVertexStruct *PVertex;
    IPAttributeStruct
	*Attr = PObj -> Attrs;
    IPVertexStruct *Vertices[100000];

    if (Attr != NULL) {
	printf("\n");
	while (Attr) {
	    printf("%s", Attr2String(Attr));
	    Attr = AttrTraceAttributes(Attr, NULL);
	}
	printf("\n");
    }
    
    printf("g  %s\n", strlen(PObj -> Name) ? PObj -> Name : "default");

    Indent += 4;
	
    switch (PObj -> ObjType) {
	case IP_OBJ_POLY:
	    NVertices = 0;
	    for (PPolygon = PObj -> U.Pl;
		 PPolygon != NULL;
		 PPolygon = PPolygon -> Pnext) {
		if (PPolygon -> PVertex== NULL) {
		    fprintf(stderr,"Dump: Attemp to dump empty polygon\n");
		    exit(1);
		}
		PVertex = PPolygon -> PVertex;
		do {		     /* Assume at least one edge in polygon! */
		    for (ii =0; ii < NVertices; ii++)
		        if (PVertex -> Coord[0] == Vertices[ii] -> Coord[0] &&
			    PVertex -> Coord[1] == Vertices[ii] -> Coord[1] &&
			    PVertex -> Coord[2] == Vertices[ii] -> Coord[2] &&
			    PVertex -> Normal[0] == Vertices[ii] -> Normal[0] &&
			    PVertex -> Normal[1] == Vertices[ii] -> Normal[1] &&
			    PVertex -> Normal[2] == Vertices[ii] -> Normal[2])
			    break;   /* This vertex isn't new in the object. */

		    if (ii == NVertices) {
			/* This vertex is new in the object. */
			Vertices[ii] = PVertex;
			NVertices ++;
			printf("v  %s %s %s\n",
			       Real2Str(PVertex -> Coord[0]),
			       Real2Str(PVertex -> Coord[1]),
			       Real2Str(PVertex -> Coord[2]));
			printf("vn  %s %s %s\n",
			       Real2Str(PVertex -> Normal[0]),
			       Real2Str(PVertex -> Normal[1]),
			       Real2Str(PVertex -> Normal[2]));
		    }

		    PVertex = PVertex -> Pnext;
		}
		while (PVertex != PPolygon -> PVertex && PVertex != NULL);
	    }

	    /* All vertices information was already printed.		    */
	    /* Now faces (or polygons in the IRIT jargon) are printed.      */
	    printf("\n\n");

	    printf("g  %s\n",
		     strlen(PObj -> Name) ? PObj -> Name : "default");
	    for (PPolygon = PObj -> U.Pl;
		 PPolygon != NULL;
		 PPolygon = PPolygon -> Pnext) {
		printf("f  ");
		PVertex = PPolygon -> PVertex;
		do {
		    for (ii =0; ii < NVertices; ii++)
		        if (PVertex -> Coord[0] == Vertices[ii] -> Coord[0] &&
			    PVertex -> Coord[1] == Vertices[ii] -> Coord[1] &&
			    PVertex -> Coord[2] == Vertices[ii] -> Coord[2] &&
			    PVertex -> Normal[0] == Vertices[ii] -> Normal[0] &&
			    PVertex -> Normal[1] == Vertices[ii] -> Normal[1] &&
			    PVertex -> Normal[2] == Vertices[ii] -> Normal[2]) {
			    /* +1 is because in .obj files the  */
			    /* vertex numeration is from one.  */
			    printf ("%d//%d ", GlblVertices + ii + 1,
				               GlblVertices + ii + 1);
			    break;
			}

		    if (ii == NVertices) {
			printf("irit2wf: error");
			exit(1);
		    }

		    PVertex = PVertex -> Pnext;
		} 
		while (PVertex != PPolygon -> PVertex && PVertex != NULL);
		printf("\n");
	    }
	    GlblVertices += NVertices;
	    break;
	default:
	    fprintf(stderr,
		    "Dump: Attemp to dump undefine object \"%s\" type (%d).\n",
		    PObj -> Name ? PObj -> Name : "", PObj -> ObjType);
	    break;
    }

    Indent -= 4;
}

/*****************************************************************************
* Convert a real number into a string.					     *
* The routine maintains 6 different buffers simultanuously so up to 6 calls  *
* can be issued from same printf...					     *
*****************************************************************************/
static char *Real2Str(RealType R)
{
    static int j, k,
	i = 0;
    static char Buffer[6][LINE_LEN_SHORT], Line[LINE_LEN];

    if (ABS(R) < EPSILON) R = 0.0;	    /* Round off very small numbers. */

    sprintf(Buffer[i], "%6lg", R);

    for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
    if (k >= LINE_LEN) {
	fprintf(stderr, "Conversion of real number (%f) failed.\n", R);
	exit(1);
    }

    for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
    if (strchr(Buffer[i], '.') != NULL)
	for (; Buffer[i][j] == '0' && j > k; j--);
    Buffer[i][j+1] = 0;

    j = i;
    i = (i + 1) % 6;
    return Buffer[j];
}
