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

//#define DJ_DBG
#include "djImageOpComp.h"

namespace dj {

void imageOpComp(
  const Image & in, Image * out, const Vec2i & position, bool premul
) {
  if (! out) return;
  
  DJ_DBG_FNC("dj::imageOpComp");
  DJ_DBG_PRN("in = " << in);
  DJ_DBG_PRN("out = " << *out);
  DJ_DBG_PRN("position = " << position);
  DJ_DBG_PRN("premul = " << premul);
  
  // Setup.
  //
  const Box2i ix = intersect(Box2i(out->size()), Box2i(position, in.size()));
  DJ_DBG_PRN("intersect = " << ix);
  if (! areaIsValid(ix)) return;
  PIXEL_FORMAT outFormat = out->format();
  PIXEL_FORMAT inFormat = PIXEL_FORMAT(0);
  switch (outFormat) {
    case PIXEL_L:
    case PIXEL_LA: inFormat = PIXEL_LA; break;
    case PIXEL_RGB:
    case PIXEL_RGBA: inFormat = PIXEL_RGBA; break;
  }
  Color inPixel(inFormat, PIXEL_F32), outPixel(outFormat, PIXEL_F32);

  // Work.
  //
  const int px = position.x(), py = position.y();
  const int x0 = ix.x0(), y0 = ix.y0(), x1 = ix.x1(), y1 = ix.y1();
  const int inChannels = pixelSize(inFormat);
  const int outChannels = pixelSize(outFormat);
  switch (outFormat) {
  
    case PIXEL_L:
    case PIXEL_RGB:
      for (int y = y0; y <= y1; ++y) {
        for (int x = x0; x <= x1; ++x) {
          in.pixel(x - px, y - py, &inPixel);
          out->pixel(x, y, &outPixel);
          const PixelF32 alpha = inPixel.f32(inChannels - 1);
          int c = 0;
          for (; c < outChannels; ++c)
            outPixel.f32(
              (premul ? inPixel.f32(c) : (inPixel.f32(c) * alpha)) +
                outPixel.f32(c) * (1.0 - alpha),
              c
            );
          out->pixel(outPixel, x, y);
        }
      }
      break;
  
    case PIXEL_LA:
    case PIXEL_RGBA:
      for (int y = y0; y <= y1; ++y) {
        for (int x = x0; x <= x1; ++x) {
          in.pixel(x - px, y - py, &inPixel);
          out->pixel(x, y, &outPixel);
          const PixelF32 alpha = inPixel.f32(inChannels - 1);
          int c = 0;
          for (; c < outChannels - 1; ++c)
            outPixel.f32(
              (premul ? inPixel.f32(c) : (inPixel.f32(c) * alpha)) +
                outPixel.f32(c) * (1.0 - alpha),
              c
            );
          outPixel.f32(alpha + outPixel.f32(c), c);
          out->pixel(outPixel, x, y);
        }
      }
      break;
  }
}

}
