////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// Implementation file
//
// SPDX-FileCopyrightText: © 2004, Tim Blechmann and the GEM contributors
// SPDX-License-Identifier: GPL-2.0-or-later
//
////////////////////////////////////////////////////////
#include "pix_mean_color.h"
#include "Utils/Functions.h"

CPPEXTERN_NEW_WITH_GIMME(pix_mean_color);

/* const, destructor */
pix_mean_color::pix_mean_color(int argc, t_atom *argv)
{
  m_list = outlet_new(this->x_obj, 0);
}

pix_mean_color::~pix_mean_color()
{
  outlet_free(m_list);
}

void pix_mean_color::processYUVImage(imageStruct &image)
{
  t_atom out[4];
  unsigned int datasize = (image.xsize * image.ysize) >> 1;
  unsigned char *base = image.data;

  unsigned long sum[4] = {0,0,0,0};

  for (unsigned int i = 0; i != datasize; ++i) {
    for(int j = 0; j!= 4; ++j) {
      sum[j]  += base[j];
    }
    base += 4;
  }
  // use formulae from http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC29
  /*
   * [R]   [ 0.00456621  0.00000000  0.00625893 ]   [Y-16 ]
   * [G] = [ 0.00456621 -0.00153632 -0.00318811 ] * [U-128]
   * [B]   [ 0.00456621  0.00791071  0.00000000 ]   [V-128]
   */

  t_float y = (t_float)(sum[chY0]+sum[chY1]) / (t_float)(2*datasize) - 16;
  t_float u = (t_float) sum[chU] / (t_float)(datasize) - 128;
  t_float v = (t_float) sum[chV] / (t_float)(datasize) - 128;

  t_float r = FLOAT_CLAMP((t_float)(0.00456621*y             +0.00625893*v));
  t_float g = FLOAT_CLAMP((t_float)(0.00456621*y-0.00153632*u-0.00318811*v));
  t_float b = FLOAT_CLAMP((t_float)(0.00456621*y+0.00791071*u             ));

  SETFLOAT(out,   r);
  SETFLOAT(out+1, g);
  SETFLOAT(out+2, b);
  SETFLOAT(out+3, 1.0);

  outlet_list(m_list, 0, 4, out);

}

void pix_mean_color::processGrayImage(imageStruct &image)
{
  t_atom out[4];
  unsigned int datasize = image.xsize * image.ysize;
  unsigned char *base = image.data;

  unsigned long sum = 0;

  for (unsigned int i = 0; i != datasize; ++i) {
    sum  += *base;
    base++;
  }

  t_float grey = (t_float)sum / (t_float)(datasize*255);

  SETFLOAT(out,   grey );
  SETFLOAT(out+1, grey);
  SETFLOAT(out+2, grey);
  SETFLOAT(out+3, 1.0);

  outlet_list(m_list, 0, 4, out);
}

void pix_mean_color::processRGBImage(imageStruct &image)
{
  t_atom out[4];
  unsigned int datasize = image.xsize * image.ysize;
  unsigned char *base = image.data;

  unsigned long sum[3] = {0,0,0};

  for (unsigned int i = 0; i != datasize; ++i) {
    for(int j = 0; j!= 3; ++j) {
      sum[j]  += base[j];
    }
    base += 3;
  }


  SETFLOAT(out,   (t_float)sum[0] / (t_float)(datasize*255));
  SETFLOAT(out+1, (t_float)sum[1] / (t_float)(datasize*255));
  SETFLOAT(out+2, (t_float)sum[2] / (t_float)(datasize*255));
  SETFLOAT(out+3, 1.0);

  outlet_list(m_list, 0, 4, out);
}

void pix_mean_color::processRGBAImage(imageStruct &image)
{
  unsigned int datasize = image.xsize * image.ysize;
  unsigned char *base = image.data;

  unsigned long sum[4] = {0,0,0,0};

  for (unsigned int i = 0; i != datasize; ++i) {
    for(int j = 0; j!= 4; ++j) {
      sum[j]  += base[j];
    }
    base += 4;
  }

  t_atom out[4];

  SETFLOAT(out,   (t_float)sum[chRed  ] / (t_float)(datasize*255) );
  SETFLOAT(out+1, (t_float)sum[chGreen] / (t_float)(datasize*255) );
  SETFLOAT(out+2, (t_float)sum[chBlue ] / (t_float)(datasize*255) );
  SETFLOAT(out+3, (t_float)sum[chAlpha] / (t_float)(datasize*255) );

  outlet_list(m_list, 0, 4, out);
}

void pix_mean_color :: obj_setupCallback(t_class *classPtr)
{

}
