/*------------------------------------------------------------------------------
 src/lib/djImage/imageIoDpxLut.cxx
 
 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

//#define DJ_DBG
#include "djImageIoDpx.h"
#include <djImageOpCore.h>
#include <djImageOpXform.h>

namespace dj {
namespace ImageIoDpx {

void dpxLutUnprint(
  PixelF32 * out, int size,
  double black, double white, double gamma, double softClip
) {
  DJ_DBG_FNC("dj::ImageIoDpx::dpxLutUnprint");
  DJ_DBG_PRN("size = " << size);
  DJ_DBG_PRN("black = " << black);
  DJ_DBG_PRN("white = " << white);
  DJ_DBG_PRN("gamma = " << gamma);
  DJ_DBG_PRN("soft clip = " << softClip);
  
  //double breakPoint, gain, offset, kneeOffset, kneeGain;
  //for (int c = 0; c < channelsColor; ++c) {
  
  double gain = 1.f / (
    1.0 - pow(
      pow(10.0, (black - white) * 2.048 / 0.6),
      (1.0 / gamma) / 1.7
    )
  );
  double offset = gain - 1.0;

  // XXX Soft clip?
  //
  const double sc = softClip * 50 / 1023.0;
  double breakPoint = white - sc;
  double kneeOffset =
    pow(pow(10.0, (breakPoint - white) * 2.048 / 0.6), (1.0 / gamma) / 1.7) *
    gain - offset;
  double kneeGain = (1.0 - kneeOffset) / pow(5.0 * sc, sc / 100.0);
  
  DJ_DBG_PRN("break point = " << breakPoint);
  DJ_DBG_PRN("gain = " << gain);
  DJ_DBG_PRN("offset = " << offset);
  DJ_DBG_PRN("knee offset = " << kneeOffset);
  DJ_DBG_PRN("knee gain = " << kneeGain);
  
  pixelGradient(out, size, Pixel(PIXEL_L, PIXEL_F32));
  
  for (int i = 0; i < size; ++i, ++out) {
      
    if (*out < black) {
      
      *out = 0.0;
        
    } else if (*out > breakPoint) {
      
      const PixelF32 sc = softClip * 50 / 1023.0;
      *out =
        pow(*out - breakPoint, sc / 100.0) *
        kneeGain + kneeOffset;
          
    } else {
      
      *out =
        pow(pow(10.0, (*out - white) * 2.048 / 0.6), (1.0 / gamma) / 1.7) *
        gain - offset;
    }
    
    DJ_DBG_PRN("lut[" << i << "] = " << *out);
  }
}

void dpxLutPrint(
  PixelF32 * out, int size,
  double black, double white, double gamma
) {
  DJ_DBG_FNC("dj::ImageIoDpx::dpxLutPrint");
  DJ_DBG_PRN("size = " << size);
  DJ_DBG_PRN("black = " << black);
  DJ_DBG_PRN("white = " << white);
  DJ_DBG_PRN("gamma = " << gamma);
  
  double gain = 1.0 / (
    1.0 - pow(pow(10.0, (black - white) * 2.048 / 0.6), (1.0 / gamma) / 1.7)
  );
  double offset = gain - 1.0;
  DJ_DBG_PRN("gain = " << gain);
  DJ_DBG_PRN("offset = " << offset);
  
  pixelGradient(out, size, Pixel(PIXEL_L, PIXEL_F32));
  
  for (int i = 0; i < size; ++i, ++out) {
  
    *out =
      white +
      log10(pow((*out + offset) / gain, 1.7 / (1.0 / gamma))) / (2.048 / 0.6);
      
    DJ_DBG_PRN("lut[" << i << "] = " << *out);
  }
}

}
}
