Files
CDAG/Research/inc/pvm/ddsbase.cpp

1147 lines
29 KiB
C++

// (c) by Stefan Roettger, licensed under GPL 2+
#include "ddsbase.h"
#ifdef HAVE_MINI
#include <mini/rawbase.h>
#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<<bits);}
inline unsigned int DDS_shiftr(const unsigned int value,const unsigned int bits)
{return((bits>=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_bufsize)
{
DDS_bufsize-=bits;
value=DDS_shiftr(DDS_buffer,DDS_bufsize);
}
else
{
value=DDS_shiftl(DDS_buffer,bits-DDS_bufsize);
if (DDS_cachepos>=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; i<skip; i++)
for (j=i; j<bytes; j+=skip) *ptr++=data[j];
else
for (ptr=data,i=0; i<skip; i++)
for (j=i; j<bytes; j+=skip) data2[j]=*ptr++;
memcpy(data,data2,bytes);
}
else
{
if ((data2=(unsigned char *)malloc((bytes<skip*block)?bytes:skip*block))==NULL) MEMERROR();
if (!restore)
{
for (k=0; k<bytes/skip/block; k++)
{
for (ptr=data2,i=0; i<skip; i++)
for (j=i; j<skip*block; j+=skip) *ptr++=data[k*skip*block+j];
memcpy(data+k*skip*block,data2,skip*block);
}
for (ptr=data2,i=0; i<skip; i++)
for (j=i; j<bytes-k*skip*block; j+=skip) *ptr++=data[k*skip*block+j];
memcpy(data+k*skip*block,data2,bytes-k*skip*block);
}
else
{
for (k=0; k<bytes/skip/block; k++)
{
for (ptr=data+k*skip*block,i=0; i<skip; i++)
for (j=i; j<skip*block; j+=skip) data2[j]=*ptr++;
memcpy(data+k*skip*block,data2,skip*block);
}
for (ptr=data+k*skip*block,i=0; i<skip; i++)
for (j=i; j<bytes-k*skip*block; j+=skip) data2[j]=*ptr++;
memcpy(data+k*skip*block,data2,bytes-k*skip*block);
}
}
free(data2);
}
// interleave a byte stream
void DDS_interleave(unsigned char *data,unsigned int bytes,unsigned int skip,unsigned int block=0)
{DDS_deinterleave(data,bytes,skip,block,TRUE);}
// encode a Differential Data Stream
void DDS_encode(unsigned char *data,unsigned int bytes,unsigned int skip,unsigned int strip,
unsigned char **chunk,unsigned int *size,
unsigned int block=0)
{
int i;
unsigned char lookup[256];
unsigned char *ptr1,*ptr2;
int pre1,pre2,
act1,act2,
tmp1,tmp2;
unsigned int cnt,cnt1,cnt2;
int bits,bits1,bits2;
if (bytes<1) ERRORMSG();
if (skip<1 || skip>4) 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<<bits)/2<-i; bits++);
else
for (bits=0; (1<<bits)/2<=i; bits++);
lookup[i+128]=bits;
}
DDS_initbuffer();
DDS_clearbits();
DDS_writebits(skip-1,2);
DDS_writebits(strip-1,16);
ptr1=ptr2=data;
pre1=pre2=0;
cnt=cnt1=cnt2=0;
bits=bits1=bits2=0;
while (cnt++<bytes)
{
tmp1=*ptr1;
if (strip==1 || ptr1-strip<=data) act1=tmp1-pre1;
else act1=tmp1-pre1-*(ptr1-strip)+*(ptr1-strip-1);
pre1=tmp1;
ptr1++;
while (act1<-128) act1+=256;
while (act1>127) act1-=256;
bits=lookup[act1+128];
bits=DDS_decode(DDS_code(bits));
if (cnt1==0)
{
cnt1++;
bits1=bits;
continue;
}
if (cnt1<(1<<DDS_RL)-1 && bits==bits1)
{
cnt1++;
continue;
}
if (cnt1+cnt2<(1<<DDS_RL) && (cnt1+cnt2)*max(bits1,bits2)<cnt1*bits1+cnt2*bits2+DDS_RL+3)
{
cnt2+=cnt1;
if (bits1>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)/2,bits2);
}
cnt2=cnt1;
bits2=bits1;
}
cnt1=1;
bits1=bits;
}
if (cnt1+cnt2<(1<<DDS_RL) && (cnt1+cnt2)*max(bits1,bits2)<cnt1*bits1+cnt2*bits2+DDS_RL+3)
{
cnt2+=cnt1;
if (bits1>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)/2,bits2);
}
cnt2=cnt1;
bits2=bits1;
}
if (cnt2!=0)
{
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)/2,bits2);
}
}
DDS_flushbits();
DDS_savebits(chunk,size);
DDS_interleave(data,bytes,skip,block);
}
// decode a Differential Data Stream
void DDS_decode(unsigned char *chunk,unsigned int size,
unsigned char **data,unsigned int *bytes,
unsigned int block=0)
{
unsigned int skip,strip;
unsigned char *ptr1,*ptr2;
unsigned int cnt,cnt1,cnt2;
int bits,act;
DDS_initbuffer();
DDS_clearbits();
DDS_loadbits(chunk,size);
skip=DDS_readbits(2)+1;
strip=DDS_readbits(16)+1;
ptr1=ptr2=NULL;
cnt=act=0;
while ((cnt1=DDS_readbits(DDS_RL))!=0)
{
bits=DDS_decode(DDS_readbits(3));
for (cnt2=0; cnt2<cnt1; cnt2++)
{
if (strip==1 || cnt<=strip) act+=DDS_readbits(bits)-(1<<bits)/2;
else act+=*(ptr2-strip)-*(ptr2-strip-1)+DDS_readbits(bits)-(1<<bits)/2;
while (act<0) act+=256;
while (act>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<size; i++)
{
lo=ptr[0];
hi=ptr[1];
*ptr++=hi;
*ptr++=lo;
}
}
// write an optionally compressed PNM image
void writePNMimage(const char *filename,unsigned char *image,unsigned int width,unsigned int height,unsigned int components,BOOLINT dds)
{
char str[DDS_MAXSTR];
unsigned char *data;
if (width<1 || height<1) ERRORMSG();
switch (components)
{
case 1: snprintf(str,DDS_MAXSTR,"P5\n%d %d\n255\n",width,height); break;
case 2: snprintf(str,DDS_MAXSTR,"P5\n%d %d\n32767\n",width,height); break;
case 3: snprintf(str,DDS_MAXSTR,"P6\n%d %d\n255\n",width,height); break;
default: ERRORMSG();
}
if ((data=(unsigned char *)malloc(strlen(str)+width*height*components))==NULL) MEMERROR();
memcpy(data,str,strlen(str));
memcpy(data+strlen(str),image,width*height*components);
if (dds) writeDDSfile(filename,data,strlen(str)+width*height*components,components,width);
else writeRAWfile(filename,data,strlen(str)+width*height*components);
}
// read a possibly compressed PNM image
unsigned char *readPNMimage(const char *filename,unsigned int *width,unsigned int *height,unsigned int *components)
{
const int maxstr=100;
char str[maxstr];
unsigned char *data,*ptr1,*ptr2;
unsigned int bytes;
int pnmtype,maxval;
unsigned char *image;
if ((data=readDDSfile(filename,&bytes))==NULL)
if ((data=readRAWfile(filename,&bytes))==NULL) return(NULL);
if (bytes<4) return(NULL);
memcpy(str,data,3);
str[3]='\0';
if (sscanf(str,"P%1d\n",&pnmtype)!=1) return(NULL);
ptr1=data+3;
while (*ptr1=='\n' || *ptr1=='#')
{
while (*ptr1=='\n')
if (++ptr1>=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; i<bytes; i++)
{
value=*ptr++;
cipher=prime*cipher+value;
sum+=cipher*value;
}
return(sum);
}
// swap the hi and lo byte of 16 bit data
void swapbytes(unsigned char *data,long long bytes)
{
long long i;
unsigned char *ptr,tmp;
for (ptr=data,i=0; i<bytes/2; i++,ptr+=2)
{
tmp=*ptr;
*ptr=*(ptr+1);
*(ptr+1)=tmp;
}
}
// convert from signed short to unsigned short
void convbytes(unsigned char *data,long long bytes)
{
long long i;
unsigned char *ptr;
int v,vmin;
for (vmin=32767,ptr=data,i=0; i<bytes/2; i++,ptr+=2)
{
v=256*(*ptr)+*(ptr+1);
if (v>32767) v=v-65536;
if (v<vmin) vmin=v;
}
for (ptr=data,i=0; i<bytes/2; i++,ptr+=2)
{
v=256*(*ptr)+*(ptr+1);
if (v>32767) 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; i<bytes/4; i++,ptr+=4)
{
if (DDS_ISINTEL) DDS_swapuint((unsigned int *)ptr);
v=fabs(*((float *)ptr));
if (v>vmax) vmax=v;
}
for (ptr=*data,i=0; i<bytes/4; i++,ptr+=4)
{
v=fabs(*((float *)ptr))/vmax;
(*data)[2*i]=ftrc(65535.0f*v+0.5f)/256;
(*data)[2*i+1]=ftrc(65535.0f*v+0.5f)%256;
}
if ((*data=(unsigned char *)realloc(*data,bytes/4*2))==NULL) MEMERROR();
}
// convert from rgb to byte
void convrgb(unsigned char **data,long long bytes)
{
long long i;
unsigned char *ptr1,*ptr2;
for (ptr1=ptr2=*data,i=0; i<bytes/3; i++,ptr1+=3,ptr2++)
*ptr2=((*ptr1)+*(ptr1+1)+*(ptr1+2)+1)/3;
if ((*data=(unsigned char *)realloc(*data,bytes/3))==NULL) MEMERROR();
}
// helper to get a short value from a volume
inline int getshort(unsigned short int *data,
long long width,long long height,long long depth,
long long i,long long j,long long k)
{return(data[i+(j+k*height)*width]);}
// helper to get a gradient value from a volume
inline double getgrad(unsigned short int *data,
long long width,long long height,long long depth,
long long i,long long j,long long k)
{
double gx,gy,gz;
if (i>0)
if (i<width-1) gx=(getshort(data,width,height,depth,i+1,j,k)-getshort(data,width,height,depth,i-1,j,k))/2.0;
else gx=getshort(data,width,height,depth,i,j,k)-getshort(data,width,height,depth,i-1,j,k);
else
if (i<width-1) gx=getshort(data,width,height,depth,i+1,j,k)-getshort(data,width,height,depth,i,j,k);
else gx=0.0;
if (j>0)
if (j<height-1) gy=(getshort(data,width,height,depth,i,j+1,k)-getshort(data,width,height,depth,i,j-1,k))/2.0;
else gy=getshort(data,width,height,depth,i,j,k)-getshort(data,width,height,depth,i,j-1,k);
else
if (j<height-1) gy=getshort(data,width,height,depth,i,j+1,k)-getshort(data,width,height,depth,i,j,k);
else gy=0.0;
if (k>0)
if (k<depth-1) gz=(getshort(data,width,height,depth,i,j,k+1)-getshort(data,width,height,depth,i,j,k-1))/2.0;
else gz=getshort(data,width,height,depth,i,j,k)-getshort(data,width,height,depth,i,j,k-1);
else
if (k<depth-1) gz=getshort(data,width,height,depth,i,j,k+1)-getshort(data,width,height,depth,i,j,k);
else gz=0.0;
return(sqrt(gx*gx+gy*gy+gz*gz));
}
// quantize 16 bit data to 8 bit using a non-linear mapping
unsigned char *quantize(unsigned char *data,
long long width,long long height,long long depth,
BOOLINT msb,
BOOLINT linear,BOOLINT nofree)
{
long long i,j,k;
unsigned char *data2;
unsigned short int *data3;
long long idx;
int v,vmin,vmax;
double *err,eint;
BOOLINT done;
if ((data3=(unsigned short int*)malloc(width*height*depth*sizeof(unsigned short int)))==NULL) MEMERROR();
vmin=65535;
vmax=0;
for (k=0; k<depth; k++)
for (j=0; j<height; j++)
for (i=0; i<width; i++)
{
idx=i+(j+k*height)*width;
if (msb)
v=256*data[2*idx]+data[2*idx+1];
else
v=data[2*idx]+256*data[2*idx+1];
data3[idx]=v;
if (v<vmin) vmin=v;
if (v>vmax) 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; k<depth; k++)
for (j=0; j<height; j++)
for (i=0; i<width; i++)
err[getshort(data3,width,height,depth,i,j,k)]+=sqrt(getgrad(data3,width,height,depth,i,j,k));
for (i=0; i<65536; i++) err[i]=pow(err[i],1.0/3);
err[vmin]=err[vmax]=0.0;
for (k=0; k<256; k++)
{
for (eint=0.0,i=0; i<65536; i++) eint+=err[i];
done=TRUE;
for (i=0; i<65536; i++)
if (err[i]>eint/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<depth; k++)
for (j=0; j<height; j++)
for (i=0; i<width; i++)
{
idx=i+(j+k*height)*width;
data2[idx]=(int)(err[data3[idx]]+0.5);
}
delete err;
free(data3);
return(data2);
}
// copy a PVM volume to a RAW volume
char *processPVMvolume(const char *filename)
{
unsigned char *volume;
unsigned int width,height,depth,
components;
float scalex,scaley,scalez;
char *output,*dot;
char *outname;
// read and uncompress PVM volume
if ((volume=readPVMvolume(filename,
&width,&height,&depth,&components,
&scalex,&scaley,&scalez))==NULL) return(NULL);
// use input file name as output prefix
output=strdup(filename);
dot=strrchr(output,'.');
// remove suffix from output
if (dot!=NULL)
if (strcasecmp(dot,".pvm")==0) *dot='\0';
outname=NULL;
#ifdef HAVE_MINI
// copy PVM data to RAW file
outname=writeRAWvolume(output,volume,
width,height,depth,1,
components,8,FALSE,TRUE,
scalex,scaley,scalez);
#endif
free(volume);
free(output);
return(outname);
}