[comp.graphics] nff filter for redundant polygon vertices

pkh@vap.vi.ri.cmu.edu (Ping Kang Hsiung) (12/14/88)

I am posting the source code since among the people
who requested for the source code, two of them are
not reach-able from my system. Fortunately it's not a
big program. Sorry for the inconvenience.
***
/*
 * program: nfff.c
 *
 *	a filter for NFF (Neutral File Format)
 *	nfff [infile]
 *	input: infile.nff or stdin
 *	output: stdout
 *
 * input items other than polygons are copied to output directly.
 * for polygons that have 2 or more identical vertices, the redundant
 * vertices are filtered out and the "p <vert_count>" lines of
 * the polygons are adjusted properly.
 *
 * the vertices degeneration cases occur in data produced by some
 * automatic nff generation program when the resolution/prec. of
 * generation exceeds that of the floating point format.
 *
 * definition of NFF: see nff.def
 * bugs:
 *	(1) handles polygons only. break if there are other obj. types
 *	(2) MAX_VERT may cause trouble
 *
 * Fri Dec  2 16:41:27 EST 1988
 * pkh@vap
 *
 * bugs fixed:
 *
 */
#include	<stdio.h>
#include	<math.h>
/* #include	"/usr/pkh/include/all.h" */
/* #include	"/usr/pkh/include/def3d.h" */

/* from "def3d.h" */
typedef struct pt3d_struct {
	float x, y, z;
} pt3d, *pt3d_t;
#define	FPRINT3d(fp, pt, newline) do { \
	if (newline) \
		fprintf(fp, "%g %g %g\n", pt.x, pt.y, pt.z); \
	else \
		fprintf(fp, "%g %g %g", pt.x, pt.y, pt.z); \
} while (0)
#define FSCAN3d(fp, pt) do { \
	fscanf(fp,"%f %f %f", &(pt.x), &(pt.y), &(pt.z)); \
} while(0)
#define ASSIGN3d(p0, p1) do {p0.x=p1.x; p0.y=p1.y; p0.z=p1.z;} while(0)
#define EQ3d(p0, p1) ((p0.x==p1.x)&&(p0.y==p1.y)&& (p0.z==p1.z))

/* from "all.h" */
int	debug;
#define POW2(y)		(1<<y)
#define	ERROR_MSG_LENGTH	(200)
#define DEBUG(arg) \
do { \
	char msg[ERROR_MSG_LENGTH]; \
	if (debug) { \
		sprintf arg; \
	 	fprintf(stderr, "%s", msg); \
	} \
} while (0)
#define ERROR(arg) \
do { \
	char msg[ERROR_MSG_LENGTH]; \
		sprintf arg; \
	 	fprintf(stderr, "%s", msg); \
		exit(0); \
} while (0)

#define		MAX_VERT	POW2(12)	/* 4k verts per poly */
pt3d *v;	/* array of dim MAX_VERT */

FILE	*nfffile;
char	infile[25];

/*
 * for statistics
 */
int	total_byte;	/* total byte allocated */
int	poly_id;

/*
 * copy to end of line
 */
copy_line(ifp, ofp)
FILE *ifp, *ofp;
{
	char c;
	do {
		putc((c=getc(ifp)), ofp);
	} while (c!='\n');
}

int read_poly(fp)
FILE *fp;
{
	int             tv;
	int             i;

	fscanf(fp, "%d", &tv);

	for (i = 0; i < tv; i++) {
		FSCAN3d(fp,(v[i]));
	}
	return (tv);
}

/*
 * filter out degenerated (redundant) vertices
 * and return the true vert count.
 * complain when polygon has less than 3 vert
 */
int vert_filter(in_vert)
int in_vert;
{
	int             head, tail;
	int             tv, skip;

	/*
	 * filter out degenerated vertices. head points to the verified vert,
	 * tail scans down the vert list for new vert.
	 */
	head = 0;		/* points to v[0] */
	tail = head + 1;	/* points to v[1] */
	tv = 1;			/* count one vert already (v[0]) */
	skip = 0;		/* "skip occured" flag */
	do {
		while (EQ3d((v[head]), (v[tail]))) {
			tail++;
			if (tail == in_vert)
				goto last_vert;
			skip = 1;
		}
		if (skip) {
			ASSIGN3d((v[head + 1]), (v[tail]));
		}
		head++;
		tail++;
	} while (tail < in_vert);

	/* head now points to the last valid vert. compare last and first */
last_vert:if (EQ3d((v[0]), v[head]))
		tv = head;
	else
		tv = head + 1;
	if (tv < 3) {
		ERROR((msg, "poly %d has less than 3 vert\n", poly_id));
		write_polygon(stderr, tv);	/* write vert */
	}
	if (debug) {
		write_polygon(stderr, tv);	/* write vert */
	}
	return (tv);
}

/*
 * write out the cleaned-up polygons in nff format
 * also print out the poly id
 */
write_polygon(fp, ply_vert)
FILE *fp;
int ply_vert;
{
	int             j;

	fprintf(fp, "# p%d\np %d\n", poly_id, ply_vert);
	for (j = 0; j < ply_vert; j++) {
		FPRINT3d(fp, (v[j]), 0);
		fprintf(fp, "\n");
	}
}

/*
 * for polygons: read-filter-write
 * for the rest: read-write
 */
read_write(ifp, ofp)
FILE *ifp, *ofp;
{
	char            key[20];
	int             in_vert, out_vert;

	/* read "key" */
	while (fscanf(ifp, "%s", key) != EOF) {

		DEBUG((msg, "get key %s\n", key));
		if (strcmp(key, "p") == 0) {
			in_vert = read_poly(ifp);
			out_vert = vert_filter(in_vert);
			write_polygon(ofp, out_vert);
			poly_id++;
		} else {
			fprintf(ofp, "%s ", key);
			copy_line(ifp, ofp);
		}
	};
}

init()
{
	int             new_byte;

	new_byte = sizeof(pt3d) * MAX_VERT;
	total_byte += new_byte;
	v = (pt3d_t) malloc(new_byte);
	DEBUG((msg, "v alloc %3dB; total %5dB\n", new_byte, total_byte));
	if (v == NULL)
		ERROR((msg, "v array alloc err\n"));

	poly_id = 0;
}

main(argc, argv)
int	argc;
char	*argv[];
{
	if (argc == 1) {
		nfffile= stdin;
	}
	else if (argc == 2) {
		/* append .nff suffix */
		sprintf(infile, "%s.nff", argv[1]);
		if ((nfffile= fopen(infile, "r")) == NULL) {
			ERROR((msg, "input file %s not found\n", infile));
			exit(1);
		}
	} else {
		ERROR((msg, "Usage: %s [file].nff\n", argv[0]));
		exit(1);
	}

	debug = 0;

	init();

	fprintf(stdout, "#\n# polygons filtered by nfffilter program\n");
	fprintf(stdout, "# date:\n#\n");
	read_write(nfffile, stdout);
}
--