00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef LUX_FILM_H
00024 #define LUX_FILM_H
00025
00026 #include "lux.h"
00027 #include "color.h"
00028 #include "error.h"
00029 #include "memory.h"
00030
00031 #include <boost/serialization/split_member.hpp>
00032 #include <boost/thread/mutex.hpp>
00033
00034 namespace lux {
00035
00036 enum ImageType {
00037 IMAGE_NONE = 0,
00038 IMAGE_FILEOUTPUT = 1 << 1,
00039 IMAGE_FRAMEBUFFER = 1 << 2,
00040 IMAGE_ALL = IMAGE_FILEOUTPUT | IMAGE_FRAMEBUFFER
00041 };
00042
00043
00044
00045 enum BufferType {
00046 BUF_TYPE_PER_PIXEL = 0,
00047 BUF_TYPE_PER_SCREEN,
00048 BUF_TYPE_RAW,
00049 NUM_OF_BUFFER_TYPES
00050 };
00051
00052 enum BufferOutputConfig {
00053 BUF_FRAMEBUFFER = 1 << 0,
00054 BUF_STANDALONE = 1 << 1,
00055 BUF_RAWDATA = 1 << 2
00056 };
00057
00058 class BufferConfig {
00059 public:
00060 BufferConfig(BufferType t, BufferOutputConfig o, const string& s) :
00061 type(t), output(o), postfix(s) { }
00062 BufferType type;
00063 BufferOutputConfig output;
00064 string postfix;
00065 };
00066
00067
00068 struct Pixel {
00069
00070 friend class boost::serialization::access;
00071
00072 template<class Archive> void serialize(Archive & ar, const unsigned int version) {
00073 ar & L;
00074 ar & alpha;
00075 ar & weightSum;
00076 }
00077
00078 Pixel(): L(0.f), alpha(0.f), weightSum(0.f) { }
00079 XYZColor L;
00080 float alpha, weightSum;
00081 };
00082
00083
00084 struct FloatPixel {
00085
00086 friend class boost::serialization::access;
00087
00088 template<class Archive> void serialize(Archive & ar, const unsigned int version) {
00089 ar & V;
00090 ar & weightSum;
00091 }
00092
00093 FloatPixel(): V(0.f), weightSum(0.f) { }
00094 float V, weightSum;
00095 };
00096
00097
00098 class Buffer {
00099 public:
00100 Buffer(int x, int y) : xPixelCount(x), yPixelCount(y) {
00101 pixels = new BlockedArray<Pixel>(x, y);
00102 }
00103
00104 virtual ~Buffer() {
00105 delete pixels;
00106 }
00107
00108 void Add(int x, int y, XYZColor L, float alpha, float wt) {
00109 Pixel &pixel = (*pixels)(x, y);
00110 pixel.L.AddWeighted(wt, L);
00111 pixel.alpha += alpha * wt;
00112 pixel.weightSum += wt;
00113 }
00114
00115 void Clear() {
00116 for (int y = 0, offset = 0; y < yPixelCount; ++y) {
00117 for (int x = 0; x < xPixelCount; ++x, ++offset) {
00118 Pixel &pixel = (*pixels)(x, y);
00119 pixel.L.c[0] = 0.0f;
00120 pixel.L.c[1] = 0.0f;
00121 pixel.L.c[2] = 0.0f;
00122 pixel.alpha = 0.0f;
00123 pixel.weightSum = 0.0f;
00124 }
00125 }
00126 }
00127
00128 virtual void GetData(XYZColor *color, float *alpha) const = 0;
00129 virtual float GetData(int x, int y, XYZColor *color, float *alpha) const = 0;
00130 bool isFramebuffer;
00131 int xPixelCount, yPixelCount;
00132 float scaleFactor;
00133 BlockedArray<Pixel> *pixels;
00134 };
00135
00136
00137 class RawBuffer : public Buffer {
00138 public:
00139 RawBuffer(int x, int y) : Buffer(x, y) { }
00140
00141 virtual ~RawBuffer() { }
00142
00143 virtual void GetData(XYZColor *color, float *alpha) const {
00144 for (int y = 0, offset = 0; y < yPixelCount; ++y) {
00145 for (int x = 0; x < xPixelCount; ++x, ++offset) {
00146 const Pixel &pixel = (*pixels)(x, y);
00147 color[offset] = pixel.L;
00148 alpha[offset] = pixel.alpha;
00149 }
00150 }
00151 }
00152 virtual float GetData(int x, int y, XYZColor *color, float *alpha) const {
00153 const Pixel &pixel = (*pixels)(x, y);
00154 *color = pixel.L;
00155 *alpha = pixel.alpha;
00156 return pixel.weightSum;
00157 }
00158 };
00159
00160
00161 class PerPixelNormalizedBuffer : public Buffer {
00162 public:
00163 PerPixelNormalizedBuffer(int x, int y) : Buffer(x, y) { }
00164
00165 virtual ~PerPixelNormalizedBuffer() { }
00166
00167 virtual void GetData(XYZColor *color, float *alpha) const {
00168 for (int y = 0, offset = 0; y < yPixelCount; ++y) {
00169 for (int x = 0; x < xPixelCount; ++x, ++offset) {
00170 const Pixel &pixel = (*pixels)(x, y);
00171 if (pixel.weightSum == 0.f) {
00172 color[offset] = XYZColor(0.f);
00173 alpha[offset] = 0.f;
00174 } else {
00175 float inv = 1.f / pixel.weightSum;
00176 color[offset] = pixel.L * inv;
00177 alpha[offset] = pixel.alpha * inv;
00178 }
00179 }
00180 }
00181 }
00182 virtual float GetData(int x, int y, XYZColor *color, float *alpha) const {
00183 const Pixel &pixel = (*pixels)(x, y);
00184 if (pixel.weightSum == 0.f) {
00185 *color = XYZColor(0.f);
00186 *alpha = 0.f;
00187 } else {
00188 *color = pixel.L / pixel.weightSum;
00189 *alpha = pixel.alpha;
00190 }
00191 return pixel.weightSum;
00192 }
00193 };
00194
00195
00196 class PerPixelNormalizedFloatBuffer {
00197 public:
00198 PerPixelNormalizedFloatBuffer(int x, int y) {
00199 floatpixels = new BlockedArray<FloatPixel>(x, y);
00200 }
00201
00202 ~PerPixelNormalizedFloatBuffer() {
00203 delete floatpixels;
00204 }
00205
00206 void Add(int x, int y, float value, float wt) {
00207 FloatPixel &fpixel = (*floatpixels)(x, y);
00208 fpixel.V += value;
00209 fpixel.weightSum += wt;
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 float GetData(int x, int y) const {
00229 const FloatPixel &pixel = (*floatpixels)(x, y);
00230 if (pixel.weightSum == 0.f) {
00231 return 0.f;
00232 }
00233 return pixel.V / pixel.weightSum;
00234 }
00235 private:
00236 BlockedArray<FloatPixel> *floatpixels;
00237 };
00238
00239
00240 class PerScreenNormalizedBuffer : public Buffer {
00241 public:
00242 PerScreenNormalizedBuffer(int x, int y, const double *samples) :
00243 Buffer(x, y), numberOfSamples_(samples) { }
00244
00245 virtual ~PerScreenNormalizedBuffer() { }
00246
00247 virtual void GetData(XYZColor *color, float *alpha) const {
00248 const double inv = xPixelCount * yPixelCount / *numberOfSamples_;
00249 for (int y = 0, offset = 0; y < yPixelCount; ++y) {
00250 for (int x = 0; x < xPixelCount; ++x, ++offset) {
00251 const Pixel &pixel = (*pixels)(x, y);
00252 color[offset] = pixel.L * inv;
00253 if (pixel.weightSum > 0.f)
00254 alpha[offset] = pixel.alpha / pixel.weightSum;
00255 else
00256 alpha[offset] = 0.f;
00257 }
00258 }
00259 }
00260 virtual float GetData(int x, int y, XYZColor *color, float *alpha) const {
00261 const Pixel &pixel = (*pixels)(x, y);
00262 if (pixel.weightSum > 0.f) {
00263 *color = pixel.L * (xPixelCount * yPixelCount / *numberOfSamples_);
00264 *alpha = pixel.alpha;
00265 } else {
00266 *color = XYZColor(0.f);
00267 *alpha = 0.f;
00268 }
00269 return pixel.weightSum;
00270 }
00271 private:
00272 const double *numberOfSamples_;
00273 };
00274
00275
00276 class BufferGroup {
00277 public:
00278 BufferGroup(const string &n) : numberOfSamples(0.f), name(n),
00279 enable(true), globalScale(1.f), temperature(0.f),
00280 rgbScale(1.f), scale(1.f) { }
00281 ~BufferGroup() {
00282 for(vector<Buffer *>::iterator buffer = buffers.begin(); buffer != buffers.end(); ++buffer)
00283 delete *buffer;
00284 }
00285
00286 void CreateBuffers(const vector<BufferConfig> &configs, int x, int y) {
00287 for(vector<BufferConfig>::const_iterator config = configs.begin(); config != configs.end(); ++config) {
00288 switch ((*config).type) {
00289 case BUF_TYPE_PER_PIXEL:
00290 buffers.push_back(new PerPixelNormalizedBuffer(x, y));
00291 break;
00292 case BUF_TYPE_PER_SCREEN:
00293 buffers.push_back(new PerScreenNormalizedBuffer(x, y, &numberOfSamples));
00294 break;
00295 case BUF_TYPE_RAW:
00296 buffers.push_back(new RawBuffer(x, y));
00297 break;
00298 default:
00299 assert(0);
00300 }
00301 }
00302 }
00303
00304 Buffer *getBuffer(int index) {
00305 return buffers[index];
00306 }
00307 double numberOfSamples;
00308 vector<Buffer *> buffers;
00309 string name;
00310 bool enable;
00311 float globalScale, temperature;
00312 RGBColor rgbScale;
00313 XYZColor scale;
00314 };
00315
00316
00317 class GREYCStorationParams {
00318 public:
00319 GREYCStorationParams() { Reset(); }
00320 void Reset() {
00321 enabled = false;
00322 amplitude = 40.0f;
00323 nb_iter = 2;
00324 sharpness = 0.8f;
00325 anisotropy = 0.2f;
00326 alpha = 0.8f;
00327 sigma = 1.1f;
00328 fast_approx = true;
00329 gauss_prec = 2.0f;
00330 dl = 0.8f;
00331 da = 30.0f;
00332 interp = 0;
00333 tile = 0;
00334 btile = 4;
00335 threads = 1;
00336 }
00337
00338 bool enabled, fast_approx;
00339 unsigned int nb_iter, interp, tile, btile, threads;
00340 float amplitude, sharpness, anisotropy, alpha, sigma, gauss_prec, dl, da;
00341 };
00342
00343
00344 class ChiuParams {
00345 public:
00346 ChiuParams() { Reset(); }
00347 void Reset() {
00348 enabled = false;
00349 radius = 3;
00350 includecenter = false;
00351 }
00352
00353 bool enabled, includecenter;
00354 double radius;
00355 };
00356
00357
00358
00359 class Histogram {
00360 public:
00361 Histogram();
00362 ~Histogram();
00363 void Calculate(vector<RGBColor> &pixels, unsigned int width, unsigned int height);
00364 void MakeImage(unsigned char *outPixels, unsigned int width, unsigned int height, int options);
00365 private:
00366 void CheckBucketNr();
00367 int m_bucketNr, m_newBucketNr;
00368 float *m_buckets;
00369 int m_zones[11];
00370 float m_lowRange, m_highRange, m_bucketSize;
00371 float m_displayGamma;
00372 boost::mutex m_mutex;
00373 };
00374
00375
00376 class Film {
00377 public:
00378
00379
00380 Film(int xres, int yres, int haltspp, int halttime) :
00381 xResolution(xres), yResolution(yres), EV(0.f),
00382 haltSamplePerPixel(haltspp), haltTime(halttime), enoughSamplePerPixel(false),
00383 scene(NULL), histogram(NULL) {
00384 samplePerPass = (double)xResolution * (double)yResolution;
00385 boost::xtime_get(&creationTime, boost::TIME_UTC);
00386 }
00387 virtual ~Film() { delete histogram; }
00388
00389 virtual void AddSample(Contribution *contrib) = 0;
00390 virtual void AddSampleCount(float count) = 0;
00391 virtual void WriteImage(ImageType type) = 0;
00392 virtual void WriteFilm(const string &filename) = 0;
00393 virtual void CheckWriteOuputInterval() = 0;
00394
00395 virtual void TransmitFilm(std::basic_ostream<char> &stream, bool clearBuffers = true, bool transmitParams = false) = 0;
00396 virtual float UpdateFilm(std::basic_istream<char> &stream) = 0;
00397 virtual void GetSampleExtent(int *xstart, int *xend, int *ystart, int *yend) const = 0;
00398
00399 virtual void RequestBufferGroups(const vector<string> &bg) = 0;
00400 virtual int RequestBuffer(BufferType type, BufferOutputConfig output, const string& filePostfix) = 0;
00401
00402 virtual void CreateBuffers() { }
00403 virtual u_int GetNumBufferConfigs() const = 0;
00404 virtual const BufferConfig& GetBufferConfig(u_int index) const = 0;
00405 virtual u_int GetNumBufferGroups() const = 0;
00406 virtual string GetGroupName(u_int index) const = 0;
00407 virtual void SetGroupEnable(u_int index, bool status) = 0;
00408 virtual bool GetGroupEnable(u_int index) const = 0;
00409 virtual void SetGroupScale(u_int index, float value) = 0;
00410 virtual float GetGroupScale(u_int index) const = 0;
00411 virtual void SetGroupRGBScale(u_int index, const RGBColor &value) = 0;
00412 virtual RGBColor GetGroupRGBScale(u_int index) const = 0;
00413 virtual void SetGroupTemperature(u_int index, float value) = 0;
00414 virtual float GetGroupTemperature(u_int index) const = 0;
00415 virtual unsigned char* getFrameBuffer() = 0;
00416 virtual void updateFrameBuffer() = 0;
00417 virtual float getldrDisplayInterval() = 0;
00418 void getHistogramImage(unsigned char *outPixels, int width, int height, int options);
00419
00420 virtual u_int GetXPixelCount() const = 0;
00421 virtual u_int GetYPixelCount() const = 0;
00422
00423 void SetScene(Scene *scene1) { scene = scene1; }
00424
00425
00426 virtual void SetParameterValue(luxComponentParameters param, double value, int index) = 0;
00427 virtual double GetParameterValue(luxComponentParameters param, int index) = 0;
00428 virtual double GetDefaultParameterValue(luxComponentParameters param, int index) = 0;
00429 virtual void SetStringParameterValue(luxComponentParameters param, const string& value, int index) = 0;
00430 virtual string GetStringParameterValue(luxComponentParameters param, int index) = 0;
00431
00432
00433 int xResolution, yResolution;
00434 float EV;
00435
00436
00437
00438 int haltSamplePerPixel;
00439
00440 int haltTime;
00441 bool enoughSamplePerPixel;
00442
00443 Scene *scene;
00444
00445 Histogram *histogram;
00446
00447 protected:
00448
00449 double samplePerPass;
00450
00451
00452 boost::xtime creationTime;
00453 };
00454
00455
00456 void ApplyImagingPipeline(vector<XYZColor> &pixels,
00457 int xResolution, int yResolution,
00458 const GREYCStorationParams &GREYCParams, const ChiuParams &chiuParams,
00459 ColorSystem &colorSpace, Histogram *histogram, bool HistogramEnabled,
00460 bool &haveBloomImage, XYZColor *&bloomImage, bool bloomUpdate,
00461 float bloomRadius, float bloomWeight,
00462 bool VignettingEnabled, float VignetScale,
00463 bool aberrationEnabled, float aberrationAmount,
00464 bool &haveGlareImage, XYZColor *&glareImage, bool glareUpdate,
00465 float glareAmount, float glareRadius, int glareBlades,
00466 const char *tonemap, const ParamSet *toneMapParams, float gamma,
00467 float dither);
00468
00469 }
00470
00471 #endif // LUX_FILM_H