This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Color Manipulation Submitted by

Here comes my COTD, It consists on a collection of color manipulation primitives that work directly on 565 color space, their main contributions are that they donīt lose colour resolution and the colour saturation is performed without any conditional statement.
The example code comes in C++, but its easy to port it to Java or asm. Its also interesting that you can use the same kind of trick to code 555 and 888 bpp versions of te routines. The Operations Covered are:

> - One pair of colours saturated add/sub
> - Two pair of colours saturated add/sub
> - One pair of colours alfablend (32levels)
> - Two pair of colours alfablend (32levels)

Have a Nice Day :-)
Unai Landa

Download Associated File: colors.hpp (14,413 bytes)

    /*
      License:
        This is free software; you can redistribute it and/or
        modify it under the terms of the GNU Library General Public
        License as published by the Free Software Foundation; either
        version 2 of the License, or (at your option) any later version.

      Use:
        Some usefull color code.

      Author:
        Unai Landa	(unai_landa#eresmas·com)

      Notes:
        My english is really bad, I allready now that so dont tell me.
        The original code was nice comented in spanish, but I translated this  "on the fly" so I hope you can understand :-)

    */

    // --------------------------------------------------------------------------------------------------------------------
    // Some 565 Color space defines.
    // --------------------------------------------------------------------------------------------------------------------
    enum
    {
        COLORSPACE_565_RED_MASK             = (0xF800),
        COLORSPACE_565_GREEN_MASK           = (0x07E0),
        COLORSPACE_565_BLUE_MASK            = (0x001F),

        COLORSPACE_565_SATURATE_RED_BIT     = (0x10000),
        COLORSPACE_565_SATURATE_GREEN_BIT   = (0x0800),
        COLORSPACE_565_SATURATE_BLUE_BIT    = (0x0020),
    };

    //----------------------------------------------------------------------------
    // Some more defines
    //----------------------------------------------------------------------------
    enum
    {
      MAXIMO_NUM_BITS_COLOR   = 6   ,
      BITS_BAJOS              = 5   ,

      MASCARA_A               =(COLORSPACE_565_GREEN_MASK)                                        ,
      MASCARA_B               =(COLORSPACE_565_RED_MASK|COLORSPACE_565_BLUE_MASK)                 ,

      MASCARA_SAT_A           =(COLORSPACE_565_SATURATE_GREEN_BIT )                               ,
      MASCARA_SAT_B           =(COLORSPACE_565_SATURATE_RED_BIT|COLORSPACE_565_SATURATE_BLUE_BIT) ,

      MASCARA_A_TWICE         =( ((COLORSPACE_565_RED_MASK|COLORSPACE_565_BLUE_MASK)<<16)|(COLORSPACE_565_GREEN_MASK<<0 ))  ,
      MASCARA_B_TWICE         =( ((COLORSPACE_565_RED_MASK|COLORSPACE_565_BLUE_MASK)<<0 )|(COLORSPACE_565_GREEN_MASK<<16))  ,

      MASCARA_SAT_A_TWICE     =( ((COLORSPACE_565_SATURATE_RED_BIT|COLORSPACE_565_SATURATE_BLUE_BIT)<<(16-BITS_BAJOS))|(COLORSPACE_565_SATURATE_GREEN_BIT>>BITS_BAJOS) )                              ,
      MASCARA_SAT_B_TWICE     =((((COLORSPACE_565_SATURATE_RED_BIT|COLORSPACE_565_SATURATE_BLUE_BIT)                 )|(COLORSPACE_565_SATURATE_GREEN_BIT<<16))<<(MAXIMO_NUM_BITS_COLOR-BITS_BAJOS) )
    };

    //----------------------------------------------------------------------
    //  Use:            Adds two 565 colours with saturation and no lose.
    //  Returns:        The added colour.
    //  Parameters:     Two colours.
    //----------------------------------------------------------------------
    __inline unsigned GE_AddColors565( const unsigned c1, const unsigned c2)
    {
        //  Separacion:
        //  SetUp:
        unsigned  t1_a = (c1 & MASCARA_A);                              //  0000__g1__
        unsigned  t2_a = (c2 & MASCARA_A);                              //  0000__g2__

        unsigned  t1_b = (c1 & MASCARA_B);                              //  0000r1__b1
        unsigned  t2_b = (c2 & MASCARA_B);                              //  0000r2__b2

        //  Suma_A:
        //  Suma_B:
        t1_a  = t2_a = t1_a + t2_a;                                     //  00__gT__    * T means Total
        t1_b  = t2_b = t1_b + t2_b;                                     //  00rT__bT

        t2_a &= MASCARA_SAT_A;                                          //  00_1____    *** 1 appears ONLY where saturation happened.
        t2_b &= MASCARA_SAT_B;                                          //  01___1__    *** 1 appears ONLY where saturation happened.

        t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR);                          //  00__11__    *** 1 appears ONLY where saturation happened.
        t2_b -= (t2_b>>BITS_BAJOS);                                     //  0011__11    *** 1 appears ONLY where saturation happened.

        t1_a |= t2_a;                                                   //  00__gS__    * S means Saturated
        t1_b |= t2_b;                                                   //  00rS__bS

        //  Comoposicion:
        return(t1_a | t1_b);
    }

    //----------------------------------------------------------------------
    //  Use:            Adds two 565 colours TWICE with saturation and no lose.
    //  Returns:        The two added colours.
    //  Parameters:     Four 565 colours, The first parameter colurs are added to the second parameter colours..
    //----------------------------------------------------------------------
    __inline unsigned  GE_AddColors565Twice( const unsigned c1, const unsigned c2)
    {
        //  Separacion:
        //  SetUp:
        unsigned  t1_a = (c1 & MASCARA_A_TWICE) >> BITS_BAJOS;                          //  __R1__B1__g1
        unsigned  t2_a = (c2 & MASCARA_A_TWICE) >> BITS_BAJOS;                          //  __R2__B2__g2

        unsigned  t1_b = (c1 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS);  //  __G1__r1__b1
        unsigned  t2_b = (c2 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS);  //  __G2__r2__b2

        //  Suma_A:
        //  Suma_B:
        t1_a  = t2_a = t1_a + t2_a;                                                     //  __RT__BT__gT  * T means Total
        t1_b  = t2_b = t1_b + t2_b;                                                     //  __GT__rT__bT

        t2_a &= MASCARA_SAT_A_TWICE;                                                    //  _1___1___1__  *** 1 appears ONLY where saturation happened.
        t2_b &= MASCARA_SAT_B_TWICE;                                                    //  _1___1___1__  *** 1 appears ONLY where saturation happened.

        t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR);                                          //  __11__11__11  *** 1 appears ONLY where saturation happened.
        t2_b -= (t2_b>>MAXIMO_NUM_BITS_COLOR);                                          //  __11__11__11  *** 1 appears ONLY where saturation happened.

        t1_a |= t2_a;                                                                   //  __RSxxBSxxgS  * S means Saturated
        t1_b |= t2_b;                                                                   //  __GSxxrSxxbS  * xx Garbage that appeared betwen the color components.

        t1_a  = (t1_a<<BITS_BAJOS) & (MASCARA_A_TWICE);                                 //  11xx11xx11xx  * Moves all to its correct place.
                                                                                        //  11__11__11__  * Cleans the space betwen components.
        t1_b  = (t1_b>>MAXIMO_NUM_BITS_COLOR-BITS_BAJOS) & (MASCARA_B_TWICE);           //  11xx11xx11xx  * Moves all to its correct place.
                                                                                        //  __11__11__11  * Cleans the space betwen components.
        //  Comoposicion:
        return(t1_a | t1_b);
    }

    //----------------------------------------------------------------------
    //  Use:            Subs two 565 colours with saturation and no lose.
    //  Returns:        The Sub colour.
    //  Parameters:     Two colours.
    //----------------------------------------------------------------------
    __inline  unsigned GE_SubColors565( unsigned c1, const unsigned c2)
    {
        //  Separacion:
        unsigned  t1_a = (c1 &  MASCARA_A) | MASCARA_SAT_A;             //  0000_1g1__    //  I set the bit so later I can check underflow.
        unsigned  t2_a = (c2 &  MASCARA_A);                             //  0000__g2__

        unsigned  t1_b = (c1 &  MASCARA_B) | MASCARA_SAT_B;             //  0001r1_1b1    //  I set the bit so later I can check underflow.
        unsigned  t2_b = (c2 &  MASCARA_B);                             //  0000r2__b2

        //  Resta_A:
        //  Resta_B:
        t1_a  = t2_a = (t1_a - t2_a);                                   //  00__gT__    * T means Total
        t1_b  = t2_b = (t1_b - t2_b);                                   //  00rT__bT

        t2_a &= (MASCARA_SAT_A);                                        //  00_1____    I test sign change.
        t2_b &= (MASCARA_SAT_B);                                        //  01___1__    1 appears ONLY where no underflow happened.

        t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR);                          //  00__11__    I create the 1filled mask on the colours the didn't underflow.
        t2_b -= (t2_b>>BITS_BAJOS);                                     //  0011__11

        t1_a &= t2_a;                                                   //  00__gU__    * U means UnderFlow
        t1_b &= t2_b;                                                   //  00rU__bU

        //  Comoposicion:
        return(t1_a | t1_b);
    }

    //----------------------------------------------------------------------
    //  Use:            Subs two 565 colours TWICE with saturation and no lose.
    //  Returns:        The two added colours.
    //  Parameters:     Four 565 colours, The second parameter colurs are sub from the first parameter colours..
    //----------------------------------------------------------------------
    __inline  unsigned GE_SubColors565Twice( unsigned c1, const unsigned c2)
    {
        //  Separacion:
        //  SetUp:
        unsigned  t1_a = ((c1 & MASCARA_A_TWICE) >> BITS_BAJOS) | MASCARA_SAT_A_TWICE;                          //  _1R1_1B1_1g1
        unsigned  t2_a = ((c2 & MASCARA_A_TWICE) >> BITS_BAJOS);                                                //  __R2__B2__g2

        unsigned  t1_b = ((c1 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS)) | MASCARA_SAT_B_TWICE;  //  _1G1_1r1_1b1
        unsigned  t2_b = ((c2 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS));                        //  __G2__r2__b2

        //  Suma_A:
        //  Suma_B:
        t1_a  = t2_a = t1_a - t2_a;                                               //  __RT__BT__gT  * T means Total
        t1_b  = t2_b = t1_b - t2_b;                                               //  __GT__rT__bT

        t2_a &= MASCARA_SAT_A_TWICE;                                              //  _1___1___1__  *** 1 appears ONLY where no underflow happened.
        t2_b &= MASCARA_SAT_B_TWICE;                                              //  _1___1___1__  *** 1 appears ONLY where no underflow happened.

        t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR);                                    //  __11__11__11  *** 1 appears ONLY where no underflow happened.
        t2_b -= (t2_b>>MAXIMO_NUM_BITS_COLOR);                                    //  __11__11__11  *** 1 appears ONLY where no underflow happened.

        t1_a &= t2_a;                                                             //  __RUxxBUxxgU  * U means Underflow
        t1_b &= t2_b;                                                             //  __GUxxrSxxbU  * xx Garbage that appeared betwen the color components.

        t1_a  = (t1_a<<BITS_BAJOS) & (MASCARA_A_TWICE);                           //  11xx11xx11xx  * Moves all to its correct place.
                                                                                  //  11__11__11__  * Cleans the space betwen components.
        t1_b  = (t1_b>>MAXIMO_NUM_BITS_COLOR-BITS_BAJOS) & (MASCARA_B_TWICE);     //  11xx11xx11xx  * Moves all to its correct place.
                                                                                  //  __11__11__11  * Cleans the space betwen components.
        //  Comoposicion:
        return(t1_a | t1_b);
    }

    //----------------------------------------------------------------------
    //  Use:            Make a 32 levels alfa blend betwen two 565 colours.
    //  Returns:        The blended colour.
    //  Parameters:     iAlfa=0 Only c1 is set, iAlfa=32 only c2 is set
    //----------------------------------------------------------------------
    __inline unsigned GE_BlendColors565( const unsigned c1, const unsigned c2, int iAlfa)
    {
      unsigned  ta = c1 & MASCARA_A;                                            //  0000__g1__
      unsigned  tb = c2 & MASCARA_B;                                            //  0000r2__b2

      ta *= (32-iAlfa);
      tb *= (   iAlfa);

      ta += (   iAlfa) *(c2 & MASCARA_A);                                            //  0000__g2__
      tb += (32-iAlfa) *(c1 & MASCARA_B);                                            //  0000r1__b1

      ta =  (ta>>BITS_BAJOS) & MASCARA_A;
      ta += (tb>>BITS_BAJOS) & MASCARA_B;

      return(ta);
    }

    //----------------------------------------------------------------------
    //  Use:            Make a 32 levels alfa blend betwen two 565 colours TWICE
    //  Returns:        The two blended colours.
    //  Parameters:     iAlfa=0 Only c1 is set, iAlfa=32 only c2 is set
    //		    c1; two 565 Colours thar will blend with c2 that contains anothe two 565 colours.
    //----------------------------------------------------------------------
    __inline unsigned  GE_BlendColors565Twice( const unsigned c1, const unsigned c2, int iAlfa)
    {
      unsigned  ta = (c1 & MASCARA_A_TWICE)>>BITS_BAJOS;                          //  __R1__B1__g1
      unsigned  tb = (c1 & MASCARA_B_TWICE);                                      //  __G1__r1__b1

      ta *= (32-iAlfa);
      tb *= (32-iAlfa);

      ta += iAlfa *((c2 & MASCARA_A_TWICE)>>(BITS_BAJOS));                        //  __R2__B2__g2
      tb += iAlfa * (c2 & MASCARA_B_TWICE);                                       //  __G2__r2__b2

      ta &=                    MASCARA_A_TWICE;                                   //  R2__B2__g2__
      ta += (tb>>BITS_BAJOS) & MASCARA_B_TWICE;                                   //  __G2__r2__b2
      return(ta);
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.