00001
00024 #ifndef _PHOTOMETRIC_VIGNETTING_CORRECTION_H
00025 #define _PHOTOMETRIC_VIGNETTING_CORRECTION_H
00026
00027 #include <vector>
00028 #include <functional>
00029 #include <boost/version.hpp>
00030 #if BOOST_VERSION>104700
00031 #include <boost/random/taus88.hpp>
00032 #define RANDOMGENERATOR boost::random::taus88
00033 #else
00034 #include <boost/random/mersenne_twister.hpp>
00035 #define RANDOMGENERATOR boost::mt19937
00036 #endif
00037
00038 #include <vigra/stdimage.hxx>
00039 #include <vigra/numerictraits.hxx>
00040 #include <vigra/array_vector.hxx>
00041
00042 #include <hugin_math/hugin_math.h>
00043 #include <vigra_ext/lut.h>
00044 #include <vigra_ext/utils.h>
00045 #include <panodata/SrcPanoImage.h>
00046
00047
00048 namespace HuginBase { namespace Photometric {
00049
00050
00056 template <class VTIn>
00057 class ResponseTransform
00058 {
00059
00060 public:
00062 typedef typename vigra_ext::ValueTypeTraits<VTIn>::value_type VT1;
00063
00065 typedef std::vector<double> LUT;
00066
00067
00068 public:
00070 ResponseTransform();
00071
00073 ResponseTransform(const HuginBase::SrcPanoImage & src);
00074
00076 virtual ~ResponseTransform() {};
00077
00078 private:
00080 void initWithSrcImg(const HuginBase::SrcPanoImage & src);
00081
00082
00083 public:
00085 void setFlatfield(const vigra::FImage * flat)
00086 { m_flatfield = flat; }
00087
00089 double calcVigFactor(hugin_utils::FDiff2D d) const;
00090
00091 void enforceMonotonicity()
00092 {
00093 vigra_ext::enforceMonotonicity(m_lutR);
00094 }
00095
00097 typename vigra::NumericTraits<VT1>::RealPromote
00098 apply(VT1 v, const hugin_utils::FDiff2D & pos, vigra::VigraTrueType) const;
00099
00101 typename vigra::NumericTraits<VT1>::RealPromote
00102 apply(VT1 v, const hugin_utils::FDiff2D & pos) const;
00103
00105 typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
00106 apply(vigra::RGBValue<VT1> v, const hugin_utils::FDiff2D & pos, vigra::VigraFalseType) const;
00107
00109 typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
00110 apply(vigra::RGBValue<VT1> v, const hugin_utils::FDiff2D & pos) const;
00111
00112
00114 template <class T>
00115 typename vigra::NumericTraits<T>::RealPromote
00116 operator()(T v, const hugin_utils::FDiff2D & pos) const { return apply(v, pos); }
00117
00118
00119
00120 public:
00121
00122 LUT m_lutR;
00123 double m_radiusScale;
00124 vigra_ext::LUTFunctor<VT1, LUT> m_lutRFunc;
00125 const vigra::FImage * m_flatfield;
00126 double m_srcExposure;
00127 std::vector<double> m_RadialVigCorrCoeff;
00128 hugin_utils::FDiff2D m_RadialVigCorrCenter;
00129 int m_VigCorrMode;
00130 double m_WhiteBalanceRed;
00131 double m_WhiteBalanceBlue;
00132
00133 HuginBase::SrcPanoImage m_src;
00134 };
00135
00136
00142 template <class VTIn, class VTOut>
00143 class InvResponseTransform : public ResponseTransform<VTIn>
00144 {
00145
00146 typedef ResponseTransform<VTIn> Base;
00147
00148 public:
00149 typedef typename vigra_ext::ValueTypeTraits<VTIn>::value_type VT1;
00150 typedef typename vigra::NumericTraits<VT1>::RealPromote VTInCompReal;
00151 typedef typename vigra_ext::ValueTypeTraits<VTOut>::value_type dest_type;
00152
00153 typedef std::vector<double> LUT;
00154 typedef std::vector<dest_type> LUTD;
00155
00156
00157 public:
00159 InvResponseTransform();
00160
00162 InvResponseTransform(const HuginBase::SrcPanoImage & src);
00163
00165 virtual ~InvResponseTransform() {};
00166
00167 private:
00169 void init(const HuginBase::SrcPanoImage & src);
00170
00171
00172 public:
00174 void setHDROutput(bool hdrMode, double destExposure);
00175
00177 void setOutput(double destExposure, const LUTD & destLut, double scale);
00178
00179 void enforceMonotonicity()
00180 {
00181 if (Base::m_lutR.size()) {
00182 vigra_ext::enforceMonotonicity(Base::m_lutR);
00183
00184 m_lutRInvFunc = vigra_ext::InvLUTFunctor<VT1, LUT>(Base::m_lutR);
00185 }
00186 }
00187
00194 double dither(const double &v) const;
00195
00197 typename vigra::NumericTraits<dest_type>::RealPromote
00198 apply(VT1 v, const hugin_utils::FDiff2D & pos, vigra::VigraTrueType) const;
00199
00201 typename vigra::NumericTraits<dest_type>::RealPromote
00202 apply(VT1 v, const hugin_utils::FDiff2D & pos) const;
00203
00205 typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
00206 apply(vigra::RGBValue<VT1> v, const hugin_utils::FDiff2D & pos, vigra::VigraFalseType) const;
00207
00209 typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote
00210 apply(vigra::RGBValue<VT1> v, const hugin_utils::FDiff2D & pos) const;
00211
00212
00214 template <class T>
00215 typename vigra::NumericTraits<T>::RealPromote
00216 operator()(T v, const hugin_utils::FDiff2D & pos) const
00217 {
00218 return apply(v, pos);
00219 }
00220
00222 template <class T, class A>
00223 A hdrWeight(T v, A a) const
00224 {
00225 if (m_hdrMode && a > 0) {
00226 return vigra::NumericTraits<A>::fromRealPromote(vigra_ext::getMaxComponent(v)/(double)vigra_ext::LUTTraits<T>::max()*vigra_ext::LUTTraits<A>::max());
00227 } else {
00228 return a;
00229 }
00230 }
00231
00232 void emitGLSL(std::ostringstream& oss, std::vector<double>& invLut, std::vector<double>& destLut) const;
00233
00234 protected:
00235
00236 vigra_ext::InvLUTFunctor<VT1, LUT> m_lutRInvFunc;
00237 LUTD m_destLut;
00238 vigra_ext::LUTFunctor<VTInCompReal, LUTD> m_destLutFunc;
00239 double m_destExposure;
00240 bool m_hdrMode;
00241 double m_intScale;
00242
00243 private:
00244 RANDOMGENERATOR Twister;
00245 };
00246
00247
00248 }}
00249
00250
00251
00252
00253
00254
00255
00256 namespace HuginBase { namespace Photometric {
00257
00258
00259 template <class VTIn>
00260 ResponseTransform<VTIn>::ResponseTransform()
00261 {
00262 m_radiusScale=0;
00263 m_flatfield = 0;
00264 }
00265
00266 template <class VTIn>
00267 ResponseTransform<VTIn>::ResponseTransform(const HuginBase::SrcPanoImage & src)
00268 {
00269 initWithSrcImg(src);
00270 }
00271
00272
00273 template <class VTIn>
00274 void ResponseTransform<VTIn>::initWithSrcImg(const HuginBase::SrcPanoImage & src)
00275 {
00276
00277 m_flatfield = 0;
00278 m_src = src;
00279 m_radiusScale = 1.0/sqrt(m_src.getSize().x/2.0*m_src.getSize().x/2.0 + m_src.getSize().y/2.0*m_src.getSize().y/2.0);
00280 m_srcExposure = m_src.getExposure();
00281
00282 m_RadialVigCorrCoeff = m_src.getRadialVigCorrCoeff();
00283 m_RadialVigCorrCenter = m_src.getRadialVigCorrCenter();
00284 m_VigCorrMode = m_src.getVigCorrMode();
00285 m_WhiteBalanceRed = m_src.getWhiteBalanceRed();
00286 m_WhiteBalanceBlue = m_src.getWhiteBalanceBlue();
00287
00288
00289 if (m_src.getResponseType() != HuginBase::SrcPanoImage::RESPONSE_LINEAR) {
00290
00291 double lutLenD = vigra_ext::LUTTraits<VT1>::max();
00292
00293
00294 size_t lutLen=0;
00295 if (lutLenD == 1.0 || (lutLenD > ((1<<10)-1))) {
00296 lutLen = (1<<10);
00297 } else {
00298 lutLen = size_t(lutLenD) + 1;
00299 }
00300 switch (m_src.getResponseType())
00301 {
00302 case HuginBase::SrcPanoImage::RESPONSE_EMOR:
00303 {
00304 if (lutLen == 1<<10) {
00305 vigra_ext::EMoR::createEMoRLUT(m_src.getEMoRParams(), m_lutR);
00306 } else {
00307
00308 LUT tmp;
00309 vigra_ext::EMoR::createEMoRLUT(m_src.getEMoRParams(), tmp);
00310 m_lutR.resize(lutLen);
00311 vigra_ext::resizeLUT(tmp, m_lutR);
00312 }
00313 }
00314 break;
00315 case HuginBase::SrcPanoImage::RESPONSE_GAMMA:
00316 m_lutR.resize(lutLen);
00317 vigra_ext::createGammaLUT(m_src.getGamma(), m_lutR);
00318 break;
00319 default:
00320
00321 vigra_fail("ResponseTransform: unknown response function type");
00322 break;
00323 }
00324 m_lutRFunc = vigra_ext::LUTFunctor<VT1, LUT>(m_lutR);
00325 }
00326 }
00327
00328
00329 template <class VTIn>
00330 double ResponseTransform<VTIn>::calcVigFactor(hugin_utils::FDiff2D d) const
00331 {
00332 if (m_VigCorrMode & HuginBase::SrcPanoImage::VIGCORR_RADIAL) {
00333 d = d - m_RadialVigCorrCenter;
00334
00335 d *= m_radiusScale;
00336 double vig = m_RadialVigCorrCoeff[0];
00337 double r2 = d.x*d.x + d.y*d.y;
00338 double r = r2;
00339 for (unsigned int i = 1; i < 4; i++) {
00340 vig += m_RadialVigCorrCoeff[i] * r;
00341 r *= r2;
00342 }
00343 return vig;
00344 } else if (m_VigCorrMode & HuginBase::SrcPanoImage::VIGCORR_FLATFIELD) {
00345
00346 if (m_flatfield) {
00347 int x = std::min(std::max(hugin_utils::roundi(d.x),0), m_flatfield->width()-1);;
00348 int y = std::min(std::max(hugin_utils::roundi(d.y),0), m_flatfield->height()-1);;
00349 return (*m_flatfield)(x,y);
00350 } else {
00351 return 1;
00352 }
00353 } else {
00354 return 1;
00355 }
00356 }
00357
00358
00359 template <class VTIn>
00360 typename vigra::NumericTraits<typename ResponseTransform<VTIn>::VT1>::RealPromote
00361 ResponseTransform<VTIn>::apply(typename ResponseTransform<VTIn>::VT1 v, const hugin_utils::FDiff2D & pos, vigra::VigraTrueType) const
00362 {
00363 typename vigra::NumericTraits<VT1>::RealPromote ret = v;
00364
00365
00366 ret = ret*calcVigFactor(pos)*m_srcExposure;
00367 if (m_lutR.size()) {
00368 return m_lutRFunc(ret);
00369 } else {
00370 return ret;
00371 }
00372 }
00373
00374 template <class VTIn>
00375 typename vigra::NumericTraits<vigra::RGBValue<typename ResponseTransform<VTIn>::VT1> >::RealPromote
00376 ResponseTransform<VTIn>::apply(vigra::RGBValue<typename ResponseTransform<VTIn>::VT1> v, const hugin_utils::FDiff2D & pos, vigra::VigraFalseType) const
00377 {
00378 typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote ret = v;
00379
00380 double common = calcVigFactor(pos)*m_srcExposure;
00381 ret = ret*common;
00382
00383 ret.red() = ret.red() * m_WhiteBalanceRed;
00384 ret.blue() = ret.blue() * m_WhiteBalanceBlue;
00385
00386 if (m_lutR.size()) {
00387 return m_lutRFunc(ret);
00388 } else {
00389 return ret;
00390 }
00391 }
00392
00393 template <class VTIn>
00394 typename vigra::NumericTraits<typename ResponseTransform<VTIn>::VT1>::RealPromote
00395 ResponseTransform<VTIn>::apply(typename ResponseTransform<VTIn>::VT1 v, const hugin_utils::FDiff2D & pos) const
00396 {
00397 typedef typename vigra::NumericTraits<VT1>::isScalar is_scalar;
00398 return apply(v, pos, is_scalar());
00399 }
00400
00401 template <class VTIn>
00402 typename vigra::NumericTraits<vigra::RGBValue<typename ResponseTransform<VTIn>::VT1> >::RealPromote
00403 ResponseTransform<VTIn>::apply(vigra::RGBValue<typename ResponseTransform<VTIn>::VT1> v, const hugin_utils::FDiff2D & pos) const
00404 {
00405 typedef typename vigra::NumericTraits<vigra::RGBValue<VT1> >::isScalar is_scalar;
00406 return apply(v, pos, is_scalar());
00407 }
00408
00409 template <class VTIn, class VTOut>
00410 InvResponseTransform<VTIn,VTOut>::InvResponseTransform()
00411 {
00412 m_destExposure = 1.0;
00413 m_hdrMode = false;
00414 m_intScale = 1;
00415 }
00416
00417 template <class VTIn, class VTOut>
00418 InvResponseTransform<VTIn,VTOut>::InvResponseTransform(const HuginBase::SrcPanoImage & src)
00419 : Base(src), m_hdrMode(false)
00420 {
00421 m_destExposure = 1.0;
00422 m_intScale = 1;
00423 if (Base::m_lutR.size()) {
00424
00425 m_lutRInvFunc = vigra_ext::InvLUTFunctor<VT1, LUT>(Base::m_lutR);
00426 }
00427 }
00428
00429 template <class VTIn, class VTOut>
00430 void InvResponseTransform<VTIn,VTOut>::init(const HuginBase::SrcPanoImage & src)
00431 {
00432 m_destExposure = 1.0;
00433 m_intScale = 1;
00434 Base::init(src);
00435 if (Base::m_lutR.size()) {
00436
00437 m_lutRInvFunc = vigra_ext::InvLUTFunctor<VT1, LUT>(Base::m_lutR);
00438 }
00439 }
00440
00441 template <class VTIn, class VTOut>
00442 void InvResponseTransform<VTIn,VTOut>::setHDROutput(bool hdrMode, double destExposure)
00443 {
00444 m_hdrMode = hdrMode;
00445 m_intScale = 1;
00446 m_destExposure = destExposure;
00447 m_destLut.clear();
00448 }
00449
00450 template <class VTIn, class VTOut>
00451 void InvResponseTransform<VTIn,VTOut>::setOutput(double destExposure, const LUTD & destLut, double scale)
00452 {
00453 m_hdrMode = false;
00454 m_destLut = destLut;
00455 if (m_destLut.size() > 0) {
00456 m_destLutFunc = vigra_ext::LUTFunctor<VTInCompReal, LUTD>(m_destLut);
00457 }
00458 m_destExposure = destExposure;
00459 m_intScale = scale;
00460 }
00461
00462
00463 template <class VTIn, class VTOut>
00464 double InvResponseTransform<VTIn,VTOut>::dither(const double &v) const
00465 {
00466 RANDOMGENERATOR &mt = const_cast<RANDOMGENERATOR &>(Twister);
00467 double vFraction = v - floor(v);
00468
00469 if (vFraction > 0.25 && vFraction <= 0.75) {
00470
00471 double random = 0.5 * (double)mt() / UINT_MAX;
00472 if ((vFraction - 0.25) >= random) {
00473 return ceil(v);
00474 } else {
00475 return floor(v);
00476 }
00477 } else {
00478 return v;
00479 }
00480 }
00481
00482
00483 template <class VTIn, class VTOut>
00484 typename vigra::NumericTraits<typename InvResponseTransform<VTIn,VTOut>::dest_type>::RealPromote
00485 InvResponseTransform<VTIn,VTOut>::apply(VT1 v, const hugin_utils::FDiff2D & pos, vigra::VigraTrueType) const
00486 {
00487
00488 typename vigra::NumericTraits<VT1>::RealPromote ret(v);
00489 if (Base::m_lutR.size()) {
00490 ret = m_lutRInvFunc(v);
00491 } else {
00492 ret /= vigra_ext::LUTTraits<VT1>::max();
00493 }
00494
00495 ret *= m_destExposure / (Base::calcVigFactor(pos) * Base::m_srcExposure);
00496
00497 if (m_destLut.size() > 0) {
00498 ret = m_destLutFunc(ret);
00499 }
00500
00501 if ( m_intScale > 1) {
00502 return dither(ret * m_intScale);
00503 }
00504 return ret;
00505 }
00506
00507
00508 template <class VTIn, class VTOut>
00509 typename vigra::NumericTraits<vigra::RGBValue<typename InvResponseTransform<VTIn,VTOut>::VT1> >::RealPromote
00510 InvResponseTransform<VTIn,VTOut>::apply(vigra::RGBValue<VT1> v, const hugin_utils::FDiff2D & pos, vigra::VigraFalseType) const
00511 {
00512 typename vigra::NumericTraits<vigra::RGBValue<VT1> >::RealPromote ret(v);
00513 if (Base::m_lutR.size()) {
00514 ret = m_lutRInvFunc(v);
00515 } else {
00516 ret /= vigra_ext::LUTTraits<VT1>::max();
00517 }
00518
00519
00520 ret *= m_destExposure/(Base::calcVigFactor(pos)*Base::m_srcExposure);
00521 ret.red() /= Base::m_WhiteBalanceRed;
00522 ret.blue() /= Base::m_WhiteBalanceBlue;
00523
00524 if (m_destLut.size() > 0) {
00525 ret = m_destLutFunc(ret);
00526 }
00527
00528 if (m_intScale > 1) {
00529 for (size_t i=0; i < 3; i++) {
00530 ret[i] = dither(ret[i] * m_intScale);
00531 }
00532 }
00533 return ret;
00534 }
00535
00536
00537 template <class VTIn, class VTOut>
00538 typename vigra::NumericTraits<typename InvResponseTransform<VTIn,VTOut>::dest_type>::RealPromote
00539 InvResponseTransform<VTIn,VTOut>::apply(VT1 v, const hugin_utils::FDiff2D & pos) const
00540 {
00541 typedef typename vigra::NumericTraits<VT1>::isScalar is_scalar;
00542 return apply(v, pos, is_scalar());
00543 }
00544
00545 template <class VTIn, class VTOut>
00546 typename vigra::NumericTraits<vigra::RGBValue<typename InvResponseTransform<VTIn,VTOut>::VT1> >::RealPromote
00547 InvResponseTransform<VTIn,VTOut>::apply(vigra::RGBValue<VT1> v, const hugin_utils::FDiff2D & pos) const
00548 {
00549 typedef typename vigra::NumericTraits<vigra::RGBValue<VT1> >::isScalar is_scalar;
00550 return apply(v, pos, is_scalar());
00551 }
00552
00553 template <class VTIn, class VTOut>
00554 void
00555 InvResponseTransform<VTIn,VTOut>::emitGLSL(std::ostringstream& oss, std::vector<double>& invLut, std::vector<double>& destLut) const
00556 {
00557 invLut.clear();
00558 invLut.reserve(Base::m_lutR.size());
00559
00560 for (int i = 0; i < Base::m_lutR.size(); i++) {
00561 double f = static_cast<double>(i) / (Base::m_lutR.size() - 1);
00562 double v = m_lutRInvFunc(f);
00563 invLut.push_back(v);
00564 }
00565
00566 destLut.clear();
00567 destLut.reserve(m_destLut.size());
00568
00569 for (typename LUTD::const_iterator lutI = m_destLut.begin(); lutI != m_destLut.end(); ++lutI) {
00570 typename LUTD::value_type entry = *lutI;
00571 destLut.push_back(entry);
00572 }
00573
00574 double invLutSize = Base::m_lutR.size();
00575 double pixelMax = vigra_ext::LUTTraits<VT1>::max();
00576 double destLutSize = m_destLut.size();
00577
00578 oss << " // invLutSize = " << invLutSize << endl
00579 << " // pixelMax = " << pixelMax << endl
00580 << " // destLutSize = " << destLutSize << endl
00581 << " // destExposure = " << m_destExposure << endl
00582 << " // srcExposure = " << Base::m_srcExposure << endl
00583 << " // whiteBalanceRed = " << Base::m_src.getWhiteBalanceRed() << endl
00584 << " // whiteBalanceBlue = " << Base::m_src.getWhiteBalanceBlue() << endl;
00585
00586 if (Base::m_lutR.size() > 0) {
00587 oss << " p.rgb = p.rgb * " << (invLutSize - 1.0) << ";" << endl
00588 << " vec2 invR = texture2DRect(InvLutTexture, vec2(p.r, 0.0)).sq;" << endl
00589 << " vec2 invG = texture2DRect(InvLutTexture, vec2(p.g, 0.0)).sq;" << endl
00590 << " vec2 invB = texture2DRect(InvLutTexture, vec2(p.b, 0.0)).sq;" << endl
00591 << " vec3 invX = vec3(invR.x, invG.x, invB.x);" << endl
00592 << " vec3 invY = vec3(invR.y, invG.y, invB.y);" << endl
00593 << " vec3 invA = fract(p.rgb);" << endl
00594 << " p.rgb = mix(invX, invY, invA);" << endl;
00595 }
00596
00597 if (Base::m_src.getVigCorrMode() & HuginBase::SrcPanoImage::VIGCORR_RADIAL) {
00598 oss << " // VigCorrMode=VIGCORR_RADIAL" << endl
00599 << " float vig = 1.0;" << endl
00600 << " {" << endl
00601 << " vec2 vigCorrCenter = vec2(" << Base::m_src.getRadialVigCorrCenter().x << ", "
00602 << Base::m_src.getRadialVigCorrCenter().y << ");" << endl
00603 << " float radiusScale=" << Base::m_radiusScale << ";" << endl
00604 << " float radialVigCorrCoeff0 = " << Base::m_src.getRadialVigCorrCoeff()[0] << ";" << endl
00605 << " float radialVigCorrCoeff1 = " << Base::m_src.getRadialVigCorrCoeff()[1] << ";" << endl
00606 << " float radialVigCorrCoeff2 = " << Base::m_src.getRadialVigCorrCoeff()[2] << ";" << endl
00607 << " float radialVigCorrCoeff3 = " << Base::m_src.getRadialVigCorrCoeff()[3] << ";" << endl
00608 << " vec2 src = texture2DRect(CoordTexture, gl_TexCoord[0].st).sq;" << endl
00609 << " vec2 d = src - vigCorrCenter;" << endl
00610 << " d *= radiusScale;" << endl
00611 << " vig = radialVigCorrCoeff0;" << endl
00612 << " float r2 = dot(d, d);" << endl
00613 << " float r = r2;" << endl
00614 << " vig += radialVigCorrCoeff1 * r;" << endl
00615 << " r *= r2;" << endl
00616 << " vig += radialVigCorrCoeff2 * r;" << endl
00617 << " r *= r2;" << endl
00618 << " vig += radialVigCorrCoeff3 * r;" << endl
00619 << " }" << endl;
00620 } else if (Base::m_src.getVigCorrMode() & HuginBase::SrcPanoImage::VIGCORR_FLATFIELD) {
00621 oss << " // VigCorrMode=VIGCORR_FLATFIELD" << endl
00622 << " float vig = 1.0;" << endl;
00623 } else {
00624 oss << " // VigCorrMode=none" << endl
00625 << " float vig = 1.0;" << endl;
00626 }
00627
00628 oss << " vec3 exposure_whitebalance = vec3("
00629 << (m_destExposure / (Base::m_srcExposure * Base::m_src.getWhiteBalanceRed())) << ", "
00630 << (m_destExposure / (Base::m_srcExposure)) << ", "
00631 << (m_destExposure / (Base::m_srcExposure * Base::m_src.getWhiteBalanceBlue())) << ");" << endl
00632 << " p.rgb = (p.rgb * exposure_whitebalance) / vig;" << endl;
00633
00634 if (m_destLut.size() > 0) {
00635 oss << " p.rgb = p.rgb * " << (destLutSize - 1.0) << ";" << endl
00636 << " vec2 destR = texture2DRect(DestLutTexture, vec2(p.r, 0.0)).sq;" << endl
00637 << " vec2 destG = texture2DRect(DestLutTexture, vec2(p.g, 0.0)).sq;" << endl
00638 << " vec2 destB = texture2DRect(DestLutTexture, vec2(p.b, 0.0)).sq;" << endl
00639 << " vec3 destX = vec3(destR.x, destG.x, destB.x);" << endl
00640 << " vec3 destY = vec3(destR.y, destG.y, destB.y);" << endl
00641 << " vec3 destA = fract(p.rgb);" << endl
00642 << " p.rgb = mix(destX, destY, destA);" << endl;
00643 }
00644
00645
00646 if (m_hdrMode) {
00647 oss << " p.a = max(p.r, max(p.g, p.b));" << endl;
00648 }
00649 }
00650
00651 }}
00652
00653 #endif // _H