LCOV - code coverage report
Current view: top level - addons/color - color.c (source / functions) Hit Total Coverage
Test: allegro_auto.info Lines: 98 300 32.7 %
Date: 2018-08-11 00:50:28 Functions: 8 34 23.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Addon which allows converting between different color
       2             :  * representations. Included are:
       3             :  * - HSV (like A4)
       4             :  * - names (mostly X11 color names, except where CSS redefines them)
       5             :  * - HSL (the "better" HSV)
       6             :  * - CMYK (a bit like the opposite of RGB)
       7             :  * - YUV (the Y channel is quite useful for creating grayscale pictures)
       8             :  */
       9             : #include "allegro5/allegro.h"
      10             : #include "allegro5/allegro_color.h"
      11             : #include "allegro5/internal/aintern.h"
      12             : #include <math.h>
      13             : #include <stdio.h>
      14             : 
      15             : typedef struct {
      16             :    char const *name;
      17             :    int r, g, b;
      18             : } ColorName;
      19             : 
      20             : /* Taken from http://www.w3.org/TR/2010/PR-css3-color-20101028/#svg-color
      21             :  * This must be sorted correctly for binary search.
      22             :  */
      23             : static ColorName _al_color_names[] = {
      24             :    {"aliceblue", 0xf0, 0xf8, 0xff},
      25             :    {"antiquewhite", 0xfa, 0xeb, 0xd7},
      26             :    {"aqua", 0x00, 0xff, 0xff},
      27             :    {"aquamarine", 0x7f, 0xff, 0xd4},
      28             :    {"azure", 0xf0, 0xff, 0xff},
      29             :    {"beige", 0xf5, 0xf5, 0xdc},
      30             :    {"bisque", 0xff, 0xe4, 0xc4},
      31             :    {"black", 0x00, 0x00, 0x00},
      32             :    {"blanchedalmond", 0xff, 0xeb, 0xcd},
      33             :    {"blue", 0x00, 0x00, 0xff},
      34             :    {"blueviolet", 0x8a, 0x2b, 0xe2},
      35             :    {"brown", 0xa5, 0x2a, 0x2a},
      36             :    {"burlywood", 0xde, 0xb8, 0x87},
      37             :    {"cadetblue", 0x5f, 0x9e, 0xa0},
      38             :    {"chartreuse", 0x7f, 0xff, 0x00},
      39             :    {"chocolate", 0xd2, 0x69, 0x1e},
      40             :    {"coral", 0xff, 0x7f, 0x50},
      41             :    {"cornflowerblue", 0x64, 0x95, 0xed},
      42             :    {"cornsilk", 0xff, 0xf8, 0xdc},
      43             :    {"crimson", 0xdc, 0x14, 0x3c},
      44             :    {"cyan", 0x00, 0xff, 0xff},
      45             :    {"darkblue", 0x00, 0x00, 0x8b},
      46             :    {"darkcyan", 0x00, 0x8b, 0x8b},
      47             :    {"darkgoldenrod", 0xb8, 0x86, 0x0b},
      48             :    {"darkgray", 0xa9, 0xa9, 0xa9},
      49             :    {"darkgreen", 0x00, 0x64, 0x00},
      50             :    {"darkgrey", 0xa9, 0xa9, 0xa9},
      51             :    {"darkkhaki", 0xbd, 0xb7, 0x6b},
      52             :    {"darkmagenta", 0x8b, 0x00, 0x8b},
      53             :    {"darkolivegreen", 0x55, 0x6b, 0x2f},
      54             :    {"darkorange", 0xff, 0x8c, 0x00},
      55             :    {"darkorchid", 0x99, 0x32, 0xcc},
      56             :    {"darkred", 0x8b, 0x00, 0x00},
      57             :    {"darksalmon", 0xe9, 0x96, 0x7a},
      58             :    {"darkseagreen", 0x8f, 0xbc, 0x8f},
      59             :    {"darkslateblue", 0x48, 0x3d, 0x8b},
      60             :    {"darkslategray", 0x2f, 0x4f, 0x4f},
      61             :    {"darkslategrey", 0x2f, 0x4f, 0x4f},
      62             :    {"darkturquoise", 0x00, 0xce, 0xd1},
      63             :    {"darkviolet", 0x94, 0x00, 0xd3},
      64             :    {"deeppink", 0xff, 0x14, 0x93},
      65             :    {"deepskyblue", 0x00, 0xbf, 0xff},
      66             :    {"dimgray", 0x69, 0x69, 0x69},
      67             :    {"dimgrey", 0x69, 0x69, 0x69},
      68             :    {"dodgerblue", 0x1e, 0x90, 0xff},
      69             :    {"firebrick", 0xb2, 0x22, 0x22},
      70             :    {"floralwhite", 0xff, 0xfa, 0xf0},
      71             :    {"forestgreen", 0x22, 0x8b, 0x22},
      72             :    {"fuchsia", 0xff, 0x00, 0xff},
      73             :    {"gainsboro", 0xdc, 0xdc, 0xdc},
      74             :    {"ghostwhite", 0xf8, 0xf8, 0xff},
      75             :    {"gold", 0xff, 0xd7, 0x00},
      76             :    {"goldenrod", 0xda, 0xa5, 0x20},
      77             :    {"gray", 0x80, 0x80, 0x80},
      78             :    {"green", 0x00, 0x80, 0x00},
      79             :    {"greenyellow", 0xad, 0xff, 0x2f},
      80             :    {"grey", 0x80, 0x80, 0x80},
      81             :    {"honeydew", 0xf0, 0xff, 0xf0},
      82             :    {"hotpink", 0xff, 0x69, 0xb4},
      83             :    {"indianred", 0xcd, 0x5c, 0x5c},
      84             :    {"indigo", 0x4b, 0x00, 0x82},
      85             :    {"ivory", 0xff, 0xff, 0xf0},
      86             :    {"khaki", 0xf0, 0xe6, 0x8c},
      87             :    {"lavender", 0xe6, 0xe6, 0xfa},
      88             :    {"lavenderblush", 0xff, 0xf0, 0xf5},
      89             :    {"lawngreen", 0x7c, 0xfc, 0x00},
      90             :    {"lemonchiffon", 0xff, 0xfa, 0xcd},
      91             :    {"lightblue", 0xad, 0xd8, 0xe6},
      92             :    {"lightcoral", 0xf0, 0x80, 0x80},
      93             :    {"lightcyan", 0xe0, 0xff, 0xff},
      94             :    {"lightgoldenrodyellow", 0xfa, 0xfa, 0xd2},
      95             :    {"lightgray", 0xd3, 0xd3, 0xd3},
      96             :    {"lightgreen", 0x90, 0xee, 0x90},
      97             :    {"lightgrey", 0xd3, 0xd3, 0xd3},
      98             :    {"lightpink", 0xff, 0xb6, 0xc1},
      99             :    {"lightsalmon", 0xff, 0xa0, 0x7a},
     100             :    {"lightseagreen", 0x20, 0xb2, 0xaa},
     101             :    {"lightskyblue", 0x87, 0xce, 0xfa},
     102             :    {"lightslategray", 0x77, 0x88, 0x99},
     103             :    {"lightslategrey", 0x77, 0x88, 0x99},
     104             :    {"lightsteelblue", 0xb0, 0xc4, 0xde},
     105             :    {"lightyellow", 0xff, 0xff, 0xe0},
     106             :    {"lime", 0x00, 0xff, 0x00},
     107             :    {"limegreen", 0x32, 0xcd, 0x32},
     108             :    {"linen", 0xfa, 0xf0, 0xe6},
     109             :    {"magenta", 0xff, 0x00, 0xff},
     110             :    {"maroon", 0x80, 0x00, 0x00},
     111             :    {"mediumaquamarine", 0x66, 0xcd, 0xaa},
     112             :    {"mediumblue", 0x00, 0x00, 0xcd},
     113             :    {"mediumorchid", 0xba, 0x55, 0xd3},
     114             :    {"mediumpurple", 0x93, 0x70, 0xdb},
     115             :    {"mediumseagreen", 0x3c, 0xb3, 0x71},
     116             :    {"mediumslateblue", 0x7b, 0x68, 0xee},
     117             :    {"mediumspringgreen", 0x00, 0xfa, 0x9a},
     118             :    {"mediumturquoise", 0x48, 0xd1, 0xcc},
     119             :    {"mediumvioletred", 0xc7, 0x15, 0x85},
     120             :    {"midnightblue", 0x19, 0x19, 0x70},
     121             :    {"mintcream", 0xf5, 0xff, 0xfa},
     122             :    {"mistyrose", 0xff, 0xe4, 0xe1},
     123             :    {"moccasin", 0xff, 0xe4, 0xb5},
     124             :    {"navajowhite", 0xff, 0xde, 0xad},
     125             :    {"navy", 0x00, 0x00, 0x80},
     126             :    {"oldlace", 0xfd, 0xf5, 0xe6},
     127             :    {"olive", 0x80, 0x80, 0x00},
     128             :    {"olivedrab", 0x6b, 0x8e, 0x23},
     129             :    {"orange", 0xff, 0xa5, 0x00},
     130             :    {"orangered", 0xff, 0x45, 0x00},
     131             :    {"orchid", 0xda, 0x70, 0xd6},
     132             :    {"palegoldenrod", 0xee, 0xe8, 0xaa},
     133             :    {"palegreen", 0x98, 0xfb, 0x98},
     134             :    {"paleturquoise", 0xaf, 0xee, 0xee},
     135             :    {"palevioletred", 0xdb, 0x70, 0x93},
     136             :    {"papayawhip", 0xff, 0xef, 0xd5},
     137             :    {"peachpuff", 0xff, 0xda, 0xb9},
     138             :    {"peru", 0xcd, 0x85, 0x3f},
     139             :    {"pink", 0xff, 0xc0, 0xcb},
     140             :    {"plum", 0xdd, 0xa0, 0xdd},
     141             :    {"powderblue", 0xb0, 0xe0, 0xe6},
     142             :    {"purple", 0x80, 0x00, 0x80},
     143             :    {"rebeccapurple", 0x66, 0x33, 0x99},
     144             :    {"red", 0xff, 0x00, 0x00},
     145             :    {"rosybrown", 0xbc, 0x8f, 0x8f},
     146             :    {"royalblue", 0x41, 0x69, 0xe1},
     147             :    {"saddlebrown", 0x8b, 0x45, 0x13},
     148             :    {"salmon", 0xfa, 0x80, 0x72},
     149             :    {"sandybrown", 0xf4, 0xa4, 0x60},
     150             :    {"seagreen", 0x2e, 0x8b, 0x57},
     151             :    {"seashell", 0xff, 0xf5, 0xee},
     152             :    {"sienna", 0xa0, 0x52, 0x2d},
     153             :    {"silver", 0xc0, 0xc0, 0xc0},
     154             :    {"skyblue", 0x87, 0xce, 0xeb},
     155             :    {"slateblue", 0x6a, 0x5a, 0xcd},
     156             :    {"slategray", 0x70, 0x80, 0x90},
     157             :    {"slategrey", 0x70, 0x80, 0x90},
     158             :    {"snow", 0xff, 0xfa, 0xfa},
     159             :    {"springgreen", 0x00, 0xff, 0x7f},
     160             :    {"steelblue", 0x46, 0x82, 0xb4},
     161             :    {"tan", 0xd2, 0xb4, 0x8c},
     162             :    {"teal", 0x00, 0x80, 0x80},
     163             :    {"thistle", 0xd8, 0xbf, 0xd8},
     164             :    {"tomato", 0xff, 0x63, 0x47},
     165             :    {"turquoise", 0x40, 0xe0, 0xd0},
     166             :    {"violet", 0xee, 0x82, 0xee},
     167             :    {"wheat", 0xf5, 0xde, 0xb3},
     168             :    {"white", 0xff, 0xff, 0xff},
     169             :    {"whitesmoke", 0xf5, 0xf5, 0xf5},
     170             :    {"yellow", 0xff, 0xff, 0x00},
     171             :    {"yellowgreen", 0x9a, 0xcd, 0x32},
     172             : };
     173             : 
     174             : #define NUM_COLORS (sizeof(_al_color_names) / sizeof(ColorName))
     175             : 
     176             : static double const Xn = 0.95047;
     177             : static double const Yn = 1.00000;
     178             : static double const Zn = 1.08883;
     179             : static double const delta = 6.0 / 29;
     180             : static double const delta2 = 6.0 / 29 * 6.0 / 29;
     181             : static double const delta3 = 6.0 / 29 * 6.0 / 29 * 6.0 / 29;
     182             : static double const tf7 = 1.0 / 4 / 4 / 4 / 4 / 4 / 4 / 4;
     183             : 
     184             : static void assert_sorted_names(void)
     185             : {
     186             :    /* In debug mode, check once that the array is sorted. */
     187             : #ifdef DEBUGMODE
     188             :    static bool done = false;
     189             :    unsigned i;
     190             : 
     191             :    if (!done) {
     192             :       for (i = 1; i < NUM_COLORS; i++) {
     193             :          ASSERT(strcmp(_al_color_names[i-1].name, _al_color_names[i].name) < 0);
     194             :       }
     195             :       done = true;
     196             :    }
     197             : #endif
     198             : }
     199             : 
     200             : static int compare(const void *va, const void *vb)
     201             : {
     202        3124 :    char const *ca = va;
     203        3124 :    ColorName const *cb = vb;
     204        3124 :    return strcmp(ca, cb->name);
     205             : }
     206             : 
     207             : 
     208             : /* Function: al_color_name_to_rgb
     209             :  */
     210         518 : bool al_color_name_to_rgb(char const *name, float *r, float *g, float *b)
     211             : {
     212             :    void *result;
     213             :    assert_sorted_names();
     214         518 :    result = bsearch(name, _al_color_names, NUM_COLORS, sizeof(ColorName),
     215             :       compare);
     216         518 :    if (result) {
     217         518 :       ColorName *c = result;
     218         518 :       *r = c->r / 255.0;
     219         518 :       *g = c->g / 255.0;
     220         518 :       *b = c->b / 255.0;
     221         518 :       return true;
     222             :    }
     223             :    return false;
     224             : }
     225             : 
     226             : 
     227             : /* Function: al_color_rgb_to_name
     228             :  */
     229           0 : char const *al_color_rgb_to_name(float r, float g, float b)
     230             : {
     231             :    int i;
     232           0 :    int ir = r * 255;
     233           0 :    int ig = g * 255;
     234           0 :    int ib = b * 255;
     235           0 :    int n = NUM_COLORS;
     236           0 :    int min = n, mind = 0;
     237             :    /* Could optimize this, right now it does linear search. */
     238           0 :    for (i = 0; i < n; i++) {
     239           0 :       int dr = _al_color_names[i].r - ir;
     240           0 :       int dg = _al_color_names[i].g - ig;
     241           0 :       int db = _al_color_names[i].b - ib;
     242           0 :       int d = dr * dr + dg * dg + db * db;
     243           0 :       if (min == n || d < mind) {
     244           0 :          min = i;
     245           0 :          mind = d;
     246             :       }
     247             :    }
     248           0 :    return _al_color_names[min].name;
     249             : }
     250             : 
     251             : 
     252             : /* Function: al_color_name
     253             :  */
     254         518 : ALLEGRO_COLOR al_color_name(char const *name)
     255             : {
     256             :    float r, g, b;
     257         518 :    if (al_color_name_to_rgb(name, &r, &g, &b))
     258         518 :       return al_map_rgb_f(r, g, b);
     259             :    else
     260           0 :       return al_map_rgb_f(0, 0, 0);
     261             : }
     262             : 
     263             : 
     264             : /* Function: al_color_hsv_to_rgb
     265             :  */
     266           0 : void al_color_hsv_to_rgb(float hue, float saturation, float value,
     267             :    float *red, float *green, float *blue)
     268             : {
     269             :    int d;
     270             :    float e, a, b, c;
     271             : 
     272           0 :    hue = fmodf(hue, 360);
     273           0 :    if (hue < 0)
     274           0 :       hue += 360;
     275           0 :    d = hue / 60;
     276           0 :    e = hue / 60 - d;
     277           0 :    a = value * (1 - saturation);
     278           0 :    b = value * (1 - e * saturation);
     279           0 :    c = value * (1 - (1 - e) * saturation);
     280           0 :    switch (d) {
     281           0 :       default:
     282           0 :       case 0: *red = value, *green = c,     *blue = a;     return;
     283           0 :       case 1: *red = b,     *green = value, *blue = a;     return;
     284           0 :       case 2: *red = a,     *green = value, *blue = c;     return;
     285           0 :       case 3: *red = a,     *green = b,     *blue = value; return;
     286           0 :       case 4: *red = c,     *green = a,     *blue = value; return;
     287           0 :       case 5: *red = value, *green = a,     *blue = b;     return;
     288             :    }
     289             : }
     290             : 
     291             : 
     292             : /* Function: al_color_rgb_to_hsv
     293             :  */
     294           0 : void al_color_rgb_to_hsv(float red, float green, float blue,
     295             :    float *hue, float *saturation, float *value)
     296             : {
     297             :    float a, b, c, d;
     298           0 :    if (red > green) {
     299           0 :       if (red > blue) {
     300           0 :          if (green > blue)
     301           0 :             a = red, b = green - blue, c = blue, d = 0;
     302             :          else
     303           0 :             a = red, b = green - blue, c = green, d = 0;
     304             :       }
     305             :       else {
     306           0 :          a = blue, b = red - green, c = green, d = 4;
     307             :       }
     308             :    }
     309             :    else {
     310           0 :       if (red > blue)
     311           0 :           a = green, b = blue - red, c = blue, d = 2;
     312           0 :       else if (green > blue)
     313           0 :          a = green, b = blue - red, c = red, d = 2;
     314             :       else
     315           0 :          a = blue, b = red - green, c = red, d = 4;
     316             :    }
     317             : 
     318           0 :    if (a == c) {
     319           0 :       *hue = 0;
     320             :    }
     321             :    else {
     322           0 :       *hue = 60 * (d + b / (a - c));
     323           0 :       if (*hue < 0)
     324           0 :          *hue += 360;
     325           0 :       if (*hue > 360)
     326           0 :          *hue -= 360;
     327             :    }
     328             : 
     329           0 :    if (a == 0)
     330           0 :       *saturation = 0;
     331             :    else
     332           0 :       *saturation = (a - c) / a;
     333           0 :    *value = a;
     334           0 : }
     335             : 
     336             : 
     337             : /* Function: al_color_hsv
     338             :  */
     339           0 : ALLEGRO_COLOR al_color_hsv(float h, float s, float v)
     340             : {
     341             :    float r, g, b;
     342             : 
     343           0 :    al_color_hsv_to_rgb(h, s, v, &r, &g, &b);
     344           0 :    return al_map_rgb_f(r, g, b);
     345             : }
     346             : 
     347             : 
     348           0 : static float hsl_to_rgb_helper(float x, float a, float b)
     349             : {
     350           0 :    if (x < 0)
     351           0 :       x += 1;
     352           0 :    if (x > 1)
     353           0 :       x -= 1;
     354             : 
     355           0 :    if (x * 6 < 1)
     356           0 :       return b + (a - b) * 6 * x;
     357           0 :    if (x * 6 < 3)
     358             :       return a;
     359           0 :    if (x * 6 < 4)
     360           0 :       return b + (a - b) * (4.0 - 6.0 * x);
     361             :    return b;
     362             : }
     363             : 
     364             : 
     365             : /* Function: al_color_hsl_to_rgb
     366             :  */
     367           0 : void al_color_hsl_to_rgb(float hue, float saturation, float lightness,
     368             :    float *red, float *green, float *blue)
     369             : {
     370             :    float a, b, h;
     371             : 
     372           0 :    hue = fmodf(hue, 360);
     373           0 :    if (hue < 0)
     374           0 :       hue += 360;
     375           0 :    h = hue / 360;
     376           0 :    if (lightness < 0.5)
     377           0 :       a = lightness + lightness * saturation;
     378             :    else
     379           0 :       a = lightness + saturation - lightness * saturation;
     380           0 :    b = lightness * 2 - a;
     381           0 :    *red = hsl_to_rgb_helper(h + 1.0 / 3.0, a, b);
     382           0 :    *green = hsl_to_rgb_helper(h, a, b);
     383           0 :    *blue = hsl_to_rgb_helper(h - 1.0 / 3.0, a, b);
     384           0 : }
     385             : 
     386             : 
     387             : /* Function: al_color_rgb_to_hsl
     388             :  */
     389           0 : void al_color_rgb_to_hsl(float red, float green, float blue,
     390             :    float *hue, float *saturation, float *lightness)
     391             : {
     392             :    float a, b, c, d;
     393             : 
     394           0 :    if (red > green) {
     395           0 :       if (red > blue) {
     396           0 :          if (green > blue)
     397           0 :             a = red, b = green - blue, c = blue, d = 0;
     398             :          else
     399           0 :             a = red, b = green - blue, c = green, d = 0;
     400             :       }
     401             :       else {
     402           0 :          a = blue, b = red - green, c = green, d = 4;
     403             :       }
     404             :    }
     405             :    else {
     406           0 :       if (red > blue)
     407           0 :          a = green, b = blue - red, c = blue, d = 2;
     408           0 :       else if (green > blue)
     409           0 :          a = green, b = blue - red, c = red, d = 2;
     410             :       else
     411           0 :          a = blue, b = red - green, c = red, d = 4;
     412             :    }
     413             : 
     414           0 :    if (a == c) {
     415           0 :       *hue = 0;
     416             :    }
     417             :    else {
     418           0 :       *hue = 60 * (d + b / (a - c));
     419           0 :       if (*hue < 0)
     420           0 :          *hue += 360;
     421             :    }
     422             : 
     423           0 :    if (a == c)
     424           0 :       *saturation = 0;
     425           0 :    else if (a + c < 1)
     426           0 :       *saturation = (a - c) / (a + c);
     427             :    else
     428           0 :       *saturation = (a - c) / (2 - a - c);
     429             : 
     430           0 :    *lightness = (a + c) / 2;
     431           0 : }
     432             : 
     433             : 
     434             : /* Function: al_color_hsl
     435             :  */
     436           0 : ALLEGRO_COLOR al_color_hsl(float h, float s, float l)
     437             : {
     438             :    float r, g, b;
     439           0 :    al_color_hsl_to_rgb(h, s, l, &r, &g, &b);
     440           0 :    return al_map_rgb_f(r, g, b);
     441             : }
     442             : 
     443             : 
     444             : /* Function: al_color_cmyk_to_rgb
     445             :  */
     446           0 : void al_color_cmyk_to_rgb(float cyan, float magenta, float yellow,
     447             :     float key, float *red, float *green, float *blue)
     448             : {
     449           0 :    float max = 1 - key;
     450           0 :    *red = max - cyan * max;
     451           0 :    *green = max - magenta * max;
     452           0 :    *blue = max - yellow * max;
     453           0 : }
     454             : 
     455             : 
     456             : /* Function: al_color_rgb_to_cmyk
     457             :  */
     458           0 : void al_color_rgb_to_cmyk(float red, float green, float blue,
     459             :    float *cyan, float *magenta, float *yellow, float *key)
     460             : {
     461           0 :    float max = red;
     462           0 :    if (green > max)
     463           0 :       max = green;
     464           0 :    if (blue > max)
     465           0 :       max = blue;
     466           0 :    *key = 1 - max;
     467           0 :    if (max > 0) {
     468           0 :       *cyan = (max - red) / max;
     469           0 :       *magenta = (max - green) / max;
     470           0 :       *yellow = (max - blue) / max;
     471             :    }
     472             :    else {
     473           0 :       *cyan = *magenta = *yellow = 0;
     474             :    }
     475           0 : }
     476             : 
     477             : 
     478             : /* Function: al_color_cmyk
     479             :  */
     480           0 : ALLEGRO_COLOR al_color_cmyk(float c, float m, float y, float k)
     481             : {
     482             :    float r, g, b;
     483           0 :    al_color_cmyk_to_rgb(c, m, y, k, &r, &g, &b);
     484           0 :    return al_map_rgb_f(r, g, b);
     485             : }
     486             : 
     487             : 
     488             : /* Function: al_color_yuv_to_rgb
     489             :  */
     490           0 : void al_color_yuv_to_rgb(float y, float u, float v,
     491             :     float *red, float *green, float *blue)
     492             : {
     493             :    /* Translate range 0..1 to actual range. */
     494           0 :    u = 0.436 * (u * 2 - 1);
     495           0 :    v = 0.615 * (v * 2 - 1);
     496           0 :    *red = _ALLEGRO_CLAMP(0, 1, y + v * 1.13983);
     497           0 :    *green = _ALLEGRO_CLAMP(0, 1, y + u * -0.39465 + v * -0.58060);
     498           0 :    *blue = _ALLEGRO_CLAMP(0, 1, y + u * 2.03211);
     499           0 : }
     500             : 
     501             : 
     502             : /* Function: al_color_rgb_to_yuv
     503             :  */
     504           0 : void al_color_rgb_to_yuv(float red, float green, float blue,
     505             :    float *y, float *u, float *v)
     506             : {
     507           0 :    *y = red * 0.299 + green * 0.587 + blue * 0.114;
     508           0 :    *u = red * -0.14713 + green * -0.28886 + blue * 0.436;
     509           0 :    *v = red * 0.615 + green * -0.51499 + blue * -0.10001;
     510             :    /* Normalize chroma components into 0..1 range. */
     511           0 :    *u = (*u / 0.436 + 1) * 0.5;
     512           0 :    *v = (*v / 0.615 + 1) * 0.5;
     513           0 : }
     514             : 
     515             : 
     516             : /* Function: al_color_yuv
     517             :  */
     518           0 : ALLEGRO_COLOR al_color_yuv(float y, float u, float v)
     519             : {
     520             :    float r, g, b;
     521           0 :    al_color_yuv_to_rgb(y, u, v, &r, &g, &b);
     522           0 :    return al_map_rgb_f(r, g, b);
     523             : }
     524             : 
     525             : 
     526             : /* Function: al_color_rgb_to_html
     527             :  */
     528           0 : void al_color_rgb_to_html(float red, float green, float blue,
     529             :     char *string)
     530             : {
     531           0 :    sprintf(string, "#%02x%02x%02x", (int)(red * 255),
     532           0 :       (int)(green * 255), (int)(blue * 255));
     533           0 : }
     534             : 
     535             : 
     536             : /* Function: al_color_html_to_rgb
     537             :  */
     538           0 : bool al_color_html_to_rgb(char const *string,
     539             :    float *red, float *green, float *blue)
     540             : {
     541           0 :    char const *ptr = string;
     542             :    int ir, ig, ib;
     543             :    ASSERT(ptr);
     544             :    ASSERT(red);
     545             :    ASSERT(green);
     546             :    ASSERT(blue);
     547             : 
     548           0 :    *red = *green = *blue = 0.0f;
     549             : 
     550           0 :    if (*ptr == '#')
     551           0 :       ptr++;
     552             : 
     553           0 :    if (strlen(ptr) != 6)
     554             :       return false;
     555             : 
     556           0 :    if (sscanf(ptr, "%02x%02x%02x", &ir, &ig, &ib) != 3)
     557             :       return false;
     558             : 
     559           0 :    *red = ir / 255.0;
     560           0 :    *green = ig / 255.0;
     561           0 :    *blue = ib / 255.0;
     562           0 :    return true;
     563             : }
     564             : 
     565             : 
     566             : /* Function: al_color_html
     567             :  */
     568           0 : ALLEGRO_COLOR al_color_html(char const *string)
     569             : {
     570             :    float r, g, b;
     571             : 
     572           0 :    if (al_color_html_to_rgb(string, &r, &g, &b))
     573           0 :       return al_map_rgb_f(r, g, b);
     574             :    else
     575           0 :       return al_map_rgba(0, 0, 0, 0);
     576             : }
     577             : 
     578             : 
     579             : /* Function: al_get_allegro_color_version
     580             :  */
     581           0 : uint32_t al_get_allegro_color_version(void)
     582             : {
     583           0 :    return ALLEGRO_VERSION_INT;
     584             : }
     585             : 
     586             : 
     587             : /* Converts from an sRGB color component to the linear value.
     588             :  */
     589             : static double srgba_gamma_to_linear(double x) {
     590         204 :    double const a = 0.055;
     591         204 :    if (x < 0.04045) return x / 12.92;
     592         184 :    return pow((x + a) / (1 + a), 2.4);
     593             : }
     594             : 
     595             : 
     596             : /* Converts a linear color component back into sRGB.
     597             :  */
     598             : static double srgba_linear_to_gamma(double x) {
     599         204 :    double const a = 0.055;
     600         204 :    if (x < 0.0031308) return x * 12.92;
     601         184 :    return pow(x, 1 / 2.4) * (1 + a) - a;
     602             : }
     603             : 
     604             : 
     605             : /* Function: al_color_xyz_to_rgb
     606             :  */
     607          68 : void al_color_xyz_to_rgb(float x, float y, float z,
     608             :     float *red, float *green, float *blue)
     609             : {
     610          68 :    double r = 3.2406 * x + (-1.5372 * y) + (-0.4986 * z);
     611          68 :    double g = -0.9689 * x + 1.8758 * y + 0.0415 * z;
     612          68 :    double b = 0.0557 * x + (-0.2040 * y) + 1.0570 * z;
     613          68 :    *red = srgba_linear_to_gamma(r);
     614          68 :    *green = srgba_linear_to_gamma(g);
     615          68 :    *blue = srgba_linear_to_gamma(b);
     616          68 : }
     617             : 
     618             : 
     619             : /* Function: al_color_rgb_to_xyz
     620             :  */
     621          68 : void al_color_rgb_to_xyz(float red, float green, float blue,
     622             :    float *x, float *y, float *z)
     623             : {
     624         136 :    double r = srgba_gamma_to_linear(red);
     625         136 :    double g = srgba_gamma_to_linear(green);
     626         136 :    double b = srgba_gamma_to_linear(blue);
     627          68 :    *x = r * 0.4124 + g * 0.3576 + b * 0.1805;
     628          68 :    *y = r * 0.2126 + g * 0.7152 + b * 0.0722;
     629          68 :    *z = r * 0.0193 + g * 0.1192 + b * 0.9505;
     630          68 : }
     631             : 
     632             : 
     633             : /* Function: al_color_xyz
     634             :  */
     635           0 : ALLEGRO_COLOR al_color_xyz(float x, float y, float z)
     636             : {
     637             :    float r, g, b;
     638           0 :    al_color_xyz_to_rgb(x, y, z, &r, &g, &b);
     639           0 :    return al_map_rgb_f(r, g, b);
     640             : }
     641             : 
     642             : 
     643             : static double cielab_f(double x) {
     644         340 :    if (x > delta3) return pow(x, 1.0 / 3);
     645          19 :    return 4.0 / 29 + x / delta2 / 3;
     646             : }
     647             : 
     648             : 
     649             : static double cielab_f_inv(double x) {
     650         204 :    if (x > delta) return pow(x, 3);
     651          11 :    return (x - 4.0 / 29) * 3 * delta2;
     652             : }
     653             : 
     654             : 
     655             : /* Function: al_color_lab_to_rgb
     656             :  */
     657          68 : void al_color_lab_to_rgb(float l, float a, float b,
     658             :     float *red, float *green, float *blue)
     659             : {
     660         136 :    float x = Xn * cielab_f_inv((l + 0.16) / 1.16 + a / 5.00);
     661         136 :    float y = Yn * cielab_f_inv((l + 0.16) / 1.16);
     662         136 :    float z = Zn * cielab_f_inv((l + 0.16) / 1.16 - b / 2.00);
     663          68 :    al_color_xyz_to_rgb(x, y, z, red, green, blue);
     664          68 : }
     665             : 
     666             : 
     667             : /* Function: al_color_rgb_to_lab
     668             :  */
     669          68 : void al_color_rgb_to_lab(float red, float green, float blue,
     670             :    float *l, float *a, float *b)
     671             : {
     672             :    float x, y, z;
     673          68 :    al_color_rgb_to_xyz(red, green, blue, &x, &y, &z);
     674          68 :    x /= Xn;
     675          68 :    y /= Yn;
     676          68 :    z /= Zn;
     677         136 :    *l = 1.16 * cielab_f(y) - 0.16;
     678         204 :    *a = 5.00 * (cielab_f(x) - cielab_f(y));
     679         204 :    *b = 2.00 * (cielab_f(y) - cielab_f(z));
     680          68 : }
     681             : 
     682             : 
     683             : /* Function: al_color_lab
     684             :  */
     685          68 : ALLEGRO_COLOR al_color_lab(float l, float a, float b)
     686             : {
     687             :    float r2, g2, b2;
     688          68 :    al_color_lab_to_rgb(l, a, b, &r2, &g2, &b2);
     689          68 :    return al_map_rgb_f(r2, g2, b2);
     690             : }
     691             : 
     692             : 
     693             : /* Function: al_color_lch_to_rgb
     694             :  */
     695           0 : void al_color_lch_to_rgb(float l, float c, float h,
     696             :     float *red, float *green, float *blue)
     697             : {
     698           0 :    double a = c * cos(h);
     699           0 :    double b = c * sin(h);
     700           0 :    al_color_lab_to_rgb(l, a, b, red, green, blue);
     701           0 : }
     702             : 
     703             : 
     704             : /* Function: al_color_rgb_to_lch
     705             :  */
     706           0 : void al_color_rgb_to_lch(float red, float green, float blue,
     707             :    float *l, float *c, float *h)
     708             : {
     709             :    float a, b;
     710           0 :    al_color_rgb_to_lab(red, green, blue, l, &a, &b);
     711           0 :    *c = sqrt(a * a + b * b);
     712           0 :    *h = fmod(ALLEGRO_PI * 2 + atan2(b, a), ALLEGRO_PI * 2);
     713           0 : }
     714             : 
     715             : 
     716             : /* Function: al_color_lch
     717             :  */
     718           0 : ALLEGRO_COLOR al_color_lch(float l, float c, float h)
     719             : {
     720             :    float r, g, b;
     721           0 :    al_color_lch_to_rgb(l, c, h, &r, &g, &b);
     722           0 :    return al_map_rgb_f(r, g, b);
     723             : }
     724             : 
     725             : 
     726             : /* Function: al_color_xyy_to_rgb
     727             :  */
     728           0 : void al_color_xyy_to_rgb(float x, float y, float y2,
     729             :     float *red, float *green, float *blue)
     730             : {
     731           0 :    double x2 = x * y / y2;
     732           0 :    double z2 = (1 - y2 - x) * y / y2;
     733           0 :    al_color_xyz_to_rgb(x2, y2, z2, red, green, blue);
     734           0 : }
     735             : 
     736             : 
     737             : /* Function: al_color_rgb_to_xyy
     738             :  */
     739           0 : void al_color_rgb_to_xyy(float red, float green, float blue,
     740             :    float *x, float *y, float *y2)
     741             : {
     742             :    float x2, z2;
     743           0 :    al_color_rgb_to_xyz(red, green, blue, &x2, y2, &z2);
     744           0 :    *x = x2 / (x2 + *y2 + z2);
     745           0 :    *y = *y2 / (x2 + *y2 + z2);
     746           0 : }
     747             : 
     748             : 
     749             : /* Function: al_color_xyy
     750             :  */
     751           0 : ALLEGRO_COLOR al_color_xyy(float x, float y, float y2)
     752             : {
     753             :    float r, g, b;
     754           0 :    al_color_xyy_to_rgb(x, y, y2, &r, &g, &b);
     755           0 :    return al_map_rgb_f(r, g, b);
     756             : }
     757             : 
     758             : 
     759             : /* Function: al_color_distance_ciede2000
     760             :  */
     761          34 : double al_color_distance_ciede2000(ALLEGRO_COLOR color1,
     762             :       ALLEGRO_COLOR color2) {
     763             :    /* For implementation details refer to e.g.
     764             :     * http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
     765             :     */
     766             :    float l1, a1, b1, l2, a2, b2;
     767          34 :    al_color_rgb_to_lab(color1.r, color1.g, color1.b, &l1, &a1, &b1);
     768          34 :    al_color_rgb_to_lab(color2.r, color2.g, color2.b, &l2, &a2, &b2);
     769          34 :    double pi = ALLEGRO_PI;
     770          34 :    double dl = l1 - l2;
     771          34 :    double ml = (l1 + l2) / 2;
     772          34 :    double c1 = sqrt(a1 * a1 + b1 * b1);
     773          34 :    double c2 = sqrt(a2 * a2 + b2 * b2);
     774          34 :    double mc = (c1 + c2) / 2;
     775          34 :    double fac = sqrt(pow(mc, 7) / (pow(mc, 7) + tf7));
     776          34 :    double g = 0.5 * (1 - fac);
     777          34 :    a1 *= 1 + g;
     778          34 :    a2 *= 1 + g;
     779          34 :    c1 = sqrt(a1 * a1 + b1 * b1);
     780          34 :    c2 = sqrt(a2 * a2 + b2 * b2);
     781          34 :    double dc = c2 - c1;
     782          34 :    mc = (c1 + c2) / 2;
     783          34 :    fac = sqrt(pow(mc, 7) / (pow(mc, 7) + tf7));
     784          34 :    double h1 = fmod(2 * pi + atan2(b1, a1), 2 * pi);
     785          34 :    double h2 = fmod(2 * pi + atan2(b2, a2), 2 * pi);
     786          34 :    double dh = 0;
     787          34 :    double mh = h1 + h2;
     788          34 :    if (c1 * c2 != 0) {
     789          34 :       dh = h2 - h1;
     790          34 :       if (dh > pi) dh -= 2 * pi;
     791          34 :       if (dh < -pi) dh += 2 * pi;
     792          34 :       if (fabs(h1 - h2) <= pi) mh = (h1 + h2) / 2;
     793           7 :       else if (h1 + h2 < 2 * pi) mh = (h1 + h2 + 2 * pi) / 2;
     794           4 :       else mh = (h1 + h2 - 2 * pi) / 2;
     795             :    }
     796          34 :    dh = 2 * sqrt(c1 * c2) * sin(dh / 2);
     797         102 :    double t = 1 - 0.17 * cos(mh - pi / 6) + 0.24 * cos(2 * mh) +
     798          68 :          0.32 * cos(3 * mh + pi / 30) - 0.2 * cos(4 * mh - pi * 7 / 20);
     799          34 :    double mls = pow(ml - 0.5, 2);
     800          34 :    double sl = 1 + 1.5 * mls / sqrt(0.002 + mls);
     801          34 :    double sc = 1 + 4.5 * mc;
     802          34 :    double sh = 1 + 1.5 * mc * t;
     803          68 :    double rt = -2 * fac * sin(pi / 3 *
     804          34 :          exp(-pow(mh / pi * 36 / 5 - 11, 2)));
     805         102 :    return sqrt(pow(dl / sl, 2) + pow(dc / sc, 2) +
     806          68 :          pow(dh / sh, 2) + rt * dc / sc * dh / sh);
     807             : }
     808             : 
     809             : /* Function al_color_is_valid
     810             :  */
     811           0 : bool al_is_color_valid(ALLEGRO_COLOR color)
     812             : {
     813           0 :    return color.r >= 0 && color.g >= 0 && color.b >= 0 &&
     814           0 :       color.r <= 1 && color.g <= 1 && color.b <= 1;
     815             : }
     816             : 
     817             : /* vim: set sts=3 sw=3 et: */

Generated by: LCOV version 1.13