// (c) by Stefan Roettger, licensed under GPL 2+ #include "ddsbase.h" #ifdef HAVE_MINI #include #endif #define DDS_MAXSTR (256) #define DDS_BLOCKSIZE (1<<20) #define DDS_INTERLEAVE (1<<24) #define DDS_RL (7) #define DDS_ISINTEL (*((unsigned char *)(&DDS_INTEL)+1)==0) char DDS_ID[]="DDS v3d\n"; char DDS_ID2[]="DDS v3e\n"; unsigned char *DDS_cache; unsigned int DDS_cachepos,DDS_cachesize; unsigned int DDS_buffer; unsigned int DDS_bufsize; unsigned short int DDS_INTEL=1; // helper functions for DDS: inline unsigned int DDS_shiftl(const unsigned int value,const unsigned int bits) {return((bits>=32)?0:value<=32)?0:value>>bits);} inline void DDS_swapuint(unsigned int *x) { unsigned int tmp=*x; *x=((tmp&0xff)<<24)| ((tmp&0xff00)<<8)| ((tmp&0xff0000)>>8)| ((tmp&0xff000000)>>24); } void DDS_initbuffer() { DDS_buffer=0; DDS_bufsize=0; } inline void DDS_clearbits() { DDS_cache=NULL; DDS_cachepos=0; DDS_cachesize=0; } inline void DDS_writebits(unsigned int value,unsigned int bits) { value&=DDS_shiftl(1,bits)-1; if (DDS_bufsize+bits<32) { DDS_buffer=DDS_shiftl(DDS_buffer,bits)|value; DDS_bufsize+=bits; } else { DDS_buffer=DDS_shiftl(DDS_buffer,32-DDS_bufsize); DDS_bufsize-=32-bits; DDS_buffer|=DDS_shiftr(value,DDS_bufsize); if (DDS_cachepos+4>DDS_cachesize) if (DDS_cache==NULL) { if ((DDS_cache=(unsigned char *)malloc(DDS_BLOCKSIZE))==NULL) MEMERROR(); DDS_cachesize=DDS_BLOCKSIZE; } else { if ((DDS_cache=(unsigned char *)realloc(DDS_cache,DDS_cachesize+DDS_BLOCKSIZE))==NULL) MEMERROR(); DDS_cachesize+=DDS_BLOCKSIZE; } if (DDS_ISINTEL) DDS_swapuint(&DDS_buffer); *((unsigned int *)&DDS_cache[DDS_cachepos])=DDS_buffer; DDS_cachepos+=4; DDS_buffer=value&(DDS_shiftl(1,DDS_bufsize)-1); } } inline void DDS_flushbits() { unsigned int bufsize; bufsize=DDS_bufsize; if (bufsize>0) { DDS_writebits(0,32-bufsize); DDS_cachepos-=(32-bufsize)/8; } } inline void DDS_savebits(unsigned char **data,unsigned int *size) { *data=DDS_cache; *size=DDS_cachepos; } inline void DDS_loadbits(unsigned char *data,unsigned int size) { DDS_cache=data; DDS_cachesize=size; if ((DDS_cache=(unsigned char *)realloc(DDS_cache,DDS_cachesize+4))==NULL) MEMERROR(); *((unsigned int *)&DDS_cache[DDS_cachesize])=0; DDS_cachesize=4*((DDS_cachesize+3)/4); if ((DDS_cache=(unsigned char *)realloc(DDS_cache,DDS_cachesize))==NULL) MEMERROR(); } inline unsigned int DDS_readbits(unsigned int bits) { unsigned int value; if (bits=DDS_cachesize) DDS_buffer=0; else { DDS_buffer=*((unsigned int *)&DDS_cache[DDS_cachepos]); if (DDS_ISINTEL) DDS_swapuint(&DDS_buffer); DDS_cachepos+=4; } DDS_bufsize+=32-bits; value|=DDS_shiftr(DDS_buffer,DDS_bufsize); } DDS_buffer&=DDS_shiftl(1,DDS_bufsize)-1; return(value); } inline int DDS_code(int bits) {return(bits>1?bits-1:bits);} inline int DDS_decode(int bits) {return(bits>=1?bits+1:bits);} // deinterleave a byte stream void DDS_deinterleave(unsigned char *data,unsigned int bytes,unsigned int skip,unsigned int block=0,BOOLINT restore=FALSE) { unsigned int i,j,k; unsigned char *data2,*ptr; if (skip<=1) return; if (block==0) { if ((data2=(unsigned char *)malloc(bytes))==NULL) MEMERROR(); if (!restore) for (ptr=data2,i=0; i4) skip=1; if (strip<1 || strip>65536) strip=1; DDS_deinterleave(data,bytes,skip,block); for (i=-128; i<128; i++) { if (i<=0) for (bits=0; (1<127) act1-=256; bits=lookup[act1+128]; bits=DDS_decode(DDS_code(bits)); if (cnt1==0) { cnt1++; bits1=bits; continue; } if (cnt1<(1<bits2) bits2=bits1; } else { DDS_writebits(cnt2,DDS_RL); DDS_writebits(DDS_code(bits2),3); while (cnt2-->0) { tmp2=*ptr2; if (strip==1 || ptr2-strip<=data) act2=tmp2-pre2; else act2=tmp2-pre2-*(ptr2-strip)+*(ptr2-strip-1); pre2=tmp2; ptr2++; while (act2<-128) act2+=256; while (act2>127) act2-=256; DDS_writebits(act2+(1<bits2) bits2=bits1; } else { DDS_writebits(cnt2,DDS_RL); DDS_writebits(DDS_code(bits2),3); while (cnt2-->0) { tmp2=*ptr2; if (strip==1 || ptr2-strip<=data) act2=tmp2-pre2; else act2=tmp2-pre2-*(ptr2-strip)+*(ptr2-strip-1); pre2=tmp2; ptr2++; while (act2<-128) act2+=256; while (act2>127) act2-=256; DDS_writebits(act2+(1<0) { tmp2=*ptr2; if (strip==1 || ptr2-strip<=data) act2=tmp2-pre2; else act2=tmp2-pre2-*(ptr2-strip)+*(ptr2-strip-1); pre2=tmp2; ptr2++; while (act2<-128) act2+=256; while (act2>127) act2-=256; DDS_writebits(act2+(1<255) act-=256; if ((cnt&(DDS_BLOCKSIZE-1))==0) if (ptr1==NULL) { if ((ptr1=(unsigned char *)malloc(DDS_BLOCKSIZE))==NULL) MEMERROR(); ptr2=ptr1; } else { if ((ptr1=(unsigned char *)realloc(ptr1,cnt+DDS_BLOCKSIZE))==NULL) MEMERROR(); ptr2=&ptr1[cnt]; } *ptr2++=act; cnt++; } } if (ptr1!=NULL) if ((ptr1=(unsigned char *)realloc(ptr1,cnt))==NULL) MEMERROR(); DDS_interleave(ptr1,cnt,skip,block); *data=ptr1; *bytes=cnt; } // write a RAW file void writeRAWfile(const char *filename,unsigned char *data,unsigned int bytes,BOOLINT nofree) { FILE *file; if (bytes<1) ERRORMSG(); if ((file=fopen(filename,"wb"))==NULL) IOERROR(); if (fwrite(data,1,bytes,file)!=bytes) IOERROR(); fclose(file); if (!nofree) free(data); } // read from a RAW file unsigned char *readRAWfiled(FILE *file,unsigned int *bytes) { unsigned char *data; unsigned int cnt,blkcnt; data=NULL; cnt=0; do { if (data==NULL) {if ((data=(unsigned char *)malloc(DDS_BLOCKSIZE))==NULL) MEMERROR();} else if ((data=(unsigned char *)realloc(data,cnt+DDS_BLOCKSIZE))==NULL) MEMERROR(); blkcnt=fread(&data[cnt],1,DDS_BLOCKSIZE,file); cnt+=blkcnt; } while (blkcnt==DDS_BLOCKSIZE); if (cnt==0) { free(data); return(NULL); } if ((data=(unsigned char *)realloc(data,cnt))==NULL) MEMERROR(); *bytes=cnt; return(data); } // read a RAW file unsigned char *readRAWfile(const char *filename,unsigned int *bytes) { FILE *file; unsigned char *data; if ((file=fopen(filename,"rb"))==NULL) return(NULL); data=readRAWfiled(file,bytes); fclose(file); return(data); } // write a Differential Data Stream void writeDDSfile(const char *filename,unsigned char *data, unsigned int bytes,unsigned int skip,unsigned int strip,BOOLINT nofree) { int version=1; FILE *file; unsigned char *chunk; unsigned int size; if (bytes<1) ERRORMSG(); if (bytes>DDS_INTERLEAVE) version=2; if ((file=fopen(filename,"wb"))==NULL) IOERROR(); fprintf(file,"%s",(version==1)?DDS_ID:DDS_ID2); DDS_encode(data,bytes,skip,strip,&chunk,&size,version==1?0:DDS_INTERLEAVE); if (chunk!=NULL) { if (fwrite(chunk,size,1,file)!=1) IOERROR(); free(chunk); } fclose(file); if (!nofree) free(data); } // read a Differential Data Stream unsigned char *readDDSfile(const char *filename,unsigned int *bytes) { int version=1; FILE *file; int cnt; unsigned char *chunk,*data; unsigned int size; if ((file=fopen(filename,"rb"))==NULL) return(NULL); for (cnt=0; DDS_ID[cnt]!='\0'; cnt++) if (fgetc(file)!=DDS_ID[cnt]) { fclose(file); version=0; break; } if (version==0) { if ((file=fopen(filename,"rb"))==NULL) return(NULL); for (cnt=0; DDS_ID2[cnt]!='\0'; cnt++) if (fgetc(file)!=DDS_ID2[cnt]) { fclose(file); return(NULL); } version=2; } if ((chunk=readRAWfiled(file,&size))==NULL) IOERROR(); fclose(file); DDS_decode(chunk,size,&data,bytes,version==1?0:DDS_INTERLEAVE); free(chunk); return(data); } void swapshort(unsigned char *ptr,unsigned int size) { unsigned int i; unsigned char lo,hi; for (i=0; i=data+bytes) ERRORMSG(); while (*ptr1=='#') if (++ptr1>=data+bytes) ERRORMSG(); else while (*ptr1!='\n') if (++ptr1>=data+bytes) ERRORMSG(); } ptr2=ptr1; while (*ptr2!='\n' && *ptr2!=' ') if (++ptr2>=data+bytes) ERRORMSG(); if (++ptr2>=data+bytes) ERRORMSG(); while (*ptr2!='\n' && *ptr2!=' ') if (++ptr2>=data+bytes) ERRORMSG(); if (++ptr2>=data+bytes) ERRORMSG(); while (*ptr2!='\n' && *ptr2!=' ') if (++ptr2>=data+bytes) ERRORMSG(); if (++ptr2>=data+bytes) ERRORMSG(); if (ptr2-ptr1>=maxstr) ERRORMSG(); memcpy(str,ptr1,ptr2-ptr1); str[ptr2-ptr1]='\0'; if (sscanf(str,"%d %d\n%d\n",width,height,&maxval)!=3) ERRORMSG(); if (*width<1 || *height<1) ERRORMSG(); if (pnmtype==5 && maxval==255) *components=1; else if (pnmtype==5 && (maxval==32767 || maxval==65535)) *components=2; else if (pnmtype==6 && maxval==255) *components=3; else ERRORMSG(); if ((image=(unsigned char *)malloc((*width)*(*height)*(*components)))==NULL) MEMERROR(); if (data+bytes!=ptr2+(*width)*(*height)*(*components)) ERRORMSG(); memcpy(image,ptr2,(*width)*(*height)*(*components)); free(data); return(image); } // write a compressed PVM volume void writePVMvolume(const char *filename,unsigned char *volume, unsigned int width,unsigned int height,unsigned int depth,unsigned int components, float scalex,float scaley,float scalez, unsigned char *description, unsigned char *courtesy, unsigned char *parameter, unsigned char *comment) { char str[DDS_MAXSTR]; unsigned char *data; unsigned int len1=1,len2=1,len3=1,len4=1; if (width<1 || height<1 || depth<1 || components<1) ERRORMSG(); if (description==NULL && courtesy==NULL && parameter==NULL && comment==NULL) if (scalex==1.0f && scaley==1.0f && scalez==1.0f) snprintf(str,DDS_MAXSTR,"PVM\n%d %d %d\n%d\n",width,height,depth,components); else snprintf(str,DDS_MAXSTR,"PVM2\n%d %d %d\n%g %g %g\n%d\n",width,height,depth,scalex,scaley,scalez,components); else snprintf(str,DDS_MAXSTR,"PVM3\n%d %d %d\n%g %g %g\n%d\n",width,height,depth,scalex,scaley,scalez,components); if (description==NULL && courtesy==NULL && parameter==NULL && comment==NULL) { if ((data=(unsigned char *)malloc(strlen(str)+width*height*depth*components))==NULL) MEMERROR(); memcpy(data,str,strlen(str)); memcpy(data+strlen(str),volume,width*height*depth*components); writeDDSfile(filename,data,strlen(str)+width*height*depth*components,components,width); } else { if (description!=NULL) len1=strlen((char *)description)+1; if (courtesy!=NULL) len2=strlen((char *)courtesy)+1; if (parameter!=NULL) len3=strlen((char *)parameter)+1; if (comment!=NULL) len4=strlen((char *)comment)+1; if ((data=(unsigned char *)malloc(strlen(str)+width*height*depth*components+len1+len2+len3+len4))==NULL) MEMERROR(); memcpy(data,str,strlen(str)); memcpy(data+strlen(str),volume,width*height*depth*components); if (description==NULL) *(data+strlen(str)+width*height*depth*components)='\0'; else memcpy(data+strlen(str)+width*height*depth*components,description,len1); if (courtesy==NULL) *(data+strlen(str)+width*height*depth*components+len1)='\0'; else memcpy(data+strlen(str)+width*height*depth*components+len1,courtesy,len2); if (parameter==NULL) *(data+strlen(str)+width*height*depth*components+len1+len2)='\0'; else memcpy(data+strlen(str)+width*height*depth*components+len1+len2,parameter,len3); if (comment==NULL) *(data+strlen(str)+width*height*depth*components+len1+len2+len3)='\0'; else memcpy(data+strlen(str)+width*height*depth*components+len1+len2+len3,comment,len4); writeDDSfile(filename,data,strlen(str)+width*height*depth*components+len1+len2+len3+len4,components,width); } } // read a compressed PVM volume unsigned char *readPVMvolume(const char *filename, unsigned int *width,unsigned int *height,unsigned int *depth,unsigned int *components, float *scalex,float *scaley,float *scalez, unsigned char **description, unsigned char **courtesy, unsigned char **parameter, unsigned char **comment) { unsigned char *data,*ptr; unsigned int bytes,numc; int version=1; unsigned char *volume; float sx=1.0f,sy=1.0f,sz=1.0f; unsigned int len1=0,len2=0,len3=0,len4=0; if ((data=readDDSfile(filename,&bytes))==NULL) if ((data=readRAWfile(filename,&bytes))==NULL) return(NULL); if (bytes<5) return(NULL); if ((data=(unsigned char *)realloc(data,bytes+1))==NULL) MEMERROR(); data[bytes]='\0'; if (strncmp((char *)data,"PVM\n",4)!=0) { if (strncmp((char *)data,"PVM2\n",5)==0) version=2; else if (strncmp((char *)data,"PVM3\n",5)==0) version=3; else return(NULL); ptr=&data[5]; if (sscanf((char *)ptr,"%d %d %d\n%g %g %g\n",width,height,depth,&sx,&sy,&sz)!=6) ERRORMSG(); if (*width<1 || *height<1 || *depth<1 || sx<=0.0f || sy<=0.0f || sz<=0.0f) ERRORMSG(); ptr=(unsigned char *)strchr((char *)ptr,'\n')+1; } else { ptr=&data[4]; while (*ptr=='#') while (*ptr++!='\n'); if (sscanf((char *)ptr,"%d %d %d\n",width,height,depth)!=3) ERRORMSG(); if (*width<1 || *height<1 || *depth<1) ERRORMSG(); } if (scalex!=NULL && scaley!=NULL && scalez!=NULL) { *scalex=sx; *scaley=sy; *scalez=sz; } ptr=(unsigned char *)strchr((char *)ptr,'\n')+1; if (sscanf((char *)ptr,"%d\n",&numc)!=1) ERRORMSG(); if (numc<1) ERRORMSG(); if (components!=NULL) *components=numc; else if (numc!=1) ERRORMSG(); ptr=(unsigned char *)strchr((char *)ptr,'\n')+1; if (version==3) len1=strlen((char *)(ptr+(*width)*(*height)*(*depth)*numc))+1; if (version==3) len2=strlen((char *)(ptr+(*width)*(*height)*(*depth)*numc+len1))+1; if (version==3) len3=strlen((char *)(ptr+(*width)*(*height)*(*depth)*numc+len1+len2))+1; if (version==3) len4=strlen((char *)(ptr+(*width)*(*height)*(*depth)*numc+len1+len2+len3))+1; if ((volume=(unsigned char *)malloc((*width)*(*height)*(*depth)*numc+len1+len2+len3+len4))==NULL) MEMERROR(); if (data+bytes!=ptr+(*width)*(*height)*(*depth)*numc+len1+len2+len3+len4) ERRORMSG(); memcpy(volume,ptr,(*width)*(*height)*(*depth)*numc+len1+len2+len3+len4); free(data); if (description!=NULL) if (len1>1) *description=volume+(*width)*(*height)*(*depth)*numc; else *description=NULL; if (courtesy!=NULL) if (len2>1) *courtesy=volume+(*width)*(*height)*(*depth)*numc+len1; else *courtesy=NULL; if (parameter!=NULL) if (len3>1) *parameter=volume+(*width)*(*height)*(*depth)*numc+len1+len2; else *parameter=NULL; if (comment!=NULL) if (len4>1) *comment=volume+(*width)*(*height)*(*depth)*numc+len1+len2+len3; else *comment=NULL; return(volume); } // check a file int checkfile(const char *filename) { FILE *file; if ((file=fopen(filename,"rb"))==NULL) return(0); fclose(file); return(1); } // simple checksum algorithm unsigned int checksum(unsigned char *data,unsigned int bytes) { const unsigned int prime=271; unsigned int i; unsigned char *ptr,value; unsigned int sum,cipher; sum=0; cipher=1; for (ptr=data,i=0; i32767) v=v-65536; if (v32767) v=v-65536; *ptr=(v-vmin)/256; *(ptr+1)=(v-vmin)%256; } } // convert from float to unsigned short void convfloat(unsigned char **data,long long bytes) { long long i; unsigned char *ptr; float v,vmax; for (vmax=1.0f,ptr=*data,i=0; ivmax) vmax=v; } for (ptr=*data,i=0; i0) if (i0) if (j0) if (kvmax) vmax=v; } if (!nofree) free(data); if (vmin==vmax) vmax=vmin+1; if (vmax-vmin<256) linear=TRUE; err=new double[65536]; if (linear) for (i=0; i<65536; i++) err[i]=255*(double)(i-vmin)/(vmax-vmin); else { for (i=0; i<65536; i++) err[i]=0.0; for (k=0; keint/256) { err[i]=eint/256; done=FALSE; } if (done) break; } for (i=1; i<65536; i++) err[i]+=err[i-1]; if (err[65535]>0.0f) for (i=0; i<65536; i++) err[i]*=255.0/err[65535]; } if ((data2=(unsigned char *)malloc(width*height*depth))==NULL) MEMERROR(); for (k=0; k