00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdafx.h"
00027 #include "film/image.h"
00028 #include "spectrum.h"
00029 #include "parallel.h"
00030 #include "imageio.h"
00031 #ifdef PBRT_HAS_LIBSDL
00032 #include "SDL.h"
00033 #endif // PBRT_HAS_LIBSDL
00034
00035
00036 ImageFilm::ImageFilm(int xres, int yres, Filter *filt, const float crop[4],
00037 const string &fn, bool openWindow)
00038 : Film(xres, yres) {
00039 filter = filt;
00040 memcpy(cropWindow, crop, 4 * sizeof(float));
00041 filename = fn;
00042
00043 xPixelStart = Ceil2Int(xResolution * cropWindow[0]);
00044 xPixelCount = max(1, Ceil2Int(xResolution * cropWindow[1]) - xPixelStart);
00045 yPixelStart = Ceil2Int(yResolution * cropWindow[2]);
00046 yPixelCount = max(1, Ceil2Int(yResolution * cropWindow[3]) - yPixelStart);
00047
00048
00049 pixels = new BlockedArray<Pixel>(xPixelCount, yPixelCount);
00050
00051
00052 #define FILTER_TABLE_SIZE 16
00053 filterTable = new float[FILTER_TABLE_SIZE * FILTER_TABLE_SIZE];
00054 float *ftp = filterTable;
00055 for (int y = 0; y < FILTER_TABLE_SIZE; ++y) {
00056 float fy = ((float)y + .5f) *
00057 filter->yWidth / FILTER_TABLE_SIZE;
00058 for (int x = 0; x < FILTER_TABLE_SIZE; ++x) {
00059 float fx = ((float)x + .5f) *
00060 filter->xWidth / FILTER_TABLE_SIZE;
00061 *ftp++ = filter->Evaluate(fx, fy);
00062 }
00063 }
00064
00065
00066 if (openWindow || PbrtOptions.openWindow) {
00067 #ifdef PBRT_HAS_LIBSDL
00068 SDL_Init(SDL_INIT_VIDEO);
00069 SDL_WM_SetCaption(filename.c_str(), filename.c_str());
00070 sdlWindow = SDL_SetVideoMode(xPixelCount, yPixelCount, 32, SDL_SWSURFACE);
00071 if (sdlWindow == NULL)
00072 Error("Unable to create window to display image");
00073 if (SDL_LockSurface(sdlWindow) == -1)
00074 Error("Unable to lock surface for image display");
00075 else {
00076 for (int y = 0; y < yPixelCount; ++y) {
00077 for (int x = 0; x < xPixelCount; ++x) {
00078 uint32_t *bufp = (uint32_t *)sdlWindow->pixels + y*sdlWindow->pitch/4 + x;
00079 *bufp = SDL_MapRGB(sdlWindow->format, 64, 64, 64);
00080 }
00081 }
00082 SDL_UnlockSurface(sdlWindow);
00083 SDL_UpdateRect(sdlWindow, 0, 0, xPixelCount, yPixelCount);
00084 }
00085 #else
00086 Warning("Support for opening image display window not available in this build.");
00087 #endif // PBRT_HAS_LIBSDL
00088 }
00089 #ifdef PBRT_HAS_LIBSDL
00090 else
00091 sdlWindow = NULL;
00092 #endif // PBRT_HAS_LIBSDL
00093 }
00094
00095
00096 void ImageFilm::AddSample(const CameraSample &sample,
00097 const Spectrum &L) {
00098
00099 float dimageX = sample.imageX - 0.5f;
00100 float dimageY = sample.imageY - 0.5f;
00101 int x0 = Ceil2Int (dimageX - filter->xWidth);
00102 int x1 = Floor2Int(dimageX + filter->xWidth);
00103 int y0 = Ceil2Int (dimageY - filter->yWidth);
00104 int y1 = Floor2Int(dimageY + filter->yWidth);
00105 x0 = max(x0, xPixelStart);
00106 x1 = min(x1, xPixelStart + xPixelCount - 1);
00107 y0 = max(y0, yPixelStart);
00108 y1 = min(y1, yPixelStart + yPixelCount - 1);
00109 if ((x1-x0) < 0 || (y1-y0) < 0)
00110 {
00111 PBRT_SAMPLE_OUTSIDE_IMAGE_EXTENT(const_cast<CameraSample *>(&sample));
00112 return;
00113 }
00114
00115
00116 float xyz[3];
00117 L.ToXYZ(xyz);
00118
00119
00120 int *ifx = ALLOCA(int, x1 - x0 + 1);
00121 for (int x = x0; x <= x1; ++x) {
00122 float fx = fabsf((x - dimageX) *
00123 filter->invXWidth * FILTER_TABLE_SIZE);
00124 ifx[x-x0] = min(Floor2Int(fx), FILTER_TABLE_SIZE-1);
00125 }
00126 int *ify = ALLOCA(int, y1 - y0 + 1);
00127 for (int y = y0; y <= y1; ++y) {
00128 float fy = fabsf((y - dimageY) *
00129 filter->invYWidth * FILTER_TABLE_SIZE);
00130 ify[y-y0] = min(Floor2Int(fy), FILTER_TABLE_SIZE-1);
00131 }
00132 bool syncNeeded = (filter->xWidth > 0.5f || filter->yWidth > 0.5f);
00133 for (int y = y0; y <= y1; ++y) {
00134 for (int x = x0; x <= x1; ++x) {
00135
00136 int offset = ify[y-y0]*FILTER_TABLE_SIZE + ifx[x-x0];
00137 float filterWt = filterTable[offset];
00138
00139
00140 Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
00141 if (!syncNeeded) {
00142 pixel.Lxyz[0] += filterWt * xyz[0];
00143 pixel.Lxyz[1] += filterWt * xyz[1];
00144 pixel.Lxyz[2] += filterWt * xyz[2];
00145 pixel.weightSum += filterWt;
00146 }
00147 else {
00148
00149 AtomicAdd(&pixel.Lxyz[0], filterWt * xyz[0]);
00150 AtomicAdd(&pixel.Lxyz[1], filterWt * xyz[1]);
00151 AtomicAdd(&pixel.Lxyz[2], filterWt * xyz[2]);
00152 AtomicAdd(&pixel.weightSum, filterWt);
00153 }
00154 }
00155 }
00156 }
00157
00158
00159 void ImageFilm::Splat(const CameraSample &sample, const Spectrum &L) {
00160 if (L.HasNaNs()) {
00161 Warning("ImageFilm ignoring splatted spectrum with NaN values");
00162 return;
00163 }
00164 float xyz[3];
00165 L.ToXYZ(xyz);
00166 int x = Floor2Int(sample.imageX), y = Floor2Int(sample.imageY);
00167 if (x < xPixelStart || x - xPixelStart >= xPixelCount ||
00168 y < yPixelStart || y - yPixelStart >= yPixelCount) return;
00169 Pixel &pixel = (*pixels)(x - xPixelStart, y - yPixelStart);
00170 AtomicAdd(&pixel.splatXYZ[0], xyz[0]);
00171 AtomicAdd(&pixel.splatXYZ[1], xyz[1]);
00172 AtomicAdd(&pixel.splatXYZ[2], xyz[2]);
00173 }
00174
00175
00176 void ImageFilm::GetSampleExtent(int *xstart, int *xend,
00177 int *ystart, int *yend) const {
00178 *xstart = Floor2Int(xPixelStart + 0.5f - filter->xWidth);
00179 *xend = Floor2Int(xPixelStart + 0.5f + xPixelCount +
00180 filter->xWidth);
00181
00182 *ystart = Floor2Int(yPixelStart + 0.5f - filter->yWidth);
00183 *yend = Floor2Int(yPixelStart + 0.5f + yPixelCount +
00184 filter->yWidth);
00185 }
00186
00187
00188 void ImageFilm::GetPixelExtent(int *xstart, int *xend,
00189 int *ystart, int *yend) const {
00190 *xstart = xPixelStart;
00191 *xend = xPixelStart + xPixelCount;
00192 *ystart = yPixelStart;
00193 *yend = yPixelStart + yPixelCount;
00194 }
00195
00196
00197 void ImageFilm::WriteImage(float splatScale) {
00198
00199 int nPix = xPixelCount * yPixelCount;
00200 float *rgb = new float[3*nPix];
00201 int offset = 0;
00202 for (int y = 0; y < yPixelCount; ++y) {
00203 for (int x = 0; x < xPixelCount; ++x) {
00204
00205 XYZToRGB((*pixels)(x, y).Lxyz, &rgb[3*offset]);
00206
00207
00208 float weightSum = (*pixels)(x, y).weightSum;
00209 if (weightSum != 0.f) {
00210 float invWt = 1.f / weightSum;
00211 rgb[3*offset ] = max(0.f, rgb[3*offset ] * invWt);
00212 rgb[3*offset+1] = max(0.f, rgb[3*offset+1] * invWt);
00213 rgb[3*offset+2] = max(0.f, rgb[3*offset+2] * invWt);
00214 }
00215
00216
00217 float splatRGB[3];
00218 XYZToRGB((*pixels)(x, y).splatXYZ, splatRGB);
00219 rgb[3*offset ] += splatScale * splatRGB[0];
00220 rgb[3*offset+1] += splatScale * splatRGB[1];
00221 rgb[3*offset+2] += splatScale * splatRGB[2];
00222 ++offset;
00223 }
00224 }
00225
00226
00227 ::WriteImage(filename, rgb, NULL, xPixelCount, yPixelCount,
00228 xResolution, yResolution, xPixelStart, yPixelStart);
00229
00230
00231 delete[] rgb;
00232 }
00233
00234
00235 void ImageFilm::UpdateDisplay(int x0, int y0, int x1, int y1,
00236 float splatScale) {
00237 #ifdef PBRT_HAS_LIBSDL
00238 if (!sdlWindow) return;
00239
00240 x0 -= xPixelStart;
00241 x1 -= xPixelStart;
00242 y0 -= yPixelStart;
00243 y1 -= yPixelStart;
00244 x0 = Clamp(x0, 0, xPixelCount);
00245 x1 = Clamp(x1, 0, xPixelCount);
00246 y0 = Clamp(y0, 0, yPixelCount);
00247 y1 = Clamp(y1, 0, yPixelCount);
00248 uint32_t *pix = new uint32_t[(x1-x0)*(y1-y0)];
00249 uint32_t *pp = pix;
00250 for (int y = y0; y < y1; ++y) {
00251 for (int x = x0; x < x1; ++x) {
00252
00253 Pixel &pixel = (*pixels)(x, y);
00254 float rgb[3];
00255 XYZToRGB(pixel.Lxyz, rgb);
00256 float weightSum = pixel.weightSum;
00257 if (weightSum != 0.f) {
00258 float invWt = 1.f / weightSum;
00259 rgb[0] *= invWt;
00260 rgb[1] *= invWt;
00261 rgb[2] *= invWt;
00262 }
00263 float splatRGB[3];
00264 XYZToRGB(pixel.splatXYZ, splatRGB);
00265 rgb[0] += splatScale * splatRGB[0];
00266 rgb[1] += splatScale * splatRGB[1];
00267 rgb[2] += splatScale * splatRGB[2];
00268
00269 *pp++ = SDL_MapRGB(sdlWindow->format,
00270 uint8_t(Clamp(powf(rgb[0], 1./1.8), 0.f, 1.f) * 255),
00271 uint8_t(Clamp(powf(rgb[1], 1./1.8), 0.f, 1.f) * 255),
00272 uint8_t(Clamp(powf(rgb[2], 1./1.8), 0.f, 1.f) * 255));
00273 }
00274 }
00275
00276 if (SDL_LockSurface(sdlWindow) == -1) { }
00277 pp=pix;
00278 for (int y = y0; y < y1; ++y) {
00279 for (int x = x0; x < x1; ++x) {
00280 uint32_t *bufp = (uint32_t *)sdlWindow->pixels + y*sdlWindow->pitch/4 + x;
00281 *bufp = *pp++;
00282 }
00283 }
00284 SDL_UnlockSurface(sdlWindow);
00285 SDL_UpdateRect(sdlWindow, x0, y0, x1-x0, y1-y0);
00286 delete[] pix;
00287 #if 0
00288 SDL_Event event;
00289 while (SDL_PollEvent(&event)) {
00290 if (event.type == SDL_QUIT)
00291 SDL_Quit();
00292 }
00293 #endif
00294 #endif // PBRT_HAS_LIBSDL
00295 }
00296
00297
00298 ImageFilm *CreateImageFilm(const ParamSet ¶ms, Filter *filter) {
00299 string filename = params.FindOneString("filename", PbrtOptions.imageFile);
00300 if (filename == "")
00301 #ifdef PBRT_HAS_OPENEXR
00302 filename = "pbrt.exr";
00303 #else
00304 filename = "pbrt.tga";
00305 #endif
00306
00307 int xres = params.FindOneInt("xresolution", 640);
00308 int yres = params.FindOneInt("yresolution", 480);
00309 if (PbrtOptions.quickRender) xres = max(1, xres / 4);
00310 if (PbrtOptions.quickRender) yres = max(1, yres / 4);
00311 bool openwin = params.FindOneBool("display", false);
00312 float crop[4] = { 0, 1, 0, 1 };
00313 int cwi;
00314 const float *cr = params.FindFloat("cropwindow", &cwi);
00315 if (cr && cwi == 4) {
00316 crop[0] = Clamp(min(cr[0], cr[1]), 0., 1.);
00317 crop[1] = Clamp(max(cr[0], cr[1]), 0., 1.);
00318 crop[2] = Clamp(min(cr[2], cr[3]), 0., 1.);
00319 crop[3] = Clamp(max(cr[2], cr[3]), 0., 1.);
00320 }
00321
00322 return new ImageFilm(xres, yres, filter, crop, filename, openwin);
00323 }
00324
00325