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

//#define DJ_DBG
#include "djImageOpColor.h"
#include <djMath.h>

namespace dj {

// XXX Core dumps on FreeBSD 6.1.

/*#define _CONVERT_U8(IN) clamp(int(IN), pixelU8Min, pixelU8Max)
#define _CONVERT_U16(IN) clamp(int(IN), pixelU16Min, pixelU16Max)
#define _CONVERT_F32(IN) (IN)

#define _LUT(TYPE) \
  int value##TYPE [pixel##TYPE##Range][pixelFormatMax]; \
  int tmp##TYPE [pixel##TYPE##Range][pixelFormatMax]; \
  for (int c = 0; c < channels; ++c) \
    for (int i = 0; i < pixel##TYPE##Range; ++i) { \
      value##TYPE[i][c] = int(i * valueP[c]); \
      tmp##TYPE[i][c] = int(i * tmpP[c]); \
    }
#define _LUT_U8() _LUT(U8)
#define _LUT_U16() _LUT(U16)
#define _LUT_F32()

//#define _OP_U8(C) \
//  outP[C] = _CONVERT_U8(inP[C] * valueP[C] + greyP[0] * tmpP[C]);
#define _OP_U8(C) \
  outP[C] = _CONVERT_U8(valueU8[inP[C]][C] + tmpU8[greyP[0]][C]);
#define _OP_U16(C) \
  outP[C] = _CONVERT_U16(valueU16[inP[C]][C] + tmpU16[greyP[0]][C]);
#define _OP_F32(C) \
  outP[C] = inP[C] * valueP[C] + greyP[0] * tmpP[C];

#define _LOOP() \
  for (int x = 0; x < w; ++x, inP += channels, outP += channels, ++greyP)

#define _SATURATION(TYPE) \
  \
  const Pixel##TYPE * inP = \
    reinterpret_cast<const Pixel##TYPE *>(input.data()); \
  Pixel##TYPE * outP = \
    reinterpret_cast<Pixel##TYPE *>(out.data()); \
  \
  Color value(format, PIXEL_F32), tmp(format, PIXEL_F32); \
  convert(_value, &value); \
  const PixelF32 * const valueP = \
    reinterpret_cast<const PixelF32 *>(value.data()); \
  PixelF32 * const tmpP = reinterpret_cast<PixelF32 *>(tmp.data()); \
  for (int c = 0; c < channels; ++c) \
    tmpP[c] = 1.0 - valueP[c]; \
  PixelData grey(Vec2i(w, 1), Pixel(PIXEL_L, PIXEL_##TYPE)); \
  _LUT_##TYPE() \
  \
  for (int y = 0; y < h; ++y) { \
    pixelCopy(inP, grey.data(), w, input.pixel(), grey.pixel()); \
    const Pixel##TYPE * greyP = reinterpret_cast<Pixel##TYPE *>(grey.data()); \
    switch (channels) { \
      case 1: \
        _LOOP() \
          _OP_##TYPE(0) \
        break; \
      case 2: \
        _LOOP() { \
          _OP_##TYPE(0) \
          _OP_##TYPE(1) \
        } \
        break; \
      case 3: \
        _LOOP() { \
          _OP_##TYPE(0) \
          _OP_##TYPE(1) \
          _OP_##TYPE(2) \
        } \
        break; \
      case 4: \
        _LOOP() { \
          _OP_##TYPE(0) \
          _OP_##TYPE(1) \
          _OP_##TYPE(2) \
          _OP_##TYPE(3) \
        } \
        break; \
      default: \
        _LOOP() \
          for (int c = 0; c < channels; ++c) \
            _OP_##TYPE(c) \
    } \
  }

const Image ImageOpSaturation::work(const InputList & in) const
{	
  if (! in.size()) return Image();
  const Image & input = *in[0];
  
  DJ_DBG_FNC("dj::ImageOpSaturation::work");
	
	Color _value(2.0);
  
  // Setup.
  //
  Image out(workInfo(in));
  out.proxy(input.proxy());
  out.tagList(input.tagList());
  DJ_DBG_PRN("input = " << input);
  DJ_DBG_PRN("output = " << out);
  
  // Work.
  //
  const int w = out.width(), h = out.height();
  const PIXEL_FORMAT format = out.format();
  const int channels = pixelSize(format);
  switch (out.type()) {
    case PIXEL_U8: { _SATURATION(U8) } break;
    case PIXEL_U16: { _SATURATION(U16) } break;
    case PIXEL_F32: { _SATURATION(F32) } break;
  }
  
  return out;
}*/

void ImageOpSaturation::workF32(
  PixelF32 * in, int size, PIXEL_FORMAT format
) const {
  
	const int channels = pixelSize(format);
		
	PixelData grey(Vec2i(size, 1), Pixel(PIXEL_L, PIXEL_F32));
	pixelCopy(
	  in, grey.data(), size, Pixel(format, PIXEL_F32), grey.pixel()
  );
  Color value(format, PIXEL_F32);
  convert(_value, &value);
	
	const PixelF32 * greyP =
    reinterpret_cast<const PixelF32 *>(grey.data());
	const PixelF32 * const valueP =
    reinterpret_cast<const PixelF32 *>(value.data());
  for (int x = 0; x < size; ++x, in += channels, ++greyP)
    for (int c = 0; c < channels; ++c)
      in[c] = in[c] * valueP[c] + *greyP * (1.0 - valueP[c]);
}

}
