home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / formats / off / code / offconv.c < prev    next >
C/C++ Source or Header  |  1994-06-20  |  9KB  |  367 lines

  1. /*
  2.  *
  3.  * Name
  4.  *    offconv
  5.  *
  6.  * Description
  7.  *    Convert off (Object File Format) files from ASCII to binary
  8.  *    and vice versa.
  9.  *    Optionally, ``pack'' the geometry to improve file size and
  10.  *    rendering speed.
  11.  *      Optionally adds per polygon normals.
  12.  *    Optionally decrements vertex numbers so they begin at 0.
  13.  *
  14.  * Author
  15.  *    Randi J. Rost
  16.  *    Digital Equipment Corp.
  17.  *    Workstation Systems Engineering
  18.  *    Palo Alto, CA
  19.  *
  20.  *    Packing option added by Allen Akin, also of WSE
  21.  *
  22.  * Diagnostics
  23.  *    Returns -1 if it blows up for any reason
  24.  *    
  25.  * History
  26.  *    Randi J. Rost    14-Nov-1986    created
  27.  *    Allen Akin    19-Feb-1987    packing option added
  28.  *      James Painter   10-Aug-1988     Per polygon normals added
  29.  *    Randi J. Rost     8-Aug-1989    vertex number adjustment option added
  30.  *
  31.  */
  32.  
  33. #include <stdio.h>
  34. #include <math.h>
  35. #include "off.h"
  36.  
  37. extern double sqrt();
  38. static char *ProgramName;
  39. static int toascii = 1, addnormals = 0, pack = 0, adjust = 0;
  40. char *infilename = NULL, *outfilename;
  41.  
  42. Usage()
  43. {
  44.   fprintf(stderr, "usage: %s [-a][-b][p-][-n] inobj outobj\n", ProgramName );
  45. }
  46.  
  47.  
  48. ParseCommandLine(argc, argv)
  49.      int argc;
  50.      char *argv[];
  51. {
  52.   int ArgsParsed = 0;
  53.   char *sw;
  54.  
  55.   ProgramName = argv[ArgsParsed++];
  56.  
  57.   while ( ArgsParsed < argc ) {
  58.     if (argv[ArgsParsed][0] == '-')
  59.       {
  60.     sw = argv[ArgsParsed++] + 1;
  61.     for( ; *sw != '\0'; sw++) {
  62.       switch (*sw)
  63.         {
  64.         case 'a':  toascii = 1;    break;
  65.         case 'b':  toascii = 0;    break;
  66.         case 'n':  addnormals = 1;  break;
  67.         case 'p':  pack = 1;    break;
  68.         case '1':  adjust = 1;    break;  /* undocumented option */
  69.         default:
  70.           fprintf(stderr, "Unknown option '%s'\n\n", *sw );
  71.           Usage();
  72.           exit(-1);
  73.         }
  74.     }
  75.       } else {
  76.     if (infilename != NULL) {
  77.       if (outfilename != NULL) {
  78.         Usage(); exit(-1);
  79.       }
  80.       outfilename = argv[ArgsParsed++];
  81.     }  else
  82.       infilename = argv[ArgsParsed++];
  83.       }
  84.   }
  85.   if (infilename == NULL || outfilename == NULL) {
  86.     Usage(); exit(-1);
  87.   }
  88. }
  89.  
  90.  
  91. main(argc, argv)
  92.     int        argc;
  93.     char    *argv[];
  94.  
  95.     {
  96.     OFFObjDesc    obj;
  97.     char    inbase[80], outbase[80];
  98.     char    indir[80], outdir[80];
  99.     char    inext[80], outext[80];
  100.     char    newname[80];
  101.     int        i;
  102.     int        type;
  103.     char    dir[80], base[80], ext[80];
  104.     OFFProperty    *pProp;
  105.  
  106.  
  107.     ParseCommandLine( argc, argv );
  108.  
  109.     if (-1 == OFFReadObj(&obj, infilename ) )
  110.       exit(-1);
  111.  
  112.     basename(infilename, indir, inbase, inext);
  113.     basename(outfilename, outdir, outbase, outext);
  114.     if (addnormals)
  115.       AddNormals( outbase, &obj );
  116.     if (pack)
  117.     OFFPackObj(&obj);
  118.     if (adjust)
  119.     AdjustVertexNums(&obj);
  120.  
  121.     pProp = obj.FirstProp;
  122.     while (pProp != NULL)
  123.     {
  124.     if (pProp->PropFileName != NULL)
  125.         {
  126.         basename(pProp->PropFileName, dir, base, ext);
  127.         if (toascii)
  128.         {
  129.         strcpy(newname, outbase);
  130.         strcat(newname, ".");
  131.  
  132.         /*  The following kludge will not work if there are valid  */
  133.         /*  ASCII file extensions that begin with 'b'.  Right now  */
  134.         /*  we assume that if the extension begins with 'b', the   */
  135.         /*  file is in binary.                                     */
  136.  
  137.         if (ext[0] == 'b')
  138.             strcat(newname, &(ext[1]));
  139.         else
  140.             strcat(newname, ext);
  141.         }
  142.         else
  143.         {
  144.         strcpy(newname, outbase);
  145.         strcat(newname, ".b");
  146.         strcat(newname, ext);
  147.         }
  148.         strcpy(pProp->PropFileName, newname);
  149.         }
  150.     pProp = pProp->NextProp;
  151.     }
  152.  
  153.     
  154.     if (toascii)
  155.     type = OFF_ASCII; 
  156.     else
  157.     type = OFF_BINARY; 
  158.     OFFWriteObj(&obj, outfilename, outdir, type);
  159.     }
  160.  
  161.  
  162. basename(fullname, dir, base, ext)
  163.     char    *fullname;
  164.     char    *dir;
  165.     char    *base;
  166.     char    *ext;
  167.  
  168.     {
  169.     int        i, j;
  170.  
  171.     i = strlen(fullname);
  172.     while ((i >= 0) && (fullname[i] != '.')) i--;
  173.     if (i < 0)
  174.     { i = 0; ext[0] = '\0'; }
  175.     else
  176.     strcpy(ext, &(fullname[i + 1]));
  177.        
  178.     j = i;
  179.     while ((j >= 0) && (fullname[j] != '/')) j--;
  180.     if (j < 0)
  181.     { dir[0] = '\0'; }
  182.     else
  183.     {
  184.     strncpy(dir, fullname, j);
  185.     dir[j] = '\0';
  186.     }
  187.  
  188.     if ((j <= 0) && (i == 0))
  189.     strcpy(base, fullname);
  190.     else
  191.     {
  192.     strncpy(base, &(fullname[j + 1]), i - j - 1);
  193.     base[i - j - 1] = '\0';
  194.     }
  195.     }
  196.  
  197.  
  198. /* Some types needed for the normal generation.  We should probably
  199. **  stick these in a header file.
  200. */
  201. typedef float float32_t;
  202. typedef short int16_t;
  203. typedef long  int32_t;
  204. typedef struct { float32_t x, y, z } Point;
  205. typedef struct { float32_t dx, dy, dz } Normal;
  206. typedef struct { int32_t count; Normal n[1] } NormalProperty;
  207.  
  208.  
  209. AddNormals( basename, obj )
  210. char *basename;
  211. OFFObjDesc *obj;
  212. {
  213.   OFFProperty *gprop = NULL, *pnprop = NULL, *op;
  214.   int nv, np, ne;
  215.   NormalProperty *normals;
  216.   Normal *normal;
  217.   Point *vertices;
  218.   int16_t *edges;
  219.   int16_t *nedges;
  220.   int clockwise = 1;
  221.   int i, start, end, j, vi, vj, p, n;
  222.   char *ptr;
  223.   double len;
  224.  
  225.   /*  Find the "geometery" property and the vertex_order property*/
  226.   for( op = obj->FirstProp; op; op = op->NextProp) {
  227.     if (strcmp( op->PropName, "geometry") == 0)
  228.       gprop = op;
  229.     else if (strcmp( op->PropName, "vertex_order") == 0) {
  230.       if (strcmp( *((char **) op->PropData), "clockwise")) 
  231.     clockwise = 1;
  232.       else if (strcmp( *((char **) op->PropData), "counter-clockwise"))
  233.     clockwise = 0;
  234.       else {
  235.     fprintf( stderr, "Invalid vertex order: %s\n", *((char **) op->PropData));
  236.     exit(-1);
  237.       }
  238.     }
  239.   }
  240.  
  241.   /* Remove any existing polygon normals property */
  242.   OFFRemoveProperty( obj, "polygon_normals" );
  243.  
  244.   /* Get the geometry data */
  245.   ptr = gprop->PropData;
  246.   
  247.   /* extract the counts */
  248.   nv = *( (int32_t *) ptr); ptr += sizeof(int32_t);
  249.   np = *( (int32_t *) ptr); ptr += sizeof(int32_t);
  250.   ne = *( (int32_t *) ptr); ptr += sizeof(int32_t);
  251.  
  252.  
  253.   /* Get the vertex data */
  254.   vertices = (Point *) ptr;
  255.   ptr += 3*nv*sizeof(float32_t);
  256.  
  257.   /* Get the edge-per-polygon counts */
  258.   nedges = (int16_t *) ptr;
  259.   ptr += np * sizeof(int16_t);
  260.  
  261.   /* Get the edge data */
  262.   edges = (int16_t *) ptr;
  263.   ptr += ne *sizeof(int16_t);
  264.  
  265.   /* Allocate memory for the normals */
  266.   normals = (NormalProperty *) malloc( np * sizeof(Normal) + sizeof(int16_t) );
  267.   if (normals == NULL) {
  268.     perror( "Out of memory!\n" );
  269.     exit(-1);
  270.   }
  271.   normals->count = np;
  272.  
  273.   /* Add a new polygon_normals property */
  274.   pnprop = OFFAddProperty( obj );
  275.   if (pnprop == NULL)  {
  276.     perror( "Out of memory!\n" );
  277.     exit(-1);
  278.   }
  279.  
  280.   /* Set up the property */
  281.   strcpy( pnprop->PropName, "polygon_normals" );
  282.   pnprop->PropType = OFF_GENERIC_DATA;
  283.   strcpy( pnprop->PropFileName, basename );
  284.   strcat( pnprop->PropFileName, ".pnorm" );
  285.   pnprop->PropCount = np;
  286.   strcpy( pnprop->DataFormat, "fff" );
  287.   pnprop->PropData = (char *) normals;
  288.  
  289.   /* Loop through all the polygons computing normals as we go */
  290.   i=0;
  291.   for(p=0; p<np; p++) {
  292.     n = nedges[p];
  293.     start = i;
  294.     end = i + n;
  295.     normal = normals->n +p;
  296.     normal->dx = normal->dy = normal->dz = 0.0;
  297.     for( j=i+1; i < end; i++, j++) {
  298.       if (j == end) j = start;
  299.       vi = edges[ i ] -1;
  300.       vj = edges[ j ] -1;
  301.  
  302.       /* Martin Newell's method:  Newman & Sproull page 499
  303.       ** More robust than the 3 point method.  
  304.       */
  305.       normal->dx += (vertices[vi].y - vertices[vj].y)*
  306.                       (vertices[vi].z + vertices[vj].z);
  307.       normal->dy += (vertices[vi].z - vertices[vj].z)*
  308.                       (vertices[vi].x + vertices[vj].x);
  309.       normal->dz += (vertices[vi].x - vertices[vj].x)*
  310.                       (vertices[vi].y + vertices[vj].y);
  311.     }
  312.     len = sqrt( normal->dx * normal->dx +
  313.              normal->dy * normal->dy +
  314.             normal->dz * normal->dz );
  315.     if (len > 0) {        /* Normalize length */
  316.       normal->dx /= len;
  317.       normal->dy /= len;
  318.       normal->dz /= len;
  319.     }
  320.     if (!clockwise) {        /* Flip the normal */
  321.       normal->dx = -normal->dx;
  322.       normal->dy = -normal->dy;
  323.       normal->dz = -normal->dz;
  324.     }
  325.   }
  326. }
  327.  
  328.  
  329. /* Undocumented option */
  330.  
  331. AdjustVertexNums(obj)
  332.     OFFObjDesc *obj;
  333.     {
  334.     OFFProperty *gprop = NULL, *op;
  335.     int        nv, np, ne;
  336.     int        i;
  337.     char    *ptr;
  338.     int16_t    *edges;
  339.  
  340. /*  Find the "geometery" property and the vertex_order property  */
  341.     for (op = obj->FirstProp; op; op = op->NextProp)
  342.     {
  343.     if (strcmp(op->PropName, "geometry") == 0)
  344.         gprop = op;
  345.     }
  346.  
  347. /*  Get the geometry data */
  348.     ptr = gprop->PropData;
  349.   
  350. /*  extract the counts */
  351.     nv = *((int32_t *) ptr); ptr += sizeof(int32_t);
  352.     np = *((int32_t *) ptr); ptr += sizeof(int32_t);
  353.     ne = *((int32_t *) ptr); ptr += sizeof(int32_t);
  354.  
  355. /*  Get the edge data */
  356.     ptr += 3*nv*sizeof(float32_t);
  357.     ptr += np * sizeof(int16_t);
  358.     edges = (int16_t *) ptr;
  359.  
  360. /*  Decrement each vertex number by 1  */
  361.     for (i = 0; i < ne; i++)
  362.     {
  363.     (*edges)--;
  364.     edges++;
  365.     }
  366.     }
  367.