// Copyright (c) 1998 Relic Entertainment Inc. // Written by Janik Joire // // $History: $ #include #include #include #include #include "lwob.h" // Integer read/write functions (Motorola byte order) short RBMShort(FILE *pStream) { short nVal; nVal=(short)fgetc(pStream); nVal=(nVal<<8)|(short)fgetc(pStream); return(nVal); } long RBMLong(FILE *pStream) { long nVal; nVal=(long)fgetc(pStream); nVal=(nVal<<8)|(long)fgetc(pStream); nVal=(nVal<<8)|(long)fgetc(pStream); nVal=(nVal<<8)|(long)fgetc(pStream); return(nVal); } float RBMIeee(FILE *pStream) { float fVal; long nVal; nVal=(long)fgetc(pStream); nVal=(nVal<<8)|(long)fgetc(pStream); nVal=(nVal<<8)|(long)fgetc(pStream); nVal=(nVal<<8)|(long)fgetc(pStream); memcpy(&fVal,&nVal,sizeof(float)); return(fVal); } short WBMShort(short nVal,FILE *pStream) { fputc(nVal>>8,pStream); fputc(nVal&0xFF,pStream); return(nVal); } long WBMLong(long nVal,FILE *pStream) { fputc(nVal>>24,pStream); fputc((nVal>>16)&0xFF,pStream); fputc((nVal>>8)&0xFF,pStream); fputc(nVal&0xFF,pStream); return(nVal); } // IEEE floating-point read/writefunctions double ReadIeeeExtended(FILE *pStream) { char aBytes[10]; fread(aBytes,1,10,pStream); return(ConvertFromIeeeExtended(aBytes)); } int WriteIeeeExtended(FILE *pStream,double fNum) { char aBytes[10]; ConvertToIeeeExtended(aBytes,fNum); fwrite(aBytes,1,10,pStream); return(OK); } /* Copyright (C) 1988-1991 Apple Computer, Inc. * All rights reserved. * * Machine-independent I/O routines for IEEE floating-point numbers. * * NaN's and infinities are converted to HUGE_VAL or HUGE, which * happens to be infinity on IEEE machines. Unfortunately, it is * impossible to preserve NaN's in a machine-independent way. * Infinities are, however, preserved on IEEE machines. * * These routines have been tested on the following machines: * Apple Macintosh, MPW 3.1 C compiler * Apple Macintosh, THINK C compiler * Silicon Graphics IRIS, MIPS compiler * Cray X/MP and Y/MP * Digital Equipment VaVerts * * * Implemented by Malcolm Slaney and Ken Turkowski. * * Malcolm Slaney contributions during 1988-1990 include big- and little- * endian file I/O, conversion to and from Motorola's extended 80-bit * floating-point format, and conversions to and from IEEE single- * precision floating-point format. * * In 1991, Ken Turkowski implemented the conversions to and from * IEEE double-precision format, added more precision to the extended * conversions, and accommodated conversions involving +/- infinity, * NaN's, and denormalized numbers. */ int ConvertToIeeeExtended(char *bytes,double num) { short sign; short expon; double fMant,fsMant; unsigned long hiMant,loMant; if(num < 0) { sign=(short)0x8000; num*=-1; } else sign = 0; if(num == 0) { expon=0; hiMant=0; loMant=0; } else { fMant=frexp(num,(int *)&expon); if((expon > 16384) || !(fMant < 1)) // Infinity or NaN { expon=sign|0x7FFF; hiMant=0; loMant=0; // Infinity } else // Finite { expon+=16382; if(expon < 0) // Denormalized { fMant=ldexp(fMant,expon); expon=0; } expon|=sign; fMant=ldexp(fMant,32); fsMant=floor(fMant); hiMant=FloatToUnsigned(fsMant); fMant=ldexp(fMant-fsMant,32); fsMant=floor(fMant); loMant=FloatToUnsigned(fsMant); } } bytes[0]=(char)(expon>>8); bytes[1]=(char)expon; bytes[2]=(char)(hiMant>>24); bytes[3]=(char)(hiMant>>16); bytes[4]=(char)(hiMant>>8); bytes[5]=(char)hiMant; bytes[6]=(char)(loMant>>24); bytes[7]=(char)(loMant>>16); bytes[8]=(char)(loMant>>8); bytes[9]=(char)loMant; return(OK); } double ConvertFromIeeeExtended(char *bytes) { double f; short expon; unsigned long hiMant,loMant; expon=((bytes[0]&0x7F)<<8)|(bytes[1]&0xFF); hiMant=((unsigned long)(bytes[2]&0xFF)<<24) |((unsigned long)(bytes[3]&0xFF)<<16) |((unsigned long)(bytes[4]&0xFF)<<8) |((unsigned long)(bytes[5]&0xFF)); loMant=((unsigned long)(bytes[6]&0xFF)<<24) |((unsigned long)(bytes[7]&0xFF)<<16) |((unsigned long)(bytes[8]&0xFF)<<8) |((unsigned long)(bytes[9]&0xFF)); if((expon == 0) && (hiMant == 0) && (loMant == 0)) f=0; else { if (expon == 0x7FFF) // Infinity or NaN f=HUGE_VAL; else { expon-=16383; f=ldexp(UnsignedToFloat(hiMant),expon-=31); f+=ldexp(UnsignedToFloat(loMant),expon-=32); } } if(bytes[0]&0x80) return(-f); else return(f); } // LWOB functions // Function GetLwobData() reads the points and polygons from an LWOB file // Open the file in "rb" mode and call GetLwobData() int GetLwobData(FILE *pStream,short *nVerts,short *nPolys, float **aVerts,short **aPolys) { int nPntsStat,nSrfsStat,nPolsStat; long nInd,nSize,nPos,nRef,nLen; short n,m,nDet,nSurf,nVert,nNum,nData; char aData[LWOB_ID]; *nVerts=0; *nPolys=0; *aVerts=NULL; *aPolys=NULL; nPntsStat=FALSE; nSrfsStat=FALSE; nPolsStat=FALSE; rewind(pStream); if((fread(aData,LWOB_ID,1,pStream) != 1) || (memcmp(aData,"FORM",LWOB_ID) != 0)) return(LWOB_ERR_INVALID); nLen=RBMLong(pStream); if(fread(aData,LWOB_ID,1,pStream) != 1) return(LWOB_ERR_INVALID); if(nLen == 0) { if(memcmp(aData,"MMAN",LWOB_ID) != 0) return(LWOB_ERR_INVALID); } else { if(memcmp(aData,"LWOB",LWOB_ID) != 0) return(LWOB_ERR_INVALID); } while((nPntsStat == FALSE) || (nSrfsStat == FALSE) || (nPolsStat == FALSE)) { if(fread(aData,LWOB_ID,1,pStream) != 1) { if(nPntsStat == FALSE) return(LWOB_ERR_NOPNTS); if(nSrfsStat == FALSE) return(LWOB_ERR_NOSRFS); if(nPolsStat == FALSE) return(LWOB_ERR_NOPOLS); } nSize=RBMLong(pStream); if(nSize%2 > 0) nSize++; nInd=nSize+ftell(pStream); if((nPntsStat == FALSE) && (memcmp(aData,"PNTS",LWOB_ID) == 0)) { *nVerts=nSize/LWOB_PNTS; *aVerts=(float *)calloc(*nVerts*3,sizeof(float)); if(*aVerts == NULL) return(LWOB_ERR_ALLOC); for(n=0;n<*nVerts;n++) { (*aVerts)[n*3]=RBMIeee(pStream); (*aVerts)[(n*3)+1]=RBMIeee(pStream); (*aVerts)[(n*3)+2]=RBMIeee(pStream); } nPntsStat=TRUE; } if((nSrfsStat == FALSE) && (memcmp(aData,"SRFS",LWOB_ID) == 0)) { nSrfsStat=TRUE; } if((nPntsStat == TRUE) && (nPolsStat == FALSE) && (memcmp(aData,"POLS",LWOB_ID) == 0)) { nRef=ftell(pStream); nPos=0; *nPolys=0; while(1) { if(nPos >= nSize) break; nVert=RBMShort(pStream); nPos=nPos+sizeof(short); if(nVert < 1) return(LWOB_ERR_EMPTY); #ifdef LWOB_WARN if(nVert > LWOB_SIZE) return(LWOB_ERR_NOTRGL); #endif for(n=0;n= nSize) break; nVert=RBMShort(pStream); nPos=nPos+sizeof(short); for(m=0;m= nSize) break; nVert=RBMShort(pStream); nPos=nPos+sizeof(short); if(nVert < LWOB_SIZE) nNum=LWOB_SIZE; else nNum=nVert; for(n=0;n= nSize) break; nVert=RBMShort(pStream); nPos=nPos+sizeof(short); for(m=0;m