home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * Name
- * offconv
- *
- * Description
- * Convert off (Object File Format) files from ASCII to binary
- * and vice versa.
- * Optionally, ``pack'' the geometry to improve file size and
- * rendering speed.
- * Optionally adds per polygon normals.
- * Optionally decrements vertex numbers so they begin at 0.
- *
- * Author
- * Randi J. Rost
- * Digital Equipment Corp.
- * Workstation Systems Engineering
- * Palo Alto, CA
- *
- * Packing option added by Allen Akin, also of WSE
- *
- * Diagnostics
- * Returns -1 if it blows up for any reason
- *
- * History
- * Randi J. Rost 14-Nov-1986 created
- * Allen Akin 19-Feb-1987 packing option added
- * James Painter 10-Aug-1988 Per polygon normals added
- * Randi J. Rost 8-Aug-1989 vertex number adjustment option added
- *
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "off.h"
-
- extern double sqrt();
- static char *ProgramName;
- static int toascii = 1, addnormals = 0, pack = 0, adjust = 0;
- char *infilename = NULL, *outfilename;
-
- Usage()
- {
- fprintf(stderr, "usage: %s [-a][-b][p-][-n] inobj outobj\n", ProgramName );
- }
-
-
- ParseCommandLine(argc, argv)
- int argc;
- char *argv[];
- {
- int ArgsParsed = 0;
- char *sw;
-
- ProgramName = argv[ArgsParsed++];
-
- while ( ArgsParsed < argc ) {
- if (argv[ArgsParsed][0] == '-')
- {
- sw = argv[ArgsParsed++] + 1;
- for( ; *sw != '\0'; sw++) {
- switch (*sw)
- {
- case 'a': toascii = 1; break;
- case 'b': toascii = 0; break;
- case 'n': addnormals = 1; break;
- case 'p': pack = 1; break;
- case '1': adjust = 1; break; /* undocumented option */
- default:
- fprintf(stderr, "Unknown option '%s'\n\n", *sw );
- Usage();
- exit(-1);
- }
- }
- } else {
- if (infilename != NULL) {
- if (outfilename != NULL) {
- Usage(); exit(-1);
- }
- outfilename = argv[ArgsParsed++];
- } else
- infilename = argv[ArgsParsed++];
- }
- }
- if (infilename == NULL || outfilename == NULL) {
- Usage(); exit(-1);
- }
- }
-
-
- main(argc, argv)
- int argc;
- char *argv[];
-
- {
- OFFObjDesc obj;
- char inbase[80], outbase[80];
- char indir[80], outdir[80];
- char inext[80], outext[80];
- char newname[80];
- int i;
- int type;
- char dir[80], base[80], ext[80];
- OFFProperty *pProp;
-
-
- ParseCommandLine( argc, argv );
-
- if (-1 == OFFReadObj(&obj, infilename ) )
- exit(-1);
-
- basename(infilename, indir, inbase, inext);
- basename(outfilename, outdir, outbase, outext);
- if (addnormals)
- AddNormals( outbase, &obj );
- if (pack)
- OFFPackObj(&obj);
- if (adjust)
- AdjustVertexNums(&obj);
-
- pProp = obj.FirstProp;
- while (pProp != NULL)
- {
- if (pProp->PropFileName != NULL)
- {
- basename(pProp->PropFileName, dir, base, ext);
- if (toascii)
- {
- strcpy(newname, outbase);
- strcat(newname, ".");
-
- /* The following kludge will not work if there are valid */
- /* ASCII file extensions that begin with 'b'. Right now */
- /* we assume that if the extension begins with 'b', the */
- /* file is in binary. */
-
- if (ext[0] == 'b')
- strcat(newname, &(ext[1]));
- else
- strcat(newname, ext);
- }
- else
- {
- strcpy(newname, outbase);
- strcat(newname, ".b");
- strcat(newname, ext);
- }
- strcpy(pProp->PropFileName, newname);
- }
- pProp = pProp->NextProp;
- }
-
-
- if (toascii)
- type = OFF_ASCII;
- else
- type = OFF_BINARY;
- OFFWriteObj(&obj, outfilename, outdir, type);
- }
-
-
- basename(fullname, dir, base, ext)
- char *fullname;
- char *dir;
- char *base;
- char *ext;
-
- {
- int i, j;
-
- i = strlen(fullname);
- while ((i >= 0) && (fullname[i] != '.')) i--;
- if (i < 0)
- { i = 0; ext[0] = '\0'; }
- else
- strcpy(ext, &(fullname[i + 1]));
-
- j = i;
- while ((j >= 0) && (fullname[j] != '/')) j--;
- if (j < 0)
- { dir[0] = '\0'; }
- else
- {
- strncpy(dir, fullname, j);
- dir[j] = '\0';
- }
-
- if ((j <= 0) && (i == 0))
- strcpy(base, fullname);
- else
- {
- strncpy(base, &(fullname[j + 1]), i - j - 1);
- base[i - j - 1] = '\0';
- }
- }
-
-
- /* Some types needed for the normal generation. We should probably
- ** stick these in a header file.
- */
- typedef float float32_t;
- typedef short int16_t;
- typedef long int32_t;
- typedef struct { float32_t x, y, z } Point;
- typedef struct { float32_t dx, dy, dz } Normal;
- typedef struct { int32_t count; Normal n[1] } NormalProperty;
-
-
- AddNormals( basename, obj )
- char *basename;
- OFFObjDesc *obj;
- {
- OFFProperty *gprop = NULL, *pnprop = NULL, *op;
- int nv, np, ne;
- NormalProperty *normals;
- Normal *normal;
- Point *vertices;
- int16_t *edges;
- int16_t *nedges;
- int clockwise = 1;
- int i, start, end, j, vi, vj, p, n;
- char *ptr;
- double len;
-
- /* Find the "geometery" property and the vertex_order property*/
- for( op = obj->FirstProp; op; op = op->NextProp) {
- if (strcmp( op->PropName, "geometry") == 0)
- gprop = op;
- else if (strcmp( op->PropName, "vertex_order") == 0) {
- if (strcmp( *((char **) op->PropData), "clockwise"))
- clockwise = 1;
- else if (strcmp( *((char **) op->PropData), "counter-clockwise"))
- clockwise = 0;
- else {
- fprintf( stderr, "Invalid vertex order: %s\n", *((char **) op->PropData));
- exit(-1);
- }
- }
- }
-
- /* Remove any existing polygon normals property */
- OFFRemoveProperty( obj, "polygon_normals" );
-
- /* Get the geometry data */
- ptr = gprop->PropData;
-
- /* extract the counts */
- nv = *( (int32_t *) ptr); ptr += sizeof(int32_t);
- np = *( (int32_t *) ptr); ptr += sizeof(int32_t);
- ne = *( (int32_t *) ptr); ptr += sizeof(int32_t);
-
-
- /* Get the vertex data */
- vertices = (Point *) ptr;
- ptr += 3*nv*sizeof(float32_t);
-
- /* Get the edge-per-polygon counts */
- nedges = (int16_t *) ptr;
- ptr += np * sizeof(int16_t);
-
- /* Get the edge data */
- edges = (int16_t *) ptr;
- ptr += ne *sizeof(int16_t);
-
- /* Allocate memory for the normals */
- normals = (NormalProperty *) malloc( np * sizeof(Normal) + sizeof(int16_t) );
- if (normals == NULL) {
- perror( "Out of memory!\n" );
- exit(-1);
- }
- normals->count = np;
-
- /* Add a new polygon_normals property */
- pnprop = OFFAddProperty( obj );
- if (pnprop == NULL) {
- perror( "Out of memory!\n" );
- exit(-1);
- }
-
- /* Set up the property */
- strcpy( pnprop->PropName, "polygon_normals" );
- pnprop->PropType = OFF_GENERIC_DATA;
- strcpy( pnprop->PropFileName, basename );
- strcat( pnprop->PropFileName, ".pnorm" );
- pnprop->PropCount = np;
- strcpy( pnprop->DataFormat, "fff" );
- pnprop->PropData = (char *) normals;
-
- /* Loop through all the polygons computing normals as we go */
- i=0;
- for(p=0; p<np; p++) {
- n = nedges[p];
- start = i;
- end = i + n;
- normal = normals->n +p;
- normal->dx = normal->dy = normal->dz = 0.0;
- for( j=i+1; i < end; i++, j++) {
- if (j == end) j = start;
- vi = edges[ i ] -1;
- vj = edges[ j ] -1;
-
- /* Martin Newell's method: Newman & Sproull page 499
- ** More robust than the 3 point method.
- */
- normal->dx += (vertices[vi].y - vertices[vj].y)*
- (vertices[vi].z + vertices[vj].z);
- normal->dy += (vertices[vi].z - vertices[vj].z)*
- (vertices[vi].x + vertices[vj].x);
- normal->dz += (vertices[vi].x - vertices[vj].x)*
- (vertices[vi].y + vertices[vj].y);
- }
- len = sqrt( normal->dx * normal->dx +
- normal->dy * normal->dy +
- normal->dz * normal->dz );
- if (len > 0) { /* Normalize length */
- normal->dx /= len;
- normal->dy /= len;
- normal->dz /= len;
- }
- if (!clockwise) { /* Flip the normal */
- normal->dx = -normal->dx;
- normal->dy = -normal->dy;
- normal->dz = -normal->dz;
- }
- }
- }
-
-
- /* Undocumented option */
-
- AdjustVertexNums(obj)
- OFFObjDesc *obj;
- {
- OFFProperty *gprop = NULL, *op;
- int nv, np, ne;
- int i;
- char *ptr;
- int16_t *edges;
-
- /* Find the "geometery" property and the vertex_order property */
- for (op = obj->FirstProp; op; op = op->NextProp)
- {
- if (strcmp(op->PropName, "geometry") == 0)
- gprop = op;
- }
-
- /* Get the geometry data */
- ptr = gprop->PropData;
-
- /* extract the counts */
- nv = *((int32_t *) ptr); ptr += sizeof(int32_t);
- np = *((int32_t *) ptr); ptr += sizeof(int32_t);
- ne = *((int32_t *) ptr); ptr += sizeof(int32_t);
-
- /* Get the edge data */
- ptr += 3*nv*sizeof(float32_t);
- ptr += np * sizeof(int16_t);
- edges = (int16_t *) ptr;
-
- /* Decrement each vertex number by 1 */
- for (i = 0; i < ne; i++)
- {
- (*edges)--;
- edges++;
- }
- }
-