Source Code


/*****************************************************************************
*
* Module Name:  DXtoWebOOGL
*
* Category:     Import and Export
*
* Author:       Felix Lung and David Wu, Cornell University
*
* Date:         Spring 1995
*
* Description:  DX Module to export dx text format to WebOOGL OFF file
*
****************************************************************************/

#include <dx/dx.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>

#define TRUE   1
#define FALSE  0
#define FRONT  1
#define BEHIND 0
#define ONECOLOR 0
#define COLORMAP 1
#define CLUT     2
#define MAXLEN 1024

typedef int FLAG;
typedef char * strng;

char *Def_mtllib = "master.mtl";
char *Def_usemtl = "white";         	/*For now, export all objects as white*/
char *Def_maplib = "master.map";
char *Def_usemap = "default_map";

/* Contains total number of positions and connections respectively */
int totalpos;
int totalcon;

/* Function declarations */
static Error write_header( FILE *fp);
static Error check_fields(Object o, FILE *fp, FILE *vertices, FILE *faces);
static Error get_colors(float *colors, int i, float *red, float *green, float *blue);
static Error get_positions( float *pos, int i, int dimension, float *x, float 
*y, float *z);
static Error write_lines ( FILE *fp, int *con, int ncon , float *pos, int 
dimension );
static Error write_triangles ( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int 
npos, int dimension , float *colors);
static Error write_quads ( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int npos, 
int dimension, float *colors);
static Error write_cubes ( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int npos, 
int dimension , float *colors);
static Error write_tetrahedra( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int 
npos, int dimension , float *colors);

/* Main function for module */
m_dx2web( Object *in )
{
    Array    a;
    char     fnameBuf[MAXLEN], errmsg[MAXLEN];
    char     *fname;
    char     cmd_string[100];
    FILE     *fp, *vertices, *faces, *fopen();
    float    *pos;
    int      i;
    int      slen;
    Object   o;
    
    /* Initialize total positions and connections to 0 */
    totalpos = 0;
    totalcon = 0;

    /**********************************/
    /* extract file-name string in[1] */

    if ( !in[0] )
        DXErrorReturn( ERROR_BAD_PARAMETER, "missing object" );
    if ( !in[1] )
        DXErrorReturn( ERROR_BAD_PARAMETER, "no output ray file name specified" 
);
    if ( !DXExtractString( in[1], &fname ) ) {
        DXErrorReturn( ERROR_BAD_PARAMETER, "ray file name must be a string" );
    }
    else
        strcpy( fnameBuf, fname );

    /* prevent naming the file simply ".off", or "."anything */
    slen = strlen( fname );
    if ( !strcmp( fname, ".obj" ) )
        DXErrorReturn( ERROR_BAD_PARAMETER, "unacceptable file name (.off)" );
    if ( !strncmp( fname, ".", 1 ) )
        DXErrorReturn( ERROR_BAD_PARAMETER,
            "unacceptable file name (starts with .)" );

    /* if user already appended ".off", leave it, otherwise, append ".off" */
    if ( !( slen > 3 && !strcmp( &fname[slen-4], ".off" ) ) )
        strcat( fnameBuf, ".off" );

    /* Set a file pointer to an open writable file called "vertices"  which will
    	hold the listing of the faces of the polygon */
    vertices = fopen("vertices", "w");
    /* Set a file pointer to an open writeable file called "faces" which will
    	hold the listing of the faces of the polygon */
    faces = fopen("faces", "w");

    /* Error checking for the file name given */
    if ( ( fp = fopen( fnameBuf, "w" ) ) == NULL ) {
        sprintf( errmsg, "cannot open file %s to write", fnameBuf );
        DXErrorReturn( ERROR_BAD_PARAMETER, errmsg );
    }

    
    /* write file header to .off file */
    if ( !write_header( fp ) )
        DXErrorGoto( ERROR_UNEXPECTED, "error in write_header" );
     
    
    /* get the input field in[0] and store into object variable o*/
    o = DXCopy( in[0], COPY_STRUCTURE );
    if ( !o )
        DXErrorGoto( ERROR_UNEXPECTED,
              "failed to copy structure of input object" );

    /* This is the primary recursive call which passes in the object variable o
    	and the three file pointers to check_fields */
    if (!check_fields(o, fp, vertices, faces))
      DXErrorGoto( ERROR_UNEXPECTED,
                  "error in structure of input object" );


    /* Close the files that were used */
    fclose( vertices );
    fclose( faces );
    fprintf(fp, "%i %i\n", totalpos, totalcon);
    fclose( fp );
    
    /* Concatenate the vertices and the faces to the output file */
    sprintf(cmd_string, "cat vertices >> %s", fnameBuf);
    system(cmd_string);
    sprintf(cmd_string, "cat faces >> %s",fnameBuf);
    system(cmd_string);
    return OK;

    error:
        fclose( vertices );
        fclose( faces );
        fclose( fp );
        return ERROR;
}

/* check_fields holds the body of the program. It checks the various parts of
	the object for FIELDS and XFORMS. Currently XFORMs are not applied but
	may be implemented at a later date */
static Error check_fields(Object o, FILE *fp, FILE *vertices, FILE *faces)
{
  Object subo, returno;
  Object testo;
  Object test2o;
  int i;
  Array a, test;
  Matrix *m;
  int dimension;
  int npos, ncon, ncolors;
  float *colors;
  int *con;
  float *pos;

  /* DXGetObjectClass takes the object and determines the DX object class */
  switch(DXGetObjectClass(o))
    {
      /* The class may be GROUP in which case the top of the group is stripped
      	off and the rest of the group is passed onto another check_fields call*/
      case CLASS_GROUP:
      for (i=0; subo = DXGetEnumeratedMember((Group)o,i,NULL); i++)
        if (!check_fields(subo,fp, vertices, faces)) return ERROR;
      break;
      
      /* NOT DONE YET!!!!!!!!!!!!!!!!!!!!
      case CLASS_XFORM:
      	    system("touch CLASS_XFORM");


      	     
      	    if (!DXGetXformInfo( (Xform)o, testo, m))
      	    	DXErrorGoto( ERROR_MISSING_DATA, "Yikes! Bad transform!!")	
      	    else {
      	    
      	    	returno = DXApplyTransform(testo, m);}
      	    if (!check_fields(returno,fp, vertices, faces)) return ERROR; 
      break;
      	    
      */
      
      /* If the object is of class FIELD then the positions and connections
      	are extracted and written to the respective files */
      case CLASS_FIELD:
            /* extract positions from field into the array a*/
            a = (Array)DXGetComponentValue( (Field)o, "positions" );
            if ( !a )
              DXErrorGoto( ERROR_MISSING_DATA, "input has no positions" );

	    /* check for 2-D or 3-D input */
            if ( DXTypeCheck( a, TYPE_FLOAT, CATEGORY_REAL, 1, 3 ) )
                dimension = 3;
            else if ( DXTypeCheck( a, TYPE_FLOAT, CATEGORY_REAL, 1, 2 ) )
                dimension = 2;
            else
              DXErrorGoto( ERROR_BAD_TYPE,
                          "positions are neither 2D nor 3D");

            if ( !DXGetArrayInfo( a, &npos, NULL, NULL, NULL, NULL ) )
                return ERROR;
	    /* DXGetArrayData stores the positions into the variable pos */
            pos = (float *)DXGetArrayData( a );

            
            /* extract connections from field into array a */
            a = (Array)DXGetComponentValue( (Field)o, "connections" );
            if ( !a )
              DXErrorGoto( ERROR_MISSING_DATA, "input has no data");

            if ( !DXTypeCheckV( a, TYPE_INT, CATEGORY_REAL, 1, NULL ) )
              DXErrorGoto( ERROR_BAD_TYPE, "connections not integer vector");

            DXGetArrayInfo( a, &ncon, NULL, NULL, NULL, NULL );
            /* DXGetArrayData stores the connections into the variable con */
            con = (int *)DXGetArrayData( a );
            
	    /* Trying to test whether I can get colors or not*/
	    test = (Array)DXGetComponentValue( (Field)o, "colors");
	    
	    if (!test)
	    	DXErrorGoto( ERROR_BAD_TYPE, "No colors");
	    DXGetArrayInfo( test, &ncolors, NULL, NULL, NULL, NULL);
	    
	    /* Error check for npos mismatch */
	    if (ncolors != npos)
	    	DXErrorGoto (ERROR_BAD_TYPE, "Missing colors for some vertices!");
	    	
	    colors = (float *)DXGetArrayData( test);	   
	    
            /* we must have valid connections by now, */
            /* so find out what type they are         */
            /*  then write them out                   */
            if ( DXGetConnections( (Field)o, "lines" ) ) {
                DXWarning( "Lines type is not supported" );
                write_lines( fp, con, ncon, pos, dimension );
            }
            /* If the Connection type is triangles, quads, cubes... go to the 
            	respective functions below */
            else if ( DXGetConnections( (Field)o, "triangles" ) )
                write_triangles( fp, vertices, faces, con, ncon, pos, npos, dimension , colors);
            else if ( DXGetConnections( (Field)o, "quads" ) )
                write_quads(fp, vertices, faces, con, ncon, pos, npos, dimension , colors);
            else if ( DXGetConnections( (Field)o, "cubes" ) )
                write_cubes(fp, vertices, faces, con, ncon, pos, npos, dimension, colors );
            else if ( DXGetConnections( (Field)o, "tetrahedra" ) )
                write_tetrahedra(fp, vertices, faces, con, ncon, pos, npos, dimension , colors);
            else {
              DXErrorGoto( ERROR_UNEXPECTED,
                          "can't deal with this connection type");
              }
      break;

    default:
      break;
    }

  return OK;

 error:
  return ERROR;
}


static Error write_header( FILE *fp )
{
  /* writes the header information, in this case, the standard webOOGL type OFF */
    fprintf( fp, "COFF\n");

    return OK;
}

/* This function gets the colors of the object vertices and returns them in 
	r,g,b */
static Error get_colors( float *colors, int i, float *red, float *green, float *blue)
{
  *red = *(colors + 3*i + 0);
  *green = *(colors + 3*i + 1);
  *blue = *(colors + 3*i + 2);
}
	
/* This function gets the positions of the object based on the dimension */
static Error get_positions( float *pos, int i, int dimension, float *x, float *y, float *z)
{
  if ( dimension == 2 )
    {
      *x = *(pos + 2*i + 0);
      *y = *(pos + 2*i + 1);
      *z = 0.0;
    }
  else
    {
      *x = *(pos + 3*i + 0);
      *y = *(pos + 3*i + 1);
      *z = *(pos + 3*i + 2);
    }

  return OK;
}


static Error write_lines( FILE *fp, int *con, int ncon, float *pos, int dimension )
{

    /* Lines are not supported */

    return OK;
}

/* write_triangle outputs the positions of the object to the file vertices 
	and then outputs the corresponding connections to the file faces */
static Error write_triangles( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int npos, int 
dimension, float *colors )
{
    int i;
    float x, y, z, red, green, blue;
 
    /* Loops through all the positions calling get_positions to extract the 
    	actual values from the array pos */
    for (i=0; i<npos; i++)
    {
        get_positions( pos, i, dimension, &x, &y, &z );
        get_colors( colors, i, &red, &green, &blue);
        /* print the data to the file vertices */
        fprintf( vertices, "%f %f %f %f %f %f 1.0\n", x, y, z, red, green, blue);
    }

    /* Loops through all the connections in variable con */
    for (i = 0; i < 3*ncon; i = i+3) {
    	/* print the next three connections (since it is a triangle) to faces 
    	totalpos is added to the value of con[i, i+1,...] to keep
    	track of exactly which FIELD we are processing. The FIELD has
    	its connections numbered in relative numbering but when the
    	entire group file is assembled we want it to be in absolute
    	numbering (increasing as the number of FIELDS processed increases */
    	fprintf(faces , "3 %i %i %i\n", con[i]+totalpos, con[i+1]+totalpos, con[i+2]+totalpos);
    }
    
    /* Keep track of the total positions and connections */
        totalpos += npos;
        totalcon += ncon;
    return OK;
}


static Error write_quads( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int npos, int dimension, float *colors)
{
    int i;
    float x, y, z, red, green, blue;
    
    /* Loops through all the positions calling get_positions to extract the 
    	actual values from the array pos */
    for (i=0; i<npos; i++)
      {
        get_positions( pos, i, dimension, &x, &y, &z );
        get_colors( colors, i, &red, &green, &blue);
        fprintf( vertices, "%f %f %f %f %f %f 1.0\n", x, y, z, red, green, blue);  
      }
      
    /* Loops through all the connections in variable con going by intervals
    	of four since it is a quad */
    for (i = 0; i < 4*ncon; i = i+4) {
	fprintf(faces, "4 %i %i %i %i\n", con[i]+totalpos, con[i+1]+totalpos, con[i+3]+totalpos, 
con[i+2]+totalpos);
    }
    totalpos += npos;
    totalcon += ncon;	
    return OK;
}


static Error write_cubes( FILE *fp, FILE *vertices, FILE *faces, int *con, 
int ncon, float *pos, int npos, int dimension , float *colors)
{
    int i;
    int *connect;
    float x, y, z, r, g, b;

    fprintf( fp, "/* cubes */\n");
    for (i=0; i<npos; i++)
    {
        get_positions( pos, i, dimension, &x, &y, &z );
        get_colors( colors, i, &r, &g, &b);
        fprintf( vertices, "%f %f %f %f %f %f 1.0\n", x, y, z, r, g, b);  
    }
    for (i = 0; i < 8*ncon; i = i+8) {
	fprintf(faces, "8 %i %i %i %i %i %i %i %i\n", con[i]+totalpos, 
	con[i+2]+totalpos, con[i+3]+totalpos, con[i+1]+totalpos, con[i+1]+totalpos,con[i+3]+totalpos, 
	con[i+7]+totalpos,con[i+5]+totalpos, con[i+5]+totalpos,con[i+7]+totalpos, con[i+6]+totalpos,
	con[i+4]+totalpos, con[i+4]+totalpos,con[i+6]+totalpos, con[i+2]+totalpos,con[i]+totalpos);
	
    }
    totalpos += npos;
    totalcon += ncon;
    return OK;
}


static Error write_tetrahedra( FILE *fp, FILE *vertices, FILE *faces, int *con, int ncon, float *pos, int npos , int 
dimension, float *colors )
{
    int i;
    float x, y, z, r, g, b;

    fprintf( fp, "/* tetras */\n");

      for (i=0; i<npos; i++)
      {
        get_positions( pos, i, dimension, &x, &y, &z );
        get_colors( colors, i, &r, &g, &b);
        fprintf( vertices, "%f %f %f %f %f %f 1.0\n", x, y, z, r, g, b);  
      }
    for (i = 0; i < 4*ncon; i = i+4) {
	fprintf(faces, "4 %i %i %i %i\n", con[i]+totalpos, con[i+1]+totalpos, con[i+3]+totalpos, 
con[i+2]+totalpos);
    }
    totalpos += npos;
    totalcon += ncon;
}