"Fossies" - the Fresh Open Source Software Archive

Member "libcaca-0.99.beta20/caca/dither.c" (27 Feb 2019, 42194 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  *  libcaca     Colour ASCII-Art library
    3  *  Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net>
    4  *              All Rights Reserved
    5  *
    6  *  This library is free software. It comes without any warranty, to
    7  *  the extent permitted by applicable law. You can redistribute it
    8  *  and/or modify it under the terms of the Do What the Fuck You Want
    9  *  to Public License, Version 2, as published by the WTFPL Task Force.
   10  *  See http://www.wtfpl.net/ for more details.
   11  */
   12 
   13 /*
   14  *  This file contains bitmap dithering functions.
   15  */
   16 
   17 #include "config.h"
   18 
   19 #if !defined(__KERNEL__)
   20 #   if defined(HAVE_ENDIAN_H)
   21 #       include <endian.h>
   22 #   endif
   23 #   include <stdio.h>
   24 #   include <stdlib.h>
   25 #   include <limits.h>
   26 #   include <string.h>
   27 #endif
   28 
   29 #include "caca.h"
   30 #include "caca_internals.h"
   31 
   32 #define CP437 0
   33 
   34 /*
   35  * Local variables
   36  */
   37 #if !defined(_DOXYGEN_SKIP_ME)
   38 #   define LOOKUP_VAL 32
   39 #   define LOOKUP_SAT 32
   40 #   define LOOKUP_HUE 16
   41 #endif
   42 static uint8_t hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
   43 static uint16_t lookup_colors[8];
   44 static int lookup_initialised = 0;
   45 
   46 static int const hsv_palette[] =
   47 {
   48     /* weight, hue, saturation, value */
   49     4,    0x0,    0x0,    0x0,   /* black */
   50     5,    0x0,    0x0,    0x5ff, /* 30% */
   51     5,    0x0,    0x0,    0x9ff, /* 70% */
   52     4,    0x0,    0x0,    0xfff, /* white */
   53     3,    0x1000, 0xfff,  0x5ff, /* dark yellow */
   54     2,    0x1000, 0xfff,  0xfff, /* light yellow */
   55     3,    0x0,    0xfff,  0x5ff, /* dark red */
   56     2,    0x0,    0xfff,  0xfff  /* light red */
   57 };
   58 
   59 /* RGB palette for the new colour picker */
   60 static int const rgb_palette[] =
   61 {
   62     0x0,   0x0,   0x0,
   63     0x0,   0x0,   0x7ff,
   64     0x0,   0x7ff, 0x0,
   65     0x0,   0x7ff, 0x7ff,
   66     0x7ff, 0x0,   0x0,
   67     0x7ff, 0x0,   0x7ff,
   68     0x7ff, 0x7ff, 0x0,
   69     0xaaa, 0xaaa, 0xaaa,
   70     0x555, 0x555, 0x555,
   71     0x000, 0x000, 0xfff,
   72     0x000, 0xfff, 0x000,
   73     0x000, 0xfff, 0xfff,
   74     0xfff, 0x000, 0x000,
   75     0xfff, 0x000, 0xfff,
   76     0xfff, 0xfff, 0x000,
   77     0xfff, 0xfff, 0xfff,
   78 };
   79 
   80 static int const rgb_weight[] =
   81 {
   82     /* 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2 */
   83     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
   84 };
   85 
   86 /* List of glyphs */
   87 static uint32_t ascii_glyphs[] =
   88 {
   89     ' ', '.', ':', ';', 't', '%', 'S', 'X', '@', '8', '?'
   90 };
   91 
   92 static uint32_t shades_glyphs[] =
   93 {
   94     /* ' '. '·', '░', '▒', '?' */
   95     ' ', 0xb7, 0x2591, 0x2592, '?'
   96 };
   97 
   98 static uint32_t blocks_glyphs[] =
   99 {
  100     /* ' ', '▘', '▚', '?' */
  101     ' ', 0x2598, 0x259a, '?'
  102 };
  103 
  104 #if !defined(_DOXYGEN_SKIP_ME)
  105 enum color_mode
  106 {
  107     COLOR_MODE_MONO,
  108     COLOR_MODE_GRAY,
  109     COLOR_MODE_8,
  110     COLOR_MODE_16,
  111     COLOR_MODE_FULLGRAY,
  112     COLOR_MODE_FULL8,
  113     COLOR_MODE_FULL16
  114 };
  115 
  116 struct caca_dither
  117 {
  118     int bpp, has_palette, has_alpha;
  119     size_t w, h, pitch;
  120     int rmask, gmask, bmask, amask;
  121     int rright, gright, bright, aright;
  122     int rleft, gleft, bleft, aleft;
  123     void (*get_hsv)(caca_dither_t *, char *, int, int);
  124     int red[256], green[256], blue[256], alpha[256];
  125 
  126     /* Colour features */
  127     float gamma, brightness, contrast;
  128     int gammatab[4097];
  129 
  130     /* Dithering features */
  131     char const *antialias_name;
  132     int antialias;
  133 
  134     char const *color_name;
  135     enum color_mode color;
  136 
  137     char const *algo_name;
  138     void (*init_dither) (int);
  139     int (*get_dither) (void);
  140     void (*increment_dither) (void);
  141 
  142     char const *glyph_name;
  143     uint32_t const * glyphs;
  144     int glyph_count;
  145 
  146     int invert;
  147 };
  148 
  149 #define HSV_XRATIO 6
  150 #define HSV_YRATIO 3
  151 #define HSV_HRATIO 3
  152 
  153 #define HSV_DISTANCE(h, s, v, index) \
  154     (hsv_palette[index * 4] \
  155      * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
  156                     * ((v) - hsv_palette[index * 4 + 3])) \
  157        + (hsv_palette[index * 4 + 3] \
  158            ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
  159                          * ((s) - hsv_palette[index * 4 + 2])) \
  160            : 0) \
  161        + (hsv_palette[index * 4 + 2] \
  162            ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
  163                          * ((h) - hsv_palette[index * 4 + 1])) \
  164            : 0)))
  165 #endif
  166 
  167 /*
  168  * Local prototypes
  169  */
  170 static void mask2shift(uint32_t, int *, int *);
  171 static float gammapow(float x, float y);
  172 
  173 static void get_rgba_default(caca_dither_t const *, uint8_t const *, int, int,
  174                              unsigned int *);
  175 static int init_lookup(void);
  176 
  177 /* Dithering algorithms */
  178 static void init_no_dither(int);
  179 static int get_no_dither(void);
  180 static void increment_no_dither(void);
  181 
  182 static void init_fstein_dither(int);
  183 static int get_fstein_dither(void);
  184 static void increment_fstein_dither(void);
  185 
  186 static void init_ordered2_dither(int);
  187 static int get_ordered2_dither(void);
  188 static void increment_ordered2_dither(void);
  189 
  190 static void init_ordered4_dither(int);
  191 static int get_ordered4_dither(void);
  192 static void increment_ordered4_dither(void);
  193 
  194 static void init_ordered8_dither(int);
  195 static int get_ordered8_dither(void);
  196 static void increment_ordered8_dither(void);
  197 
  198 static void init_random_dither(int);
  199 static int get_random_dither(void);
  200 static void increment_random_dither(void);
  201 
  202 static inline int sq(int x)
  203 {
  204     return x * x;
  205 }
  206 
  207 static inline void rgb2hsv_default(int r, int g, int b,
  208                                    int *hue, int *sat, int *val)
  209 {
  210     int min, max, delta;
  211 
  212     min = r; max = r;
  213     if(min > g) min = g; if(max < g) max = g;
  214     if(min > b) min = b; if(max < b) max = b;
  215 
  216     delta = max - min; /* 0 - 0xfff */
  217     *val = max; /* 0 - 0xfff */
  218 
  219     if(delta)
  220     {
  221         *sat = 0xfff * delta / max; /* 0 - 0xfff */
  222 
  223         /* Generate *hue between 0 and 0x5fff */
  224         if( r == max )
  225             *hue = 0x1000 + 0x1000 * (g - b) / delta;
  226         else if( g == max )
  227             *hue = 0x3000 + 0x1000 * (b - r) / delta;
  228         else
  229             *hue = 0x5000 + 0x1000 * (r - g) / delta;
  230     }
  231     else
  232     {
  233         *sat = 0;
  234         *hue = 0;
  235     }
  236 }
  237 
  238 /** \brief Create an internal dither object.
  239  *
  240  *  Create a dither structure from its coordinates (depth, width, height and
  241  *  pitch) and pixel mask values. If the depth is 8 bits per pixel, the mask
  242  *  values are ignored and the colour palette should be set using the
  243  *  caca_set_dither_palette() function. For depths greater than 8 bits per
  244  *  pixel, a zero alpha mask causes the alpha values to be ignored.
  245  *
  246  *  If an error occurs, NULL is returned and \b errno is set accordingly:
  247  *  - \c EINVAL Requested width, height, pitch or bits per pixel value was
  248  *    invalid.
  249  *  - \c ENOMEM Not enough memory to allocate dither structure.
  250  *
  251  *  \param bpp Bitmap depth in bits per pixel.
  252  *  \param w Bitmap width in pixels.
  253  *  \param h Bitmap height in pixels.
  254  *  \param pitch Bitmap pitch in bytes.
  255  *  \param rmask Bitmask for red values.
  256  *  \param gmask Bitmask for green values.
  257  *  \param bmask Bitmask for blue values.
  258  *  \param amask Bitmask for alpha values.
  259  *  \return Dither object upon success, NULL if an error occurred.
  260  */
  261 caca_dither_t *caca_create_dither(int bpp, int w, int h, int pitch,
  262                                     uint32_t rmask, uint32_t gmask,
  263                                     uint32_t bmask, uint32_t amask)
  264 {
  265     caca_dither_t *d;
  266     int i;
  267 
  268     /* Minor sanity test */
  269     if(w < 0 || h < 0 || pitch < 0 || bpp > 32 || bpp < 8)
  270     {
  271         seterrno(EINVAL);
  272         return NULL;
  273     }
  274 
  275     d = malloc(sizeof(caca_dither_t));
  276     if(!d)
  277     {
  278         seterrno(ENOMEM);
  279         return NULL;
  280     }
  281 
  282     if(!lookup_initialised)
  283     {
  284         /* XXX: because we do not wish to be thread-safe, there is a slight
  285          * chance that the following code will be executed twice. It is
  286          * totally harmless. */
  287         init_lookup();
  288         lookup_initialised = 1;
  289     }
  290 
  291     d->bpp = bpp;
  292     d->has_palette = 0;
  293     d->has_alpha = amask ? 1 : 0;
  294 
  295     d->w = w;
  296     d->h = h;
  297     d->pitch = pitch;
  298 
  299     d->rmask = rmask;
  300     d->gmask = gmask;
  301     d->bmask = bmask;
  302     d->amask = amask;
  303 
  304     /* Load bitmasks */
  305     if(rmask || gmask || bmask || amask)
  306     {
  307         mask2shift(rmask, &d->rright, &d->rleft);
  308         mask2shift(gmask, &d->gright, &d->gleft);
  309         mask2shift(bmask, &d->bright, &d->bleft);
  310         mask2shift(amask, &d->aright, &d->aleft);
  311     }
  312 
  313     /* In 8 bpp mode, default to a grayscale palette */
  314     if(bpp == 8)
  315     {
  316         d->has_palette = 1;
  317         d->has_alpha = 0;
  318         for(i = 0; i < 256; i++)
  319         {
  320             d->red[i] = i * 0xfff / 256;
  321             d->green[i] = i * 0xfff / 256;
  322             d->blue[i] = i * 0xfff / 256;
  323         }
  324     }
  325 
  326     /* Default gamma value */
  327     d->gamma = 1.0;
  328     for(i = 0; i < 4096; i++)
  329         d->gammatab[i] = i;
  330 
  331     /* Default colour properties */
  332     d->brightness = 1.0;
  333     d->contrast = 1.0;
  334 
  335     /* Default features */
  336     d->antialias_name = "prefilter";
  337     d->antialias = 1;
  338 
  339     d->color_name = "full16";
  340     d->color = COLOR_MODE_FULL16;
  341 
  342     d->glyph_name = "ascii";
  343     d->glyphs = ascii_glyphs;
  344     d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
  345 
  346     d->algo_name = "fstein";
  347     d->init_dither = init_fstein_dither;
  348     d->get_dither = get_fstein_dither;
  349     d->increment_dither = increment_fstein_dither;
  350 
  351     d->invert = 0;
  352 
  353     return d;
  354 }
  355 
  356 /** \brief Set the palette of an 8bpp dither object.
  357  *
  358  *  Set the palette of an 8 bits per pixel bitmap. Values should be between
  359  *  0 and 4095 (0xfff).
  360  *
  361  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  362  *  - \c EINVAL Dither bits per pixel value is not 8, or one of the pixel
  363  *   values was outside the range 0 - 4095.
  364  *
  365  *  \param d Dither object.
  366  *  \param red Array of 256 red values.
  367  *  \param green Array of 256 green values.
  368  *  \param blue Array of 256 blue values.
  369  *  \param alpha Array of 256 alpha values.
  370  *  \return 0 in case of success, -1 if an error occurred.
  371  */
  372 int caca_set_dither_palette(caca_dither_t *d,
  373                              uint32_t red[], uint32_t green[],
  374                              uint32_t blue[], uint32_t alpha[])
  375 {
  376     int i, has_alpha = 0;
  377 
  378     if(d->bpp != 8)
  379     {
  380         seterrno(EINVAL);
  381         return -1;
  382     }
  383 
  384     for(i = 0; i < 256; i++)
  385     {
  386         if((red[i] | green[i] | blue[i] | alpha[i]) >= 0x1000)
  387         {
  388             seterrno(EINVAL);
  389             return -1;
  390         }
  391     }
  392 
  393     for(i = 0; i < 256; i++)
  394     {
  395         d->red[i] = red[i];
  396         d->green[i] = green[i];
  397         d->blue[i] = blue[i];
  398         if(alpha[i])
  399         {
  400             d->alpha[i] = alpha[i];
  401             has_alpha = 1;
  402         }
  403     }
  404 
  405     d->has_alpha = has_alpha;
  406 
  407     return 0;
  408 }
  409 
  410 /** \brief Set the brightness of a dither object.
  411  *
  412  *  Set the brightness of dither.
  413  *
  414  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  415  *  - \c EINVAL Brightness value was out of range.
  416  *
  417  *  \param d Dither object.
  418  *  \param brightness brightness value.
  419  *  \return 0 in case of success, -1 if an error occurred.
  420  */
  421 int caca_set_dither_brightness(caca_dither_t *d, float brightness)
  422 {
  423     /* FIXME */
  424     d->brightness = brightness;
  425 
  426     return 0;
  427 }
  428 
  429 /** \brief Get the brightness of a dither object.
  430  *
  431  *  Get the brightness of the given dither object.
  432  *
  433  *  This function never fails.
  434  *
  435  *  \param d Dither object.
  436  *  \return Brightness value.
  437  */
  438 float caca_get_dither_brightness(caca_dither_t const *d)
  439 {
  440     return d->brightness;
  441 }
  442 
  443 /** \brief Set the gamma of a dither object.
  444  *
  445  *  Set the gamma of the given dither object. A negative value causes
  446  *  colour inversion.
  447  *
  448  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  449  *  - \c EINVAL Gamma value was out of range.
  450  *
  451  *  \param d Dither object.
  452  *  \param gamma Gamma value.
  453  *  \return 0 in case of success, -1 if an error occurred.
  454  */
  455 int caca_set_dither_gamma(caca_dither_t *d, float gamma)
  456 {
  457     /* FIXME: we don't need 4096 calls to gammapow(), we could just compute
  458      * a few of them and do linear interpolation for the rest. This will
  459      * probably speed up things a lot. */
  460     int i;
  461 
  462     if(gamma < 0.0)
  463     {
  464         d->invert = 1;
  465         gamma = -gamma;
  466     }
  467     else if(gamma == 0.0)
  468     {
  469         seterrno(EINVAL);
  470         return -1;
  471     }
  472 
  473     d->gamma = gamma;
  474 
  475     for(i = 0; i < 4096; i++)
  476         d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma);
  477 
  478     return 0;
  479 }
  480 
  481 /** \brief Get the gamma of a dither object.
  482  *
  483  *  Get the gamma of the given dither object.
  484  *
  485  *  This function never fails.
  486  *
  487  *  \param d Dither object.
  488  *  \return Gamma value.
  489  */
  490 float caca_get_dither_gamma(caca_dither_t const *d)
  491 {
  492     return d->gamma;
  493 }
  494 
  495 /** \brief Set the contrast of a dither object.
  496  *
  497  *  Set the contrast of dither.
  498  *
  499  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  500  *  - \c EINVAL Contrast value was out of range.
  501  *
  502  *  \param d Dither object.
  503  *  \param contrast contrast value.
  504  *  \return 0 in case of success, -1 if an error occurred.
  505  */
  506 int caca_set_dither_contrast(caca_dither_t *d, float contrast)
  507 {
  508     /* FIXME */
  509     d->contrast = contrast;
  510 
  511     return 0;
  512 }
  513 
  514 /** \brief Get the contrast of a dither object.
  515  *
  516  *  Get the contrast of the given dither object.
  517  *
  518  *  This function never fails.
  519  *
  520  *  \param d Dither object.
  521  *  \return Contrast value.
  522  */
  523 float caca_get_dither_contrast(caca_dither_t const *d)
  524 {
  525     return d->contrast;
  526 }
  527 
  528 /** \brief Set dither antialiasing
  529  *
  530  *  Tell the renderer whether to antialias the dither. Antialiasing smoothens
  531  *  the rendered image and avoids the commonly seen staircase effect.
  532  *  - \c "none": no antialiasing.
  533  *  - \c "prefilter" or \c "default": simple prefilter antialiasing. This
  534  *    is the default value.
  535  *
  536  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  537  *  - \c EINVAL Invalid antialiasing mode.
  538  *
  539  *  \param d Dither object.
  540  *  \param str A string describing the antialiasing method that will be used
  541  *         for the dithering.
  542  *  \return 0 in case of success, -1 if an error occurred.
  543  */
  544 int caca_set_dither_antialias(caca_dither_t *d, char const *str)
  545 {
  546     if(!strcasecmp(str, "none"))
  547     {
  548         d->antialias_name = "none";
  549         d->antialias = 0;
  550     }
  551     else if(!strcasecmp(str, "prefilter") || !strcasecmp(str, "default"))
  552     {
  553         d->antialias_name = "prefilter";
  554         d->antialias = 1;
  555     }
  556     else
  557     {
  558         seterrno(EINVAL);
  559         return -1;
  560     }
  561 
  562     return 0;
  563 }
  564 
  565 /** \brief Get available antialiasing methods
  566  *
  567  *  Return a list of available antialiasing methods for a given dither. The
  568  *  list is a NULL-terminated array of strings, interleaving a string
  569  *  containing the internal value for the antialiasing method to be used with
  570  *  caca_set_dither_antialias(), and a string containing the natural
  571  *  language description for that antialiasing method.
  572  *
  573  *  This function never fails.
  574  *
  575  *  \param d Dither object.
  576  *  \return An array of strings.
  577  */
  578 char const * const *
  579     caca_get_dither_antialias_list(caca_dither_t const *d)
  580 {
  581     static char const * const list[] =
  582     {
  583         "none", "No antialiasing",
  584         "prefilter", "Prefilter antialiasing",
  585         NULL, NULL
  586     };
  587 
  588     return list;
  589 }
  590 
  591 /** \brief Get current antialiasing method
  592  *
  593  *  Return the given dither's current antialiasing method.
  594  *
  595  *  This function never fails.
  596  *
  597  *  \param d Dither object.
  598  *  \return A static string.
  599  */
  600 char const * caca_get_dither_antialias(caca_dither_t const *d)
  601 {
  602     return d->antialias_name;
  603 }
  604 
  605 /** \brief Choose colours used for dithering
  606  *
  607  *  Tell the renderer which colours should be used to render the
  608  *  bitmap. Valid values for \c str are:
  609  *  - \c "mono": use light gray on a black background.
  610  *  - \c "gray": use white and two shades of gray on a black background.
  611  *  - \c "8": use the 8 ANSI colours on a black background.
  612  *  - \c "16": use the 16 ANSI colours on a black background.
  613  *  - \c "fullgray": use black, white and two shades of gray for both the
  614  *    characters and the background.
  615  *  - \c "full8": use the 8 ANSI colours for both the characters and the
  616  *    background.
  617  *  - \c "full16" or \c "default": use the 16 ANSI colours for both the
  618  *    characters and the background. This is the default value.
  619  *
  620  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  621  *  - \c EINVAL Invalid colour set.
  622  *
  623  *  \param d Dither object.
  624  *  \param str A string describing the colour set that will be used
  625  *         for the dithering.
  626  *  \return 0 in case of success, -1 if an error occurred.
  627  */
  628 int caca_set_dither_color(caca_dither_t *d, char const *str)
  629 {
  630     if(!strcasecmp(str, "mono"))
  631     {
  632         d->color_name = "mono";
  633         d->color = COLOR_MODE_MONO;
  634     }
  635     else if(!strcasecmp(str, "gray"))
  636     {
  637         d->color_name = "gray";
  638         d->color = COLOR_MODE_GRAY;
  639     }
  640     else if(!strcasecmp(str, "8"))
  641     {
  642         d->color_name = "8";
  643         d->color = COLOR_MODE_8;
  644     }
  645     else if(!strcasecmp(str, "16"))
  646     {
  647         d->color_name = "16";
  648         d->color = COLOR_MODE_16;
  649     }
  650     else if(!strcasecmp(str, "fullgray"))
  651     {
  652         d->color_name = "fullgray";
  653         d->color = COLOR_MODE_FULLGRAY;
  654     }
  655     else if(!strcasecmp(str, "full8"))
  656     {
  657         d->color_name = "full8";
  658         d->color = COLOR_MODE_FULL8;
  659     }
  660     else if(!strcasecmp(str, "full16") || !strcasecmp(str, "default"))
  661     {
  662         d->color_name = "full16";
  663         d->color = COLOR_MODE_FULL16;
  664     }
  665     else
  666     {
  667         seterrno(EINVAL);
  668         return -1;
  669     }
  670 
  671     return 0;
  672 }
  673 
  674 /** \brief Get available colour modes
  675  *
  676  *  Return a list of available colour modes for a given dither. The list
  677  *  is a NULL-terminated array of strings, interleaving a string containing
  678  *  the internal value for the colour mode, to be used with
  679  *  caca_set_dither_color(), and a string containing the natural
  680  *  language description for that colour mode.
  681  *
  682  *  This function never fails.
  683  *
  684  *  \param d Dither object.
  685  *  \return An array of strings.
  686  */
  687 char const * const *
  688     caca_get_dither_color_list(caca_dither_t const *d)
  689 {
  690     static char const * const list[] =
  691     {
  692         "mono", "white on black",
  693         "gray", "grayscale on black",
  694         "8", "8 colours on black",
  695         "16", "16 colours on black",
  696         "fullgray", "full grayscale",
  697         "full8", "full 8 colours",
  698         "full16", "full 16 colours",
  699         NULL, NULL
  700     };
  701 
  702     return list;
  703 }
  704 
  705 /** \brief Get current colour mode
  706  *
  707  *  Return the given dither's current colour mode.
  708  *
  709  *  This function never fails.
  710  *
  711  *  \param d Dither object.
  712  *  \return A static string.
  713  */
  714 char const * caca_get_dither_color(caca_dither_t const *d)
  715 {
  716     return d->color_name;
  717 }
  718 
  719 /** \brief Choose characters used for dithering
  720  *
  721  *  Tell the renderer which characters should be used to render the
  722  *  dither. Valid values for \c str are:
  723  *  - \c "ascii" or \c "default": use only ASCII characters. This is the
  724  *    default value.
  725  *  - \c "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592
  726  *    MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also
  727  *    present in the CP437 codepage available on DOS and VGA.
  728  *  - \c "blocks": use Unicode quarter-cell block combinations. These
  729  *    characters are only found in the Unicode set.
  730  *
  731  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  732  *  - \c EINVAL Invalid character set.
  733  *
  734  *  \param d Dither object.
  735  *  \param str A string describing the characters that need to be used
  736  *         for the dithering.
  737  *  \return 0 in case of success, -1 if an error occurred.
  738  */
  739 int caca_set_dither_charset(caca_dither_t *d, char const *str)
  740 {
  741     if(!strcasecmp(str, "shades"))
  742     {
  743         d->glyph_name = "shades";
  744         d->glyphs = shades_glyphs;
  745         d->glyph_count = sizeof(shades_glyphs) / sizeof(*shades_glyphs);
  746     }
  747     else if(!strcasecmp(str, "blocks"))
  748     {
  749         d->glyph_name = "blocks";
  750         d->glyphs = blocks_glyphs;
  751         d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
  752     }
  753     else if(!strcasecmp(str, "ascii") || !strcasecmp(str, "default"))
  754     {
  755         d->glyph_name = "ascii";
  756         d->glyphs = ascii_glyphs;
  757         d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
  758     }
  759     else
  760     {
  761         seterrno(EINVAL);
  762         return -1;
  763     }
  764 
  765     return 0;
  766 }
  767 
  768 /** \brief Get available dither character sets
  769  *
  770  *  Return a list of available character sets for a given dither. The list
  771  *  is a NULL-terminated array of strings, interleaving a string containing
  772  *  the internal value for the character set, to be used with
  773  *  caca_set_dither_charset(), and a string containing the natural
  774  *  language description for that character set.
  775  *
  776  *  This function never fails.
  777  *
  778  *  \param d Dither object.
  779  *  \return An array of strings.
  780  */
  781 char const * const * caca_get_dither_charset_list(caca_dither_t const *d)
  782 {
  783     static char const * const list[] =
  784     {
  785         "ascii", "plain ASCII",
  786         "shades", "CP437 shades",
  787         "blocks", "Unicode blocks",
  788         NULL, NULL
  789     };
  790 
  791     return list;
  792 }
  793 
  794 /** \brief Get current character set
  795  *
  796  *  Return the given dither's current character set.
  797  *
  798  *  This function never fails.
  799  *
  800  *  \param d Dither object.
  801  *  \return A static string.
  802  */
  803 char const * caca_get_dither_charset(caca_dither_t const *d)
  804 {
  805     return d->glyph_name;
  806 }
  807 
  808 /** \brief Set dithering algorithm
  809  *
  810  *  Tell the renderer which dithering algorithm should be used. Dithering is
  811  *  necessary because the picture being rendered has usually far more colours
  812  *  than the available palette. Valid values for \c str are:
  813  *  - \c "none": no dithering is used, the nearest matching colour is used.
  814  *  - \c "ordered2": use a 2x2 Bayer matrix for dithering.
  815  *  - \c "ordered4": use a 4x4 Bayer matrix for dithering.
  816  *  - \c "ordered8": use a 8x8 Bayer matrix for dithering.
  817  *  - \c "random": use random dithering.
  818  *  - \c "fstein": use Floyd-Steinberg dithering. This is the default value.
  819  *
  820  *  If an error occurs, -1 is returned and \b errno is set accordingly:
  821  *  - \c EINVAL Unknown dithering mode.
  822  *
  823  *  \param d Dither object.
  824  *  \param str A string describing the algorithm that needs to be used
  825  *         for the dithering.
  826  *  \return 0 in case of success, -1 if an error occurred.
  827  */
  828 int caca_set_dither_algorithm(caca_dither_t *d, char const *str)
  829 {
  830     if(!strcasecmp(str, "none"))
  831     {
  832         d->algo_name = "none";
  833         d->init_dither = init_no_dither;
  834         d->get_dither = get_no_dither;
  835         d->increment_dither = increment_no_dither;
  836     }
  837     else if(!strcasecmp(str, "ordered2"))
  838     {
  839         d->algo_name = "ordered2";
  840         d->init_dither = init_ordered2_dither;
  841         d->get_dither = get_ordered2_dither;
  842         d->increment_dither = increment_ordered2_dither;
  843     }
  844     else if(!strcasecmp(str, "ordered4"))
  845     {
  846         d->algo_name = "ordered4";
  847         d->init_dither = init_ordered4_dither;
  848         d->get_dither = get_ordered4_dither;
  849         d->increment_dither = increment_ordered4_dither;
  850     }
  851     else if(!strcasecmp(str, "ordered8"))
  852     {
  853         d->algo_name = "ordered8";
  854         d->init_dither = init_ordered8_dither;
  855         d->get_dither = get_ordered8_dither;
  856         d->increment_dither = increment_ordered8_dither;
  857     }
  858     else if(!strcasecmp(str, "random"))
  859     {
  860         d->algo_name = "random";
  861         d->init_dither = init_random_dither;
  862         d->get_dither = get_random_dither;
  863         d->increment_dither = increment_random_dither;
  864     }
  865     else if(!strcasecmp(str, "fstein") || !strcasecmp(str, "default"))
  866     {
  867         d->algo_name = "fstein";
  868         d->init_dither = init_fstein_dither;
  869         d->get_dither = get_fstein_dither;
  870         d->increment_dither = increment_fstein_dither;
  871     }
  872     else
  873     {
  874         seterrno(EINVAL);
  875         return -1;
  876     }
  877 
  878     return 0;
  879 }
  880 
  881 /** \brief Get dithering algorithms
  882  *
  883  *  Return a list of available dithering algorithms for a given dither. The
  884  *  list is a NULL-terminated array of strings, interleaving a string
  885  *  containing the internal value for the dithering algorithm, to be used
  886  *  with caca_set_dither_dithering(), and a string containing the natural
  887  *  language description for that algorithm.
  888  *
  889  *  This function never fails.
  890  *
  891  *  \param d Dither object.
  892  *  \return An array of strings.
  893  */
  894 char const * const * caca_get_dither_algorithm_list(caca_dither_t const *d)
  895 {
  896     static char const * const list[] =
  897     {
  898         "none", "no dithering",
  899         "ordered2", "2x2 ordered dithering",
  900         "ordered4", "4x4 ordered dithering",
  901         "ordered8", "8x8 ordered dithering",
  902         "random", "random dithering",
  903         "fstein", "Floyd-Steinberg dithering",
  904         NULL, NULL
  905     };
  906 
  907     return list;
  908 }
  909 
  910 /** \brief Get current dithering algorithm
  911  *
  912  *  Return the given dither's current dithering algorithm.
  913  *
  914  *  This function never fails.
  915  *
  916  *  \param d Dither object.
  917  *  \return A static string.
  918  */
  919 char const * caca_get_dither_algorithm(caca_dither_t const *d)
  920 {
  921     return d->algo_name;
  922 }
  923 
  924 /** \brief Dither a bitmap on the canvas.
  925  *
  926  *  Dither a bitmap at the given coordinates. The dither can be of any size
  927  *  and will be stretched to the text area.
  928  *
  929  *  This function never fails.
  930  *
  931  *  \param cv A handle to the libcaca canvas.
  932  *  \param x X coordinate of the upper-left corner of the drawing area.
  933  *  \param y Y coordinate of the upper-left corner of the drawing area.
  934  *  \param w Width of the drawing area.
  935  *  \param h Height of the drawing area.
  936  *  \param d Dither object to be drawn.
  937  *  \param pixels Bitmap's pixels.
  938  *  \return This function always returns 0.
  939  */
  940 int caca_dither_bitmap(caca_canvas_t *cv, int x, int y, int w, int h,
  941                         caca_dither_t const *d, void const *pixels)
  942 {
  943     int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
  944     uint32_t savedattr;
  945     int fs_length;
  946     int x1, y1, x2, y2, pitch, deltax, deltay, dchmax;
  947 
  948     if(!d || !pixels)
  949         return 0;
  950 
  951     savedattr = caca_get_attr(cv, -1, -1);
  952 
  953     x1 = x; x2 = x + w - 1;
  954     y1 = y; y2 = y + h - 1;
  955 
  956     /* FIXME: do not overwrite arguments */
  957     w = d->w;
  958     h = d->h;
  959     pitch = d->pitch;
  960 
  961     deltax = x2 - x1 + 1;
  962     deltay = y2 - y1 + 1;
  963     dchmax = d->glyph_count;
  964 
  965     fs_length = ((int)cv->width <= x2 ? (int)cv->width : x2) + 1;
  966     floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
  967     memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
  968     fs_r = floyd_steinberg + 1;
  969     fs_g = fs_r + fs_length + 2;
  970     fs_b = fs_g + fs_length + 2;
  971 
  972     for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)cv->height; y++)
  973     {
  974         int remain_r = 0, remain_g = 0, remain_b = 0;
  975 
  976         for(x = x1 > 0 ? x1 : 0, d->init_dither(y);
  977             x <= x2 && x <= (int)cv->width;
  978             x++)
  979     {
  980         unsigned int rgba[4];
  981         int error[3];
  982         int i, ch = 0, distmin;
  983         int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
  984         int fromx, fromy, tox, toy, myx, myy, dots, dist;
  985 
  986         int outfg = 0, outbg = 0;
  987         uint32_t outch;
  988 
  989         rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
  990 
  991         /* First get RGB */
  992         if(d->antialias)
  993         {
  994             fromx = (uint64_t)(x - x1) * w / deltax;
  995             fromy = (uint64_t)(y - y1) * h / deltay;
  996             tox = (uint64_t)(x - x1 + 1) * w / deltax;
  997             toy = (uint64_t)(y - y1 + 1) * h / deltay;
  998 
  999             /* We want at least one pixel */
 1000             if(tox == fromx) tox++;
 1001             if(toy == fromy) toy++;
 1002 
 1003             dots = 0;
 1004 
 1005             for(myx = fromx; myx < tox; myx++)
 1006                 for(myy = fromy; myy < toy; myy++)
 1007             {
 1008                 dots++;
 1009                 get_rgba_default(d, pixels, myx, myy, rgba);
 1010             }
 1011 
 1012             /* Normalize */
 1013             rgba[0] /= dots;
 1014             rgba[1] /= dots;
 1015             rgba[2] /= dots;
 1016             rgba[3] /= dots;
 1017         }
 1018         else
 1019         {
 1020             fromx = (uint64_t)(x - x1) * w / deltax;
 1021             fromy = (uint64_t)(y - y1) * h / deltay;
 1022             tox = (uint64_t)(x - x1 + 1) * w / deltax;
 1023             toy = (uint64_t)(y - y1 + 1) * h / deltay;
 1024 
 1025             /* tox and toy can overflow the canvas, but they cannot overflow
 1026              * when averaged with fromx and fromy because these are guaranteed
 1027              * to be within the pixel boundaries. */
 1028             myx = (fromx + tox) / 2;
 1029             myy = (fromy + toy) / 2;
 1030 
 1031             get_rgba_default(d, pixels, myx, myy, rgba);
 1032         }
 1033 
 1034         /* FIXME: hack to force greyscale */
 1035         if(d->color == COLOR_MODE_FULLGRAY)
 1036         {
 1037             unsigned int gray = (3 * rgba[0] + 4 * rgba[1] + rgba[2] + 4) / 8;
 1038             rgba[0] = rgba[1] = rgba[2] = gray;
 1039         }
 1040 
 1041         if(d->has_alpha && rgba[3] < 0x800)
 1042         {
 1043             remain_r = remain_g = remain_b = 0;
 1044             fs_r[x] = 0;
 1045             fs_g[x] = 0;
 1046             fs_b[x] = 0;
 1047             continue;
 1048         }
 1049 
 1050         /* XXX: OMG HAX */
 1051         if(d->init_dither == init_fstein_dither)
 1052         {
 1053             rgba[0] += remain_r;
 1054             rgba[1] += remain_g;
 1055             rgba[2] += remain_b;
 1056         }
 1057         else
 1058         {
 1059             rgba[0] += (d->get_dither() - 0x80) * 4;
 1060             rgba[1] += (d->get_dither() - 0x80) * 4;
 1061             rgba[2] += (d->get_dither() - 0x80) * 4;
 1062         }
 1063 
 1064         distmin = INT_MAX;
 1065         for(i = 0; i < 16; i++)
 1066         {
 1067             if(d->color == COLOR_MODE_FULLGRAY
 1068                 && (rgb_palette[i * 3] != rgb_palette[i * 3 + 1]
 1069                      || rgb_palette[i * 3] != rgb_palette[i * 3 + 2]))
 1070                 continue;
 1071             dist = sq(rgba[0] - rgb_palette[i * 3])
 1072                  + sq(rgba[1] - rgb_palette[i * 3 + 1])
 1073                  + sq(rgba[2] - rgb_palette[i * 3 + 2]);
 1074             dist *= rgb_weight[i];
 1075             if(dist < distmin)
 1076             {
 1077                 outbg = i;
 1078                 distmin = dist;
 1079             }
 1080         }
 1081         bg_r = rgb_palette[outbg * 3];
 1082         bg_g = rgb_palette[outbg * 3 + 1];
 1083         bg_b = rgb_palette[outbg * 3 + 2];
 1084 
 1085         /* FIXME: we currently only honour "full16" */
 1086         if(d->color == COLOR_MODE_FULL16 || d->color == COLOR_MODE_FULLGRAY)
 1087         {
 1088             distmin = INT_MAX;
 1089             for(i = 0; i < 16; i++)
 1090             {
 1091                 if(i == outbg)
 1092                     continue;
 1093                 if(d->color == COLOR_MODE_FULLGRAY
 1094                     && (rgb_palette[i * 3] != rgb_palette[i * 3 + 1]
 1095                          || rgb_palette[i * 3] != rgb_palette[i * 3 + 2]))
 1096                     continue;
 1097                 dist = sq(rgba[0] - rgb_palette[i * 3])
 1098                      + sq(rgba[1] - rgb_palette[i * 3 + 1])
 1099                      + sq(rgba[2] - rgb_palette[i * 3 + 2]);
 1100                 dist *= rgb_weight[i];
 1101                 if(dist < distmin)
 1102                 {
 1103                     outfg = i;
 1104                     distmin = dist;
 1105                 }
 1106             }
 1107             fg_r = rgb_palette[outfg * 3];
 1108             fg_g = rgb_palette[outfg * 3 + 1];
 1109             fg_b = rgb_palette[outfg * 3 + 2];
 1110 
 1111             distmin = INT_MAX;
 1112             for(i = 0; i < dchmax - 1; i++)
 1113             {
 1114                 int newr = i * fg_r + ((2*dchmax-1) - i) * bg_r;
 1115                 int newg = i * fg_g + ((2*dchmax-1) - i) * bg_g;
 1116                 int newb = i * fg_b + ((2*dchmax-1) - i) * bg_b;
 1117                 dist = abs(rgba[0] * (2*dchmax-1) - newr)
 1118                      + abs(rgba[1] * (2*dchmax-1) - newg)
 1119                      + abs(rgba[2] * (2*dchmax-1) - newb);
 1120 
 1121                 if(dist < distmin)
 1122                 {
 1123                     ch = i;
 1124                     distmin = dist;
 1125                 }
 1126             }
 1127             outch = d->glyphs[ch];
 1128 
 1129             /* XXX: OMG HAX */
 1130             if(d->init_dither == init_fstein_dither)
 1131             {
 1132                 error[0] = rgba[0] - (fg_r * ch + bg_r * ((2*dchmax-1) - ch)) / (2*dchmax-1);
 1133                 error[1] = rgba[1] - (fg_g * ch + bg_g * ((2*dchmax-1) - ch)) / (2*dchmax-1);
 1134                 error[2] = rgba[2] - (fg_b * ch + bg_b * ((2*dchmax-1) - ch)) / (2*dchmax-1);
 1135             }
 1136         }
 1137         else
 1138         {
 1139             unsigned int lum = rgba[0];
 1140             if(rgba[1] > lum) lum = rgba[1];
 1141             if(rgba[2] > lum) lum = rgba[2];
 1142             outfg = outbg;
 1143             outbg = CACA_BLACK;
 1144 
 1145             ch = lum * dchmax / 0x1000;
 1146             if(ch < 0)
 1147                 ch = 0;
 1148             else if(ch > (int)(dchmax - 1))
 1149                 ch = dchmax - 1;
 1150             outch = d->glyphs[ch];
 1151 
 1152             /* XXX: OMG HAX */
 1153             if(d->init_dither == init_fstein_dither)
 1154             {
 1155                 error[0] = rgba[0] - bg_r * ch / (dchmax-1);
 1156                 error[1] = rgba[1] - bg_g * ch / (dchmax-1);
 1157                 error[2] = rgba[2] - bg_b * ch / (dchmax-1);
 1158             }
 1159         }
 1160 
 1161         /* XXX: OMG HAX */
 1162         if(d->init_dither == init_fstein_dither)
 1163         {
 1164             remain_r = fs_r[x+1] + 7 * error[0] / 16;
 1165             remain_g = fs_g[x+1] + 7 * error[1] / 16;
 1166             remain_b = fs_b[x+1] + 7 * error[2] / 16;
 1167             fs_r[x-1] += 3 * error[0] / 16;
 1168             fs_g[x-1] += 3 * error[1] / 16;
 1169             fs_b[x-1] += 3 * error[2] / 16;
 1170             fs_r[x] = 5 * error[0] / 16;
 1171             fs_g[x] = 5 * error[1] / 16;
 1172             fs_b[x] = 5 * error[2] / 16;
 1173             fs_r[x+1] = 1 * error[0] / 16;
 1174             fs_g[x+1] = 1 * error[1] / 16;
 1175             fs_b[x+1] = 1 * error[2] / 16;
 1176         }
 1177 
 1178         if(d->invert)
 1179         {
 1180             outfg = 15 - outfg;
 1181             outbg = 15 - outbg;
 1182         }
 1183 
 1184         /* Now output the character */
 1185         caca_set_color_ansi(cv, outfg, outbg);
 1186         caca_put_char(cv, x, y, outch);
 1187 
 1188         d->increment_dither();
 1189     }
 1190         /* end loop */
 1191     }
 1192 
 1193     free(floyd_steinberg);
 1194 
 1195     caca_set_attr(cv, savedattr);
 1196 
 1197     return 0;
 1198 }
 1199 
 1200 /** \brief Free the memory associated with a dither.
 1201  *
 1202  *  Free the memory allocated by caca_create_dither().
 1203  *
 1204  *  This function never fails.
 1205  *
 1206  *  \param d Dither object.
 1207  *  \return This function always returns 0.
 1208  */
 1209 int caca_free_dither(caca_dither_t *d)
 1210 {
 1211     if(!d)
 1212         return 0;
 1213 
 1214     free(d);
 1215 
 1216     return 0;
 1217 }
 1218 
 1219 /*
 1220  * XXX: The following functions are local.
 1221  */
 1222 
 1223 /* Convert a mask, eg. 0x0000ff00, to shift values, eg. 8 and -4. */
 1224 static void mask2shift(uint32_t mask, int *right, int *left)
 1225 {
 1226     int rshift = 0, lshift = 0;
 1227 
 1228     if(!mask)
 1229     {
 1230         *right = *left = 0;
 1231         return;
 1232     }
 1233 
 1234     while(!(mask & 1))
 1235     {
 1236         mask >>= 1;
 1237         rshift++;
 1238     }
 1239     *right = rshift;
 1240 
 1241     while(mask & 1)
 1242     {
 1243         mask >>= 1;
 1244         lshift++;
 1245     }
 1246     *left = 12 - lshift;
 1247 }
 1248 
 1249 /* Compute x^y without relying on the math library */
 1250 static float gammapow(float x, float y)
 1251 {
 1252 #ifdef HAVE_FLDLN2
 1253     register double logx;
 1254     register long double v, e;
 1255 #else
 1256     register float tmp, t, t2, r;
 1257     int i;
 1258 #endif
 1259 
 1260     if(x == 0.0)
 1261         return y == 0.0 ? 1.0 : 0.0;
 1262 
 1263 #ifdef HAVE_FLDLN2
 1264     /* FIXME: this can be optimised by directly calling fyl2x for x and y */
 1265     asm volatile("fldln2; fxch; fyl2x"
 1266                  : "=t" (logx) : "0" (x) : "st(1)");
 1267 
 1268     asm volatile("fldl2e\n\t"
 1269                  "fmul %%st(1)\n\t"
 1270                  "fst %%st(1)\n\t"
 1271                  "frndint\n\t"
 1272                  "fxch\n\t"
 1273                  "fsub %%st(1)\n\t"
 1274                  "f2xm1\n\t"
 1275                  : "=t" (v), "=u" (e) : "0" (y * logx));
 1276     v += 1.0;
 1277     asm volatile("fscale"
 1278                  : "=t" (v) : "0" (v), "u" (e));
 1279     return v;
 1280 #else
 1281     /* Compute ln(x) for x ∈ ]0,1]
 1282      *   ln(x) = 2 * (t + t^3/3 + t^5/5 + ...) with t = (x-1)/(x+1)
 1283      * The convergence is a bit slow, especially when x is near 0. */
 1284     t = (x - 1.0) / (x + 1.0);
 1285     t2 = t * t;
 1286     tmp = r = t;
 1287     for(i = 3; i < 20; i += 2)
 1288     {
 1289         r *= t2;
 1290         tmp += r / i;
 1291     }
 1292 
 1293     /* Compute -y*ln(x) */
 1294     tmp = - y * 2.0 * tmp;
 1295 
 1296     /* Compute x^-y as e^t where t = -y*ln(x):
 1297      *   e^t = 1 + t/1! + t^2/2! + t^3/3! + t^4/4! + t^5/5! ...
 1298      * The convergence is quite faster here, thanks to the factorial. */
 1299     r = t = tmp;
 1300     tmp = 1.0 + t;
 1301     for(i = 2; i < 16; i++)
 1302     {
 1303         r = r * t / i;
 1304         tmp += r;
 1305     }
 1306 
 1307     /* Return x^y as 1/(x^-y) */
 1308     return 1.0 / tmp;
 1309 #endif
 1310 }
 1311 
 1312 static void get_rgba_default(caca_dither_t const *d, uint8_t const *pixels,
 1313                              int x, int y, unsigned int *rgba)
 1314 {
 1315     uint32_t bits;
 1316 
 1317     pixels += (d->bpp / 8) * x + d->pitch * y;
 1318 
 1319     switch(d->bpp / 8)
 1320     {
 1321         case 4:
 1322             bits = *(uint32_t const *)pixels;
 1323             break;
 1324         case 3:
 1325         {
 1326 #if defined(HAVE_ENDIAN_H)
 1327             if(__BYTE_ORDER == __BIG_ENDIAN)
 1328 #else
 1329             /* This is compile-time optimised with at least -O1 or -Os */
 1330             uint32_t const tmp = 0x12345678;
 1331             if(*(uint8_t const *)&tmp == 0x12)
 1332 #endif
 1333                 bits = ((uint32_t)pixels[0] << 16) |
 1334                        ((uint32_t)pixels[1] << 8) |
 1335                        ((uint32_t)pixels[2]);
 1336             else
 1337                 bits = ((uint32_t)pixels[2] << 16) |
 1338                        ((uint32_t)pixels[1] << 8) |
 1339                        ((uint32_t)pixels[0]);
 1340             break;
 1341         }
 1342         case 2:
 1343             bits = *(uint16_t const *)pixels;
 1344             break;
 1345         case 1:
 1346         default:
 1347             bits = pixels[0];
 1348             break;
 1349     }
 1350 
 1351     if(d->has_palette)
 1352     {
 1353         rgba[0] += d->gammatab[d->red[bits]];
 1354         rgba[1] += d->gammatab[d->green[bits]];
 1355         rgba[2] += d->gammatab[d->blue[bits]];
 1356         rgba[3] += d->alpha[bits];
 1357     }
 1358     else
 1359     {
 1360         rgba[0] += d->gammatab[((bits & d->rmask) >> d->rright) << d->rleft];
 1361         rgba[1] += d->gammatab[((bits & d->gmask) >> d->gright) << d->gleft];
 1362         rgba[2] += d->gammatab[((bits & d->bmask) >> d->bright) << d->bleft];
 1363         rgba[3] += ((bits & d->amask) >> d->aright) << d->aleft;
 1364     }
 1365 }
 1366 
 1367 /*
 1368  * No dithering
 1369  */
 1370 static void init_no_dither(int line)
 1371 {
 1372     ;
 1373 }
 1374 
 1375 static int get_no_dither(void)
 1376 {
 1377     return 0x80;
 1378 }
 1379 
 1380 static void increment_no_dither(void)
 1381 {
 1382     return;
 1383 }
 1384 
 1385 /*
 1386  * Floyd-Steinberg dithering
 1387  */
 1388 static void init_fstein_dither(int line)
 1389 {
 1390     ;
 1391 }
 1392 
 1393 static int get_fstein_dither(void)
 1394 {
 1395     return 0x80;
 1396 }
 1397 
 1398 static void increment_fstein_dither(void)
 1399 {
 1400     return;
 1401 }
 1402 
 1403 /*
 1404  * Ordered 2 dithering
 1405  */
 1406 static int const *ordered2_table;
 1407 static int ordered2_index;
 1408 
 1409 static void init_ordered2_dither(int line)
 1410 {
 1411     static int const dither2x2[] =
 1412     {
 1413         0x00, 0x80,
 1414         0xc0, 0x40,
 1415     };
 1416 
 1417     ordered2_table = dither2x2 + (line % 2) * 2;
 1418     ordered2_index = 0;
 1419 }
 1420 
 1421 static int get_ordered2_dither(void)
 1422 {
 1423     return ordered2_table[ordered2_index];
 1424 }
 1425 
 1426 static void increment_ordered2_dither(void)
 1427 {
 1428     ordered2_index = (ordered2_index + 1) % 2;
 1429 }
 1430 
 1431 /*
 1432  * Ordered 4 dithering
 1433  */
 1434 /*static int dither4x4[] = { 5,  0,  1,  6,
 1435                           -1, -6, -5,  2,
 1436                           -2, -7, -8,  3,
 1437                            4, -3, -4, -7};*/
 1438 static int const *ordered4_table;
 1439 static int ordered4_index;
 1440 
 1441 static void init_ordered4_dither(int line)
 1442 {
 1443     static int const dither4x4[] =
 1444     {
 1445         0x00, 0x80, 0x20, 0xa0,
 1446         0xc0, 0x40, 0xe0, 0x60,
 1447         0x30, 0xb0, 0x10, 0x90,
 1448         0xf0, 0x70, 0xd0, 0x50
 1449     };
 1450 
 1451     ordered4_table = dither4x4 + (line % 4) * 4;
 1452     ordered4_index = 0;
 1453 }
 1454 
 1455 static int get_ordered4_dither(void)
 1456 {
 1457     return ordered4_table[ordered4_index];
 1458 }
 1459 
 1460 static void increment_ordered4_dither(void)
 1461 {
 1462     ordered4_index = (ordered4_index + 1) % 4;
 1463 }
 1464 
 1465 /*
 1466  * Ordered 8 dithering
 1467  */
 1468 static int const *ordered8_table;
 1469 static int ordered8_index;
 1470 
 1471 static void init_ordered8_dither(int line)
 1472 {
 1473     static int const dither8x8[] =
 1474     {
 1475         0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
 1476         0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
 1477         0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
 1478         0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
 1479         0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
 1480         0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
 1481         0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
 1482         0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
 1483     };
 1484 
 1485     ordered8_table = dither8x8 + (line % 8) * 8;
 1486     ordered8_index = 0;
 1487 }
 1488 
 1489 static int get_ordered8_dither(void)
 1490 {
 1491     return ordered8_table[ordered8_index];
 1492 }
 1493 
 1494 static void increment_ordered8_dither(void)
 1495 {
 1496     ordered8_index = (ordered8_index + 1) % 8;
 1497 }
 1498 
 1499 /*
 1500  * Random dithering
 1501  */
 1502 static void init_random_dither(int line)
 1503 {
 1504     ;
 1505 }
 1506 
 1507 static int get_random_dither(void)
 1508 {
 1509     return caca_rand(0x00, 0x100);
 1510 }
 1511 
 1512 static void increment_random_dither(void)
 1513 {
 1514     return;
 1515 }
 1516 
 1517 /*
 1518  * Lookup tables
 1519  */
 1520 static int init_lookup(void)
 1521 {
 1522     int v, s, h;
 1523 
 1524     /* These ones are constant */
 1525     lookup_colors[0] = CACA_BLACK;
 1526     lookup_colors[1] = CACA_DARKGRAY;
 1527     lookup_colors[2] = CACA_LIGHTGRAY;
 1528     lookup_colors[3] = CACA_WHITE;
 1529 
 1530     /* These ones will be overwritten */
 1531     lookup_colors[4] = CACA_MAGENTA;
 1532     lookup_colors[5] = CACA_LIGHTMAGENTA;
 1533     lookup_colors[6] = CACA_RED;
 1534     lookup_colors[7] = CACA_LIGHTRED;
 1535 
 1536     for(v = 0; v < LOOKUP_VAL; v++)
 1537         for(s = 0; s < LOOKUP_SAT; s++)
 1538             for(h = 0; h < LOOKUP_HUE; h++)
 1539     {
 1540         int i, distbg, distfg, dist;
 1541         int val, sat, hue;
 1542         uint8_t outbg, outfg;
 1543 
 1544         val = 0xfff * v / (LOOKUP_VAL - 1);
 1545         sat = 0xfff * s / (LOOKUP_SAT - 1);
 1546         hue = 0xfff * h / (LOOKUP_HUE - 1);
 1547 
 1548         /* Initialise distances to the distance between pure black HSV
 1549          * coordinates and our white colour (3) */
 1550         outbg = outfg = 3;
 1551         distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
 1552 
 1553         /* Calculate distances to eight major colour values and store the
 1554          * two nearest points in our lookup table. */
 1555         for(i = 0; i < 8; i++)
 1556         {
 1557             dist = HSV_DISTANCE(hue, sat, val, i);
 1558             if(dist <= distbg)
 1559             {
 1560                 outfg = outbg;
 1561                 distfg = distbg;
 1562                 outbg = i;
 1563                 distbg = dist;
 1564             }
 1565             else if(dist <= distfg)
 1566             {
 1567                 outfg = i;
 1568                 distfg = dist;
 1569             }
 1570         }
 1571 
 1572         hsv_distances[v][s][h] = (outfg << 4) | outbg;
 1573     }
 1574 
 1575     return 0;
 1576 }
 1577