Color saturation

Source code

//========================================================
//
// Color saturation
//
// QUAGLIOZZI Eric © 2004
//
//========================================================

/*
   Usable for low res (72 dpi) and double res (144 dpi) 
   bitmap using 8 and 16 bits Colors.
  ---------------------------------------------------------
  | Do not use with other resolutions, may system crash ! |
  ---------------------------------------------------------
*/

/*

  L'effet de saturation est simple, toutes les composantes
  R, G et B sélectionnées sont multipliées par un coefficient
  0 <= a <= 2.

  Pour  a<1, les couleurs primaires sélectionnées sont 
  diminuées.

  Pour  a=1, les couleurs primaires sélectionnées sont
  conservées. 

  Pour  a>1, les couleurs primaires sélectionnées sont
  augmentéesclaires

  Les calculs sont implicitement réalisés en virgule fixe
  sur 16 bits au format 9:7

*/
//-------------- Macros and constants ---------------------

#if defined(_MSC_VER)     // If compiling with VC++...

    #define private        static __inline
    #define longint        __int64
    
#elif defined(__GNUC__)  // If compiling with GCC...

    #define private        static inline
    #define longint        long long int
    
#else

    #error "Unknown Compiler!"
    
#endif

#define Read68KUnaligned32(addr)            \
  (((((unsigned char *)(addr))[0]) << 24) | \
  ((((unsigned char *)(addr))[1]) << 16) |  \
  ((((unsigned char *)(addr))[2]) << 8) |   \
  ((((unsigned char *)(addr))[3])))  // For endianness conversions



#define Write68KUnaligned32(addr, value) \
    (((unsigned char *)(addr))[0] = (unsigned char)((unsigned long)(value) >> 24), \
     ((unsigned char *)(addr))[1] = (unsigned char)((unsigned long)(value) >> 16), \
     ((unsigned char *)(addr))[2] = (unsigned char)((unsigned long)(value) >> 8), \
     ((unsigned char *)(addr))[3] = (unsigned char)((unsigned long)(value)))


#define EndianSwap16(n) (((((unsigned int) n) << 8) & 0xFF00) | \
                         ((((unsigned int) n) >> 8) & 0x00FF))

#define EndianSwap32(n) (((((unsigned long) n) << 24) & 0xFF000000) | \
                         ((((unsigned long) n) <<  8) & 0x00FF0000) | \
                         ((((unsigned long) n) >>  8) & 0x0000FF00) | \
                         ((((unsigned long) n) >> 24) & 0x000000FF))





//---------------- Types ---------------------------------


typedef unsigned long Call68KFuncType(const void * emulStateP,
                                 unsigned long trapOrFunction,
                                 const void * argsOnStackP,
                                 unsigned long argsSizeAndwantA0);

typedef unsigned long NativeFuncType(const void * emulStateP,
                                     void * userData68KP,
                                     Call68KFuncType * call68KFuncP);

/*

  BMPparam (32 bit) :
    BMPparam[3]=0
    BMPparam[2]=0
    BMPparam[1]=Bitdepth (1=8bits, 2=16bits)
    BMPparam[0]=density (1=low, 2=high)
  BMPWH (32 bits) :
    BMPWH [3][2](16bits) : Height
    BMPWH [1][0](16bits) : Width
  Param1 (32 bits) :
    Param1 [0]=Facteur luminosité (0-255, 128=1)
    Param1 [1]=R (booléen indiquant quelles couleurs doivent etre saturées)
    Param1 [2]=G
    Param1 [3]=B
*/


typedef struct _ParamsType
  {
    long            BMPWH;          // Width-height
    long            BMPparam;       // infos on bitmap
    long            Param1;         // infos on bitmap
    unsigned char   * pSrc;         // bitmap source pointer
    unsigned char   * pDest;        // bitmap destination pointer
    unsigned char   pPal[1024];     // array of indexed colors
    unsigned char   pIndex[216];    // Fast RGB colors
  }
    ParamsType;


//------------- Saturation  Function ----------------------


unsigned long FastLightFunc(const void * emulStateP, 
                            void * userData68KP, 
                            Call68KFuncType * call68KFuncP)
{
  ParamsType    * p;                         //pointer to params structure
  long            BMPparam, BMPWH, Param1;   //Locale copy of params
  unsigned char * src;
  unsigned char * dest;
  unsigned char * Pal;
  unsigned char * Index;
  unsigned char * P1;                        //Vars for computations
  unsigned char * P2;
  unsigned int    w, h, wlimit;
  unsigned int    i, j, LightFactor;
  unsigned int    id;
  unsigned int    density, bitdepth;
  unsigned int    R,G,B;
  unsigned int    Rb,Gb,Bb;
  unsigned int    RGB;


  // Do local copy of params
  p=(ParamsType *) userData68KP;
  BMPWH=Read68KUnaligned32(&(p->BMPWH)); 
  BMPparam=Read68KUnaligned32(&(p->BMPparam)); 
  Param1=Read68KUnaligned32(&(p->Param1)); 
  src=(unsigned char *) Read68KUnaligned32(&(p->pSrc)); 
  dest=(unsigned char *) Read68KUnaligned32(&(p->pDest)); 
  Pal=p->pPal;
  Index=p->pIndex;

  // get bitmap infos

  density=BMPparam & 0x000000FF;
  bitdepth=(BMPparam >> 8) & 0x000000FF ;
  w=(BMPWH & 0x0000FFFF)*density*bitdepth;
  wlimit=w;
  if (wlimit & 0x0001) wlimit += 1;
  h=(BMPWH >> 16)*density;
  
  // initialization
  LightFactor=Param1 & 0x000000FF;
  Rb=(Param1 >>8)  & 0x000000FF;
  Gb=(Param1 >>16) & 0x000000FF;
  Bb=(Param1 >>24) & 0x000000FF;

  //saturation 
  P1=src;
  P2=dest;

  if (bitdepth==1)
   {
      for (j=0;j<h;j++)  
      {
        for (i=0; i<w; i++)
         {

           //color of current pixel
           id = P1[i]<<2;
           R=Pal[id+1];
           G=Pal[id+2];
           B=Pal[id+3];
        
           //compute light
           if (Rb != 0) R=(R*LightFactor)>>7;
           if (R>255) R=255;
           if(Gb != 0) G=(G*LightFactor)>>7;
           if (G>255) G=255;
           if (Bb != 0)B=(B*LightFactor)>>7;
           if (B>255) B=255;

           //retrieve nearest indexed color
           R=((R+26)*5)>>8;          // (x*5)>>8 is about x/51
           G=((G+26)*5)>>8;
           B=((B+26)*5)>>8;
           P2[i]= Index[R*36+G*6+B]; // copy new color
         }
         P1+=wlimit;
         P2+=wlimit;
      }
   } // End of 8 bits case
  else
   {
      for (j=0;j<h;j++)  
       {
         for (i=0; i<w; i+=2)
         {
           //color of current pixel
           RGB = (P1[i]<<8)|P1[i+1];
           R=(RGB >> 11) & 0x001F;
           G=(RGB >> 5) & 0x003F;
           B= RGB & 0x001F;

           //compute light
           if (Rb != 0) R=(R*LightFactor)>>7;
           if (R>255) R=255;
           if(Gb != 0) G=(G*LightFactor)>>7;
           if (G>255) G=255;
           if (Bb != 0)B=(B*LightFactor)>>7;
           if (B>255) B=255;

           //final color
           if (R > 0x001F) R=0x001F;
           if (G > 0x003F) G=0x003F;
           if (B > 0x001F) B=0x001F;
         
           //new color
           P2[i]  = (R<<3)|(G>>3);
           P2[i+1]= (G<<5)|(B);
         }
         P1+=wlimit;
         P2+=wlimit;
      }
   } // End of 16 bits case
  return 0;
}

//========================================================