////////////////////////////////////////////////////////////////////// // // Pixie // // Copyright © 1999 - 2003, Okan Arikan // // Contact: okan@cs.berkeley.edu // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // // File : texmake.cpp // Classes : - // Description : This file comtains texture file making routines // //////////////////////////////////////////////////////////////////////// #include // ensure we have NULL defined before libtiff #include #include #include "texmake.h" #include "renderer.h" #include "ri.h" #include "stats.h" #include "memory.h" #include "error.h" /////////////////////////////////////////////////////////////////////// // function : tiffErrorHandler // Description : Handle errors coming from the libtiff // Return Value : - // Comments : // Date last edited : 8/10/2001 static void tiffErrorHandler(const char *module,const char *fmt,va_list ap) { char tmp[1024]; vsprintf(tmp,fmt,ap); error(CODE_SYSTEM,"TIFF: %s\n",tmp); } /////////////////////////////////////////////////////////////////////// // Function : appendLayer // Description : Append a layer of image into an image file // Return Value : - // Comments : // Date last edited : 7/6/2001 static void appendLayer(TIFF *out,int dstart,int numSamples,int bitsperpixel,int tileSize,int width,int height,void *data,int last) { int x,y; unsigned char *tileData; int pixelSize; TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (unsigned long) width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, (unsigned long) height); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE); TIFFSetField(out, TIFFTAG_XRESOLUTION, 1.0f); TIFFSetField(out, TIFFTAG_YRESOLUTION, 1.0f); TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_LZW); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (unsigned long) numSamples); TIFFSetField(out, TIFFTAG_TILEWIDTH, (unsigned long) tileSize); TIFFSetField(out, TIFFTAG_TILELENGTH, (unsigned long) tileSize); if (bitsperpixel == 8) { TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (unsigned long) (sizeof(unsigned char)*8)); pixelSize = numSamples*sizeof(unsigned char); } else if (bitsperpixel == 16) { TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (unsigned long) (sizeof(unsigned short)*8)); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); pixelSize = numSamples*sizeof(unsigned short); } else { TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (unsigned long) (sizeof(float)*8)); pixelSize = numSamples*sizeof(float); } tileData = (unsigned char *) ralloc(pixelSize*tileSize*tileSize); assert(TIFFTileSize(out) == (tileSize*tileSize*pixelSize)); for (y=0;y static void appendPyramid(TIFF *out,int dstart,int numSamples,int bitsperpixel,int tileSize,int width,int height,T *data,int pyramidSize,int last) { T *currentLevel; int i; int currentWidth,currentHeight,nextWidth,nextHeight; float *fnextLevel; // Append the base layer appendLayer(out,dstart,numSamples,bitsperpixel,tileSize,width,height,data,last & (pyramidSize == 1)); // Append the remaining layers currentWidth = width; currentHeight = height; currentLevel = data; fnextLevel = (float *) ralloc(width*height*numSamples*sizeof(float)); for (i=1;i> 1; nextHeight = currentHeight >> 1; for (y=0,yo=0;y void copyData(T *from,int fw,int fh,int x,int y,int w,int h, T *to,int tw,int th,int tx,int ty,int numSamples) { int i,j; for (j=0;j void initData(T *to,int width,int height,int x,int y,int w,int h,int numSamples,T n) { int i,j,s; for (j=0;j void adjustSize(T **data,int *width,int *height,int numSamples,char *smode,char *tmode) { int newWidth,newHeight; for (newWidth=1;newWidth < width[0];newWidth = newWidth << 1); for (newHeight=1;newHeight < height[0];newHeight = newHeight << 1); if (!((width[0] == newWidth) && (height[0] == newHeight))) { T *newData; newData = (T *) ralloc(newWidth*newHeight*numSamples*sizeof(T)); memset(newData,0,newWidth*newHeight*numSamples*sizeof(T)); copyData(data[0],width[0],height[0],0,0,width[0],height[0],newData,newWidth,newHeight,0,0,numSamples); if (strcmp(smode,RI_PERIODIC) == 0) { copyData(data[0],width[0],height[0],0,0,newWidth-width[0],height[0],newData,newWidth,newHeight,width[0],0,numSamples); } else if (strcmp(smode,RI_CLAMP) == 0) { int i; for (i=0;i(data[0],width[0],height[0],width[0]-1,0,1,height[0],newData,newWidth,newHeight,width[0]+i,0,numSamples); } else if (strcmp(smode,RI_BLACK) == 0) { initData(newData,newWidth,newHeight,width[0],0,newWidth-width[0],height[0],numSamples,0); } if (strcmp(tmode,RI_PERIODIC) == 0) { copyData(data[0],width[0],height[0],0,0,width[0],newHeight-height[0],newData,newWidth,newHeight,0,height[0],numSamples); } else if (strcmp(tmode,RI_CLAMP) == 0) { int i; for (i=0;i(data[0],width[0],height[0],0,height[0]-1,width[0],1,newData,newWidth,newHeight,0,height[0]+i,numSamples); } else if (strcmp(tmode,RI_BLACK) == 0) { initData(newData,newWidth,newHeight,0,height[0],width[0],newHeight-height[0],numSamples,0); } data[0] = newData; width[0] = newWidth; height[0] = newHeight; } } /////////////////////////////////////////////////////////////////////// // Function : filterImage // Description : Apply a filter to the image // Return Value : // Comments : // Date last edited : 7/6/2001 template void filterImage(int width,int height,int numSamples,int bitspersample,float filterWidth,float filterHeight,RtFilterFunc filter,T *data) { memBegin(); float *filteredData = (float *) ralloc(width*height*numSamples*sizeof(float)); float *normalizer = (float *) ralloc(width*height*sizeof(float)); int x,y,i; int fw = (int) ceil((filterWidth-1)/2); int fh = (int) ceil((filterHeight-1)/2); float filterXmarginal = filterWidth/2; float filterYmarginal = filterHeight/2; float filterXmargin = (float) floor(filterXmarginal); float filterYmargin = (float) floor(filterYmarginal); float dx = filterXmarginal - filterXmargin; float dy = filterYmarginal - filterYmargin; // Clear the filtered image for (i=0;i= 0) && (i < width) && (j >= 0) && (j < height)) { float cx = (float) (i-x); float cy = (float) (j-y); float filterResponse = filter(cx,cy,filterWidth,filterHeight); int k; T *cPixel = &data[(j*width+i)*numSamples]; if (fabs(cx) > filterXmargin) filterResponse *= dx; if (fabs(cy) > filterYmargin) filterResponse *= dy; norm[0] += filterResponse; for (k=0;k 2) && (nh > 2);nw=nw>>1,nh=nh>>1,pyramidSize++); } sprintf(spec,"#texture (%dx%d): smode: %s tmode: %s levels: %d",w,h,smode,tmode,pyramidSize); } /////////////////////////////////////////////////////////////////////// // Function : appendTexture // Description : Make and append a texture to the end of the TIFF file // Return Value : // Comments : // Date last edited : 7/6/2001 void appendTexture(TIFF *out,int &dstart,int width,int height,int numSamples,int bitspersample,RtFilterFunc filter,float filterWidth,float filterHeight,int tileSize,int pyramidSize,void *data,char *smode,char *tmode,int last) { if (bitspersample == 8) { if ((filterWidth > 1) || (filterHeight > 1)) filterImage(width,height,numSamples,bitspersample,filterWidth,filterHeight,filter,(unsigned char *) data); adjustSize((unsigned char **) &data,&width,&height,numSamples,smode,tmode); appendPyramid(out,0,numSamples,bitspersample,tileSize,width,height,(unsigned char *) data,pyramidSize,last); } else if (bitspersample == 16) { if ((filterWidth > 1) || (filterHeight > 1)) filterImage(width,height,numSamples,bitspersample,filterWidth,filterHeight,filter,(unsigned short *) data); adjustSize((unsigned short **) &data,&width,&height,numSamples,smode,tmode); appendPyramid(out,0,numSamples,bitspersample,tileSize,width,height,(unsigned short *) data,pyramidSize,last); } else if (bitspersample == 32) { if ((filterWidth > 1) || (filterHeight > 1)) filterImage(width,height,numSamples,bitspersample,filterWidth,filterHeight,filter,(float *) data); adjustSize((float **) &data,&width,&height,numSamples,smode,tmode); appendPyramid(out,0,numSamples,bitspersample,tileSize,width,height,(float *) data,pyramidSize,last); } dstart += pyramidSize; } /////////////////////////////////////////////////////////////////////// // Function : makeTexture // Description : Create an image pyramid from input // Return Value : // Comments : // Date last edited : 7/6/2001 void makeTexture(char *input,char *output,TSearchpath *path,char *smode,char *tmode,RtFilterFunc filt,float fwidth,float fheight,int numParams,char **params,void **vals) { void *data; int numSamples; int bitspersample; int width,height; int tileSize = 32; char tmp[256]; RtFilterFunc filter = filt; float filterWidth = fwidth; float filterHeight = fheight; char *outPath = NULL; int pyramidSize; char inputFileName[OS_MAX_PATH_LENGTH]; TIFF *outHandle; TIFF *inHandle; char spec[1024]; // Set the error handler so we don't crash TIFFSetErrorHandler(tiffErrorHandler); TIFFSetWarningHandler(tiffErrorHandler); if (currentRenderer->locateFile(inputFileName,input,path) == FALSE) { error(CODE_NOFILE,"Unable to find \"%s\"\n",input); return; } inHandle = TIFFOpen(inputFileName,"r"); if (inHandle == NULL) { error(CODE_NOFILE,"Unable to open \"%s\" \n",inputFileName); return; } memBegin(); pyramidSize = 0; getTextureSpec(inHandle,spec,smode,tmode,tileSize,pyramidSize); data = readLayer(inHandle,&width,&height,&bitspersample,&numSamples); TIFFClose(inHandle); if (outPath != NULL) { if ((outPath[strlen(outPath-1)] == '/') || (outPath[strlen(outPath-1)] == '\\')) sprintf(tmp,"%s%s",outPath,output); else sprintf(tmp,"%s\\%s",outPath,output); } else { sprintf(tmp,"%s",output); } outHandle = TIFFOpen(tmp,"w"); if (output != NULL) { int dstart = 0; TIFFSetField(outHandle, TIFFTAG_IMAGEDESCRIPTION, spec); appendTexture(outHandle,dstart,width,height,numSamples,bitspersample,filter,filterWidth,filterHeight,tileSize,pyramidSize,data,smode,tmode,TRUE); TIFFClose(outHandle); } memEnd(); } /////////////////////////////////////////////////////////////////////// // Function : makeSideEnvironment // Description : Create a single sided environment map // Return Value : // Comments : // Date last edited : 7/6/2001 void makeSideEnvironment(char *input,char *output,TSearchpath *path,char *smode,char *tmode,RtFilterFunc filt,float fwidth,float fheight,int numParams,char **params,void **vals,int shadow) { void *data; int numSamples; int bitspersample; int width,height; int tileSize = 32; char tmp[256]; RtFilterFunc filter = filt; float filterWidth = fwidth; float filterHeight = fheight; char *outPath = NULL; int pyramidSize; char inputFileName[OS_MAX_PATH_LENGTH]; TIFF *outHandle; TIFF *inHandle; char spec[1024]; char allSpec[1024]; // Set the error handler so we don't crash TIFFSetErrorHandler(tiffErrorHandler); TIFFSetWarningHandler(tiffErrorHandler); if (currentRenderer->locateFile(inputFileName,input,path) == FALSE) { error(CODE_NOFILE,"Unable to find \"%s\"\n",input); return; } inHandle = TIFFOpen(inputFileName,"r"); if (inHandle == NULL) { error(CODE_NOFILE,"Unable to open \"%s\" \n",inputFileName); return; } memBegin(); // Read off the from world transformation from the image if possible { char *desc; TIFFGetFieldDefaulted(inHandle, TIFFTAG_IMAGEDESCRIPTION, &desc); if (strncmp(desc,"WorldToNDC=",11) == 0) { strcpy(spec,desc+11); } else { sprintf(spec,"[1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1] "); } } // Set the spec sprintf(allSpec,"#shadow "); strcat(allSpec,spec); strcat(allSpec," "); pyramidSize = (shadow ? 1 : 0); getTextureSpec(inHandle,spec,smode,tmode,tileSize,pyramidSize); strcat(allSpec,spec); // Read the data data = readLayer(inHandle,&width,&height,&bitspersample,&numSamples); // Close the input TIFFClose(inHandle); if (outPath != NULL) { if ((outPath[strlen(outPath-1)] == '/') || (outPath[strlen(outPath-1)] == '\\')) sprintf(tmp,"%s%s",outPath,output); else sprintf(tmp,"%s\\%s",outPath,output); } else { sprintf(tmp,"%s",output); } outHandle = TIFFOpen(tmp,"w"); if (output != NULL) { int dstart = 0; TIFFSetField(outHandle, TIFFTAG_IMAGEDESCRIPTION, allSpec); appendTexture(outHandle,dstart,width,height,numSamples,bitspersample,filter,filterWidth,filterHeight,tileSize,1,data,smode,tmode,TRUE); TIFFClose(outHandle); } else { error(CODE_SYSTEM,"Unable to create %s for writing\n",tmp); } memEnd(); } /////////////////////////////////////////////////////////////////////// // Function : makeCubicEnvironment // Description : Create an environment map where each side is a pyramid // Return Value : // Comments : // Date last edited : 7/6/2001 void makeCubicEnvironment(char *px,char *py,char *pz,char *nx,char *ny,char *nz,char *output,TSearchpath *path,RtFilterFunc filt,float fwidth,float fheight,int numParams,char **params,void **vals,int shadow) { void *data; int numSamples; int bitspersample; int i; int width,height; int tileSize = 32; char tmp[256]; RtFilterFunc filter = filt; float filterWidth = fwidth; float filterHeight = fheight; char *outPath = NULL; int pyramidSize; char inputFileName[OS_MAX_PATH_LENGTH]; TIFF *outHandle; char *names[6]; char allSpec[1024]; char *smode = RI_PERIODIC; char *tmode = RI_PERIODIC; names[0] = px; names[1] = nx; names[2] = py; names[3] = ny; names[4] = pz; names[5] = nz; // Set the error handler so we don't crash TIFFSetErrorHandler(tiffErrorHandler); TIFFSetWarningHandler(tiffErrorHandler); if (currentRenderer->locateFile(inputFileName,names[0],path) == FALSE) { error(CODE_NOFILE,"Unable to find \"%s\"\n",names[0]); return; } if (outPath != NULL) { if ((outPath[strlen(outPath-1)] == '/') || (outPath[strlen(outPath-1)] == '\\')) sprintf(tmp,"%s%s",outPath,output); else sprintf(tmp,"%s\\%s",outPath,output); } else { sprintf(tmp,"%s",output); } outHandle = TIFFOpen(tmp,"w"); if (output != NULL) { TIFF *inHandles[6]; sprintf(allSpec,"#cenvironment "); // Make one pass to create the env spec for (i=0;i<6;i++) { char spec[1024]; int dstart = 0; if (currentRenderer->locateFile(inputFileName,names[i],path) == FALSE) { error(CODE_NOFILE,"Unable to find \"%s\"\n",names[i]); TIFFClose(outHandle); return; } inHandles[i] = TIFFOpen(inputFileName,"r"); if (inHandles[i] == NULL) { int j; error(CODE_NOFILE,"Unable to open \"%s\" \n",inputFileName); for (j=0;jlocateFile(inputFileName,input,path) == FALSE) { error(CODE_NOFILE,"Unable to find \"%s\"\n",input); return; } inHandle = TIFFOpen(inputFileName,"r"); if (inHandle == NULL) { error(CODE_NOFILE,"Unable to open \"%s\" \n",inputFileName); return; } memBegin(); pyramidSize = 0; getTextureSpec(inHandle,spec,smode,tmode,tileSize,pyramidSize); sprintf(allSpec,"#senvironment %s",spec); data = readLayer(inHandle,&width,&height,&bitspersample,&numSamples); TIFFClose(inHandle); if (outPath != NULL) { if ((outPath[strlen(outPath-1)] == '/') || (outPath[strlen(outPath-1)] == '\\')) sprintf(tmp,"%s%s",outPath,output); else sprintf(tmp,"%s\\%s",outPath,output); } else { sprintf(tmp,"%s",output); } outHandle = TIFFOpen(tmp,"w"); if (output != NULL) { int dstart = 0; TIFFSetField(outHandle, TIFFTAG_IMAGEDESCRIPTION, allSpec); appendTexture(outHandle,dstart,width,height,numSamples,bitspersample,filter,filterWidth,filterHeight,tileSize,pyramidSize,data,smode,tmode,TRUE); TIFFClose(outHandle); } memEnd(); } /////////////////////////////////////////////////////////////////////// // Function : makeSphericalEnvironment // Description : Create an image pyramid from input // Return Value : // Comments : // Date last edited : 7/6/2001 void makeCylindericalEnvironment(char *input,char *output,TSearchpath *path,char *smode,char *tmode,RtFilterFunc filt,float fwidth,float fheight,int numParams,char **params,void **vals) { void *data; int numSamples; int bitspersample; int width,height; int tileSize = 32; char tmp[256]; RtFilterFunc filter = filt; float filterWidth = fwidth; float filterHeight = fheight; char *outPath = NULL; int pyramidSize; char inputFileName[OS_MAX_PATH_LENGTH]; TIFF *outHandle; TIFF *inHandle; char spec[1024]; char allSpec[1024]; // Set the error handler so we don't crash TIFFSetErrorHandler(tiffErrorHandler); TIFFSetWarningHandler(tiffErrorHandler); if (currentRenderer->locateFile(inputFileName,input,path) == FALSE) { error(CODE_NOFILE,"Unable to find \"%s\"\n",input); return; } inHandle = TIFFOpen(inputFileName,"r"); if (inHandle == NULL) { error(CODE_NOFILE,"Unable to open \"%s\" \n",inputFileName); return; } memBegin(); pyramidSize = 0; getTextureSpec(inHandle,spec,smode,tmode,tileSize,pyramidSize); sprintf(allSpec,"#lenvironment %s",spec); data = readLayer(inHandle,&width,&height,&bitspersample,&numSamples); TIFFClose(inHandle); if (outPath != NULL) { if ((outPath[strlen(outPath-1)] == '/') || (outPath[strlen(outPath-1)] == '\\')) sprintf(tmp,"%s%s",outPath,output); else sprintf(tmp,"%s\\%s",outPath,output); } else { sprintf(tmp,"%s",output); } outHandle = TIFFOpen(tmp,"w"); if (output != NULL) { int dstart = 0; TIFFSetField(outHandle, TIFFTAG_IMAGEDESCRIPTION, allSpec); appendTexture(outHandle,dstart,width,height,numSamples,bitspersample,filter,filterWidth,filterHeight,tileSize,pyramidSize,data,smode,tmode,TRUE); TIFFClose(outHandle); } memEnd(); }