/* Copyright Jeff Lassahn.  See graph3d.tex for details. */#include "liftio.h"#include <stdlib.h>#include <math.h>/* I/O primitives */static FILE *myfp;int PutInt(long x){int i;	for (i=0;i<4;i++) {		if (EOF==putc(x&0xFF,myfp)) return 0;		x>>=8;	}	return 1;}int PutFloat(float x){long n;int i;	n=(long)(frexp(x,&i)*0x00400000L)&0x00FFFFFFL;	n|=((long)i<<24);	return PutInt(n);;}int PutByte(int x){	if (EOF==putc(x&0xFF,myfp)) return 0;	return 1;}int PutTag(char *x){int i;	for (i=0;i<4;i++) {		if (EOF==putc(x[i],myfp)) return 0;	}	return 1;}int GetInt(int *x){int i;int c;	*x=0;	for (i=0;i<4;i++) {		c=getc(myfp);		if (c==EOF) return 0;		*x|=((long)c)<<(i*8);	}	return 1;}int GetFloat(float *x){int i;int c;long n;	n=0;	for (i=0;i<3;i++) {		c=getc(myfp);		if (c==EOF) return 0;		n|=((long)c)<<(i*8);	}	if (n&0x00800000L)		n|=-0x01000000L;	c=getc(myfp);	if (c==EOF) return 0;	c=(int)(signed char)c;	*x=ldexp(n,c-22);	return 1;}int GetByte(unsigned char *x){int c;	c=getc(myfp);	if (c==EOF) return 0;	*x=c;	return 1;}int GetTag(char *x){int i,c;	for (i=0;i<4;i++) {		c=getc(myfp);		if (c==EOF) return 0;		x[i]=c;	}	return 1;}/* FILE FORMAT for parts:	tag "PART"	int nwindows	int nvertices	PG_OBJECTPART		float detail;		int npolys;		PG_POLYGON [npolys]			int nverts			int verts [nverts]		PG_VECTOR [npolys]			float x,y,z		PIX_RGB32 [npolys]			byte r,g,b,a		int npoints;		PG_VECTOR [npoints]			float x,y,z		PG_POLYGON [nwindows]			int nverts			int verts [nverts]		PG_VECTOR [nwindows]			float x,y,z*/void StartFile(FILE *fp){	myfp=fp;}void FreePart(OBJECTPART *p){	if (p->verts)		free(p->verts);	if (p->part.polys)		free(p->part.polys);	if (p->part.norms)		free(p->part.norms);	if (p->part.colors)		free(p->part.colors);	if (p->part.points)		free(p->part.points);	if (p->part.windows)		free(p->part.windows);	if (p->part.wnorms)		free(p->part.wnorms);}/* note: ReadPart doesn't read the tag at the front of the part,because later we'll want a master read function wich reads the tagand calls the correct reader. */int ReadPart(OBJECTPART *p,FILE *fp){int i,j,vp;	StartFile(fp);	p->verts=NULL;	p->part.polys=NULL;	p->part.norms=NULL;	p->part.colors=NULL;	p->part.points=NULL;	p->part.windows=NULL;	p->part.wnorms=NULL;	if (!GetInt(&(p->nwindows))) goto die;	if (!GetInt(&(p->nverts))) goto die;	if (p->nverts<0) goto die;	if (p->nverts>0) {		p->verts=malloc(p->nverts*sizeof(int));		if (!p->verts) goto die;	}	vp=0;	if (!GetFloat(&(p->part.detail))) goto die;	if (!GetInt(&(p->part.npolys))) goto die;	if (p->part.npolys<0) goto die;	if (p->part.npolys>0) {		p->part.polys=malloc(p->part.npolys*sizeof(PG_POLYGON));		if (!p->part.polys) goto die;		p->part.norms=malloc(p->part.npolys*sizeof(PG_VECTOR));		if (!p->part.norms) goto die;		p->part.colors=malloc(p->part.npolys*sizeof(PIX_RGB32));		if (!p->part.colors) goto die;	}	for (i=0;i<p->part.npolys;i++) {		if (!GetInt(&(p->part.polys[i].n))) goto die;		p->part.polys[i].points=&(p->verts[vp]);		for (j=0;j<p->part.polys[i].n;j++) {			if (!GetInt(&(p->verts[vp]))) goto die;			vp++;		}	}	for (i=0;i<p->part.npolys;i++) {		if (!GetFloat(&(p->part.norms[i].x))) goto die;		if (!GetFloat(&(p->part.norms[i].y))) goto die;		if (!GetFloat(&(p->part.norms[i].z))) goto die;	}	for (i=0;i<p->part.npolys;i++) {		if (!GetByte(&(p->part.colors[i].red))) goto die;		if (!GetByte(&(p->part.colors[i].green))) goto die;		if (!GetByte(&(p->part.colors[i].blue))) goto die;		if (!GetByte(&(p->part.colors[i].alpha))) goto die;	}	if (!GetInt(&(p->part.npoints))) goto die;	if (p->part.npoints<0) goto die;	if (p->part.npoints>0) {		p->part.points=malloc(p->part.npoints*sizeof(PG_VECTOR));		if (!p->part.points) goto die;	}	for (i=0;i<p->part.npoints;i++) {		if (!GetFloat(&(p->part.points[i].x))) goto die;		if (!GetFloat(&(p->part.points[i].y))) goto die;		if (!GetFloat(&(p->part.points[i].z))) goto die;	}	if (p->nwindows>0) {		p->part.windows=malloc(p->nwindows*sizeof(PG_POLYGON));		if (!p->part.windows) goto die;		p->part.wnorms=malloc(p->nwindows*sizeof(PG_VECTOR));		if (!p->part.wnorms) goto die;	}	for (i=0;i<p->nwindows;i++) {		if (!GetInt(&(p->part.windows[i].n))) goto die;		p->part.windows[i].points=&(p->verts[vp]);		for (j=0;j<p->part.windows[i].n;j++) {			if (!GetInt(&(p->verts[vp]))) goto die;			vp++;		}	}	for (i=0;i<p->nwindows;i++) {		if (!GetFloat(&(p->part.wnorms[i].x))) goto die;		if (!GetFloat(&(p->part.wnorms[i].y))) goto die;		if (!GetFloat(&(p->part.wnorms[i].z))) goto die;	}	return 1;die:	FreePart(p);	return 0;}int WritePart(OBJECTPART *p,FILE *fp){int i,j;	StartFile(fp);	if (!PutTag("PART")) return 0;	if (!PutInt(p->nwindows)) return 0;	if (!PutInt(p->nverts)) return 0;	if (!PutFloat(p->part.detail)) return 0;	if (!PutInt(p->part.npolys)) return 0;	for (i=0;i<p->part.npolys;i++) {		if (!PutInt(p->part.polys[i].n)) return 0;		for (j=0;j<p->part.polys[i].n;j++) {			if (!PutInt(p->part.polys[i].points[j])) return 0;		}	}	for (i=0;i<p->part.npolys;i++) {		if (!PutFloat(p->part.norms[i].x)) return 0;		if (!PutFloat(p->part.norms[i].y)) return 0;		if (!PutFloat(p->part.norms[i].z)) return 0;	}	for (i=0;i<p->part.npolys;i++) {		if (!PutByte(p->part.colors[i].red)) return 0;		if (!PutByte(p->part.colors[i].green)) return 0;		if (!PutByte(p->part.colors[i].blue)) return 0;		if (!PutByte(p->part.colors[i].alpha)) return 0;	}	if (!PutInt(p->part.npoints)) return 0;	for (i=0;i<p->part.npoints;i++) {		if (!PutFloat(p->part.points[i].x)) return 0;		if (!PutFloat(p->part.points[i].y)) return 0;		if (!PutFloat(p->part.points[i].z)) return 0;	}	for (i=0;i<p->nwindows;i++) {		if (!PutInt(p->part.windows[i].n)) return 0;		for (j=0;j<p->part.windows[i].n;j++) {			if (!PutInt(p->part.windows[i].points[j])) return 0;		}	}	for (i=0;i<p->nwindows;i++) {		if (!PutFloat(p->part.wnorms[i].x)) return 0;		if (!PutFloat(p->part.wnorms[i].y)) return 0;		if (!PutFloat(p->part.wnorms[i].z)) return 0;	}	return 1;}