/**
 * @file pfstmo_reinhard02.cpp
 * @brief Tone map XYZ channels using Reinhard02 model
 *
 * Photographic Tone Reproduction for Digital Images.
 * E. Reinhard, M. Stark, P. Shirley, and J. Ferwerda.
 * In ACM Transactions on Graphics, 2002.
 *
 *
 * This file is a part of LuminanceHDR package, based on pfstmo.
 * ----------------------------------------------------------------------
 * Copyright (C) 2003,2004 Grzegorz Krawczyk
 *
 *  This program 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 program 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 program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * ----------------------------------------------------------------------
 *
 * @author Grzegorz Krawczyk, <krawczyk@mpi-sb.mpg.de>
 *
 * $Id: pfstmo_reinhard02.cpp,v 1.3 2008/09/04 12:46:49 julians37 Exp $
 */

#include <iostream>
#include <math.h>
#include <cstddef>

#include "Libpfs/frame.h"
#include "Libpfs/exception.h"
#include "Libpfs/progress.h"
#include "tmo_reinhard02.h"

void pfstmo_reinhard02(pfs::Frame& frame, float key, float phi, int num, int low, int high, bool use_scales, pfs::Progress &ph )
{
  //--- default tone mapping parameters;
  //float key = 0.18;
  //float phi = 1.0;
  //int num = 8;
  //int low = 1;
  //int high = 43;
  //bool use_scales = false;
  bool temporal_coherent = false;
#ifndef NDEBUG
  std::cout << "pfstmo_reinhard02 (";
  std::cout << "key: " << key;
  std::cout << ", phi: " << phi;
  std::cout << ", range: " << num;
  std::cout << ", lower scale: " << low;
  std::cout << ", upper scale: " << high;
  std::cout << ", use scales: " << use_scales << ")" << std::endl;
#endif
  pfs::Channel *X, *Y, *Z;
  frame.getXYZChannels( X, Y, Z );
  //---

  if ( Y==NULL || X==NULL || Z==NULL ) {
     throw pfs::Exception( "Missing X, Y, Z channels in the PFS stream" );
  }

  frame.getTags().setTag("LUMINANCE", "RELATIVE");
  // tone mapping
  size_t w = Y->getWidth();
  size_t h = Y->getHeight();
  pfs::Array2Df L(w, h);

  Reinhard02 tmoperator( Y, &L, use_scales, key, phi, num, low, high, temporal_coherent, ph );

  tmoperator.tmo_reinhard02();

  // TODO: this section can be rewritten using SSE Function
  for (size_t x = 0; x < w; x++)
  {
    for (size_t y = 0; y < h; y++)
    {
      float yr = (*Y)(x,y);
      float scale = 0.f;
      if (yr != 0.f)
      {
         scale = L(x,y) / yr;
      }

      (*Y)(x,y) *= scale;
      (*X)(x,y) *= scale;
      (*Z)(x,y) *= scale;
    }
  }
  if (!ph.canceled())
  {
      ph.setValue(100);
  }
}
