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