//  ------------------------------------------------------------------------------------------------
//  MODULE    : Couleur
//  LANGUAGE  : C++
//  AUTHOR    : Adolfo VIDE
//  DATE    : 09/15/92
//  DESCRIPTION : Color classes
//  COMMENT   :
//  SCCSID      : @(#)color.cpp 1.1 11:49:57 18 Dec 1996
//  ----------------------------------------------------------------------------
//  Copyright (c) 1999 Digital Imaging Group, Inc.
//  For conditions of distribution and use, see copyright notice
//  in Flashpix.h
//  ----------------------------------------------------------------------------
//  ------------------------------------------------------------------------------------------------
  #include "fpx_color.h"
//  ------------------------------------------------------------------------------------------------

//  Includes
//  --------

#ifdef LP_USE_SEP_COLOR   // We don't want to link with the separator in the IVUE Tool Kit or in Shasta

  #include "ColorConvertors.h"
  #include "ColorMatching.h"

#endif

//  Constants
//  ----------

//  Variables
//  ---------

  GCR Couleur::gcrCourant = (float)0.5;

//  ------------------------------------------------------------------------------------------------
  #ifdef macintosh
    #pragma segment Couleur
  #endif
//  ------------------------------------------------------------------------------------------------

//  ------------------------------------------------------------------------------------------------
//  Internal Functions 
//  ------------------------------------------------------------------------------------------------

//  ------------------------------------------------------------------------------------------------
//  Methods
//  ------------------------------------------------------------------------------------------------

CouleurRGB::CouleurRGB()
{
  // null
}

Couleur::Couleur(ComposanteC r, ComposanteC g, ComposanteC b)
  : rouge(r),
    vert(g),
    bleu(b),
    cyan(COL_INVALID),
    magenta(COL_INVALID),
    jaune(COL_INVALID),
    noir(COL_INVALID)
  
{
}

Couleur::Couleur(ComposanteC y, ComposanteC m, ComposanteC c, ComposanteC k)
  : rouge(COL_INVALID),
    vert(COL_INVALID),
    bleu(COL_INVALID),
    cyan(c),
    magenta(m),
    jaune(y),
    noir(k)
{
}

//  ------------------------------------------------------------------------------------------------
//  External Functions 
//  ------------------------------------------------------------------------------------------------

// CAUTION : similar interpolation functions are still defined in different
// places of the code (Masque.cp and MasqueK4.cp). They could certainly be
// somewhat generalized and optimized, eventually, rewritten in assembler code.

// R[16] is the result organized in 4 lines of 4 pixels.

void Interpole16CouleurRGB (const CouleurRGB &q0, const CouleurRGB &q1, 
              const CouleurRGB &q2, const CouleurRGB &q3, 
              ptr_CouleurRGB R)
{
  R[0] = q0;
  R[10].Average(q0,q1,q2,q3);
  R[2].Average(q0,q1);
  R[8].Average(q0,q2);
  R[1].Average(q0,R[2]);
  R[4].Average(q0,R[8]);
  R[15].Average(R[10],q3);
  R[7].Average(R[10],q1);
  R[13].Average(R[10],q2);
  R[3].Average(R[2],q1);
  R[12].Average(R[8],q2);
  R[5].Average(q0,R[10]);
  R[6].Average(R[2],R[10]);
  R[9].Average(R[8],R[10]);
  R[11].Average(R[7],R[15]);
  R[14].Average(R[13],R[15]);
}

// R[64] is the result. CAUTION : the resulting array is organized in 4 sub-tiles of 4x4
// and not 8 lines of 8 pixelsÉ

void Interpole64CouleurRGB (const CouleurRGB &qNW, const CouleurRGB &qNE, 
              const CouleurRGB &qSW, const CouleurRGB &qSE, 
              ptr_CouleurRGB R)
{
  CouleurRGB  qN, qS, qE, qW, qC;

  // Compute the intermediate 4x4 internal vertices into the 8x8 square
  qN.Average(qNW,qNE);  // North
  qW.Average(qNW,qSW);  // West
  qE.Average(qNE,qSE);  // East
  qS.Average(qSW,qSE);  // South
  qC.Average(qN,qS);    // Center

  Interpole16CouleurRGB (qNW, qN,  qW,  qC,  R);      // NW sub-tile
  Interpole16CouleurRGB (qN,  qNE, qC,  qE,  R + 16);   // NE sub-tile
  Interpole16CouleurRGB (qW,  qC,  qSW, qS,  R + 32);   // SW sub-tile
  Interpole16CouleurRGB (qC,  qE,  qS,  qSE, R + 48);   // SE sub-tile
}

// Check the color dispersion into a buffer.
// Explanation of the algorithm :
// In binary computation, the distance between two values x1 and x2 is proportionnal to (x1 ^ x2).
// We would like to know the maximum distance in a set of points (ÉxiÉ). The idea is to make
// the logical sum (|) of all the differences (xj ^ xi). It is easy to demonstrate the following equation:

//                    |(xj^xi) = (|xj) ^ (&xi)

// So we can cumulate "|"'s in a variable and "&"'s in another and make the "^" at the end.
// Because we are looking for a criteria, we can check the intermediate result at each point and break
// the loop as soon as the distance exceed a given threshold value.
// For colors, we make the same computation on each channel and add ("|"'s) the results.

Boolean IsColorDispersion (ptr_CouleurRGB tile, long size)
{
#define IncLargeBuf   3
#define IncSmallBuf   1
#define ThresholdBuf  (5*IncLargeBuf)
#define DispLimit   ~0x00FF

  long IncPix = (size < ThresholdBuf ? IncSmallBuf : IncLargeBuf);
  
  // Declare and initialize accumulators
  unsigned short maxRed = 0x0000;
  unsigned short minRed = 0xFFFF;
  unsigned short maxGrn = 0x0000;
  unsigned short minGrn = 0xFFFF;
  unsigned short maxBlu = 0x0000;
  unsigned short minBlu = 0xFFFF;
  
  while (size > 0) {
  
    // Accumulate values
    maxRed |= tile->rouge;
    minRed &= tile->rouge;
    maxGrn |= tile->vert;
    minGrn &= tile->vert;
    maxBlu |= tile->bleu;
    minBlu &= tile->bleu;
    
    // Check intermediate dispersion and exit with true if dispersion exceeds limit
    if (((maxRed ^ minRed) | (maxGrn ^ minGrn) | (maxBlu ^ minBlu)) & DispLimit)
      return TRUE;
      
    // Next pixel
    size -= IncPix;
    tile += IncPix;
  }
  
  // Exit with false if the dispersion criteria has not been challenged
  return FALSE;
}


