source: libcaca/trunk/caca/dither.c @ 4333

Last change on this file since 4333 was 4333, checked in by Sam Hocevar, 10 years ago

Large source code cleanup, getting rid of spaces, tabs, and svn keywords.

  • Property svn:keywords set to Id
File size: 43.7 KB
Line 
1/*
2 *  libcaca       Colour ASCII-Art library
3 *  Copyright (c) 2002-2006 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 Sam Hocevar. See
10 *  http://sam.zoy.org/wtfpl/COPYING 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
42static uint8_t hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
43static uint16_t lookup_colors[8];
44static int lookup_initialised = 0;
45
46static 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 */
60static 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
80static 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 */
87static uint32_t ascii_glyphs[] =
88{
89    ' ', '.', ':', ';', 't', '%', 'S', 'X', '@', '8', '?'
90};
91
92static uint32_t shades_glyphs[] =
93{
94    /* ' '. '·', '░', '▒', '?' */
95    ' ', 0xb7, 0x2591, 0x2592, '?'
96};
97
98static uint32_t blocks_glyphs[] =
99{
100    /* ' ', '▘', '▚', '?' */
101    ' ', 0x2598, 0x259a, '?'
102};
103
104#if !defined(_DOXYGEN_SKIP_ME)
105enum 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
116struct caca_dither
117{
118    int bpp, has_palette, has_alpha;
119    int 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 */
170static void mask2shift(uint32_t, int *, int *);
171static float gammapow(float x, float y);
172
173static void get_rgba_default(caca_dither_t const *, uint8_t const *, int, int,
174                             unsigned int *);
175static int init_lookup(void);
176
177/* Dithering algorithms */
178static void init_no_dither(int);
179static int get_no_dither(void);
180static void increment_no_dither(void);
181
182static void init_fstein_dither(int);
183static int get_fstein_dither(void);
184static void increment_fstein_dither(void);
185
186static void init_ordered2_dither(int);
187static int get_ordered2_dither(void);
188static void increment_ordered2_dither(void);
189
190static void init_ordered4_dither(int);
191static int get_ordered4_dither(void);
192static void increment_ordered4_dither(void);
193
194static void init_ordered8_dither(int);
195static int get_ordered8_dither(void);
196static void increment_ordered8_dither(void);
197
198static void init_random_dither(int);
199static int get_random_dither(void);
200static void increment_random_dither(void);
201
202static inline int sq(int x)
203{
204    return x * x;
205}
206
207static 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 */
261caca_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 */
372int 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 */
421int 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 */
438float 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 */
455int 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 */
490float 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 */
506int 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 */
523float 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 */
544int 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 */
578char 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 */
600char 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 */
628int 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 */
687char 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 */
714char 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 */
739int 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 */
781char 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 */
803char 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 */
828int 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 */
894char 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 */
919char 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 */
940int 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 = (x - x1) * w / deltax;
995            fromy = (y - y1) * h / deltay;
996            tox = (x - x1 + 1) * w / deltax;
997            toy = (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 = (x - x1) * w / deltax;
1021            fromy = (y - y1) * h / deltay;
1022            tox = (x - x1 + 1) * w / deltax;
1023            toy = (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 */
1209int 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. */
1224static 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 */
1250static 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
1312static 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 */
1370static void init_no_dither(int line)
1371{
1372    ;
1373}
1374
1375static int get_no_dither(void)
1376{
1377    return 0x80;
1378}
1379
1380static void increment_no_dither(void)
1381{
1382    return;
1383}
1384
1385/*
1386 * Floyd-Steinberg dithering
1387 */
1388static void init_fstein_dither(int line)
1389{
1390    ;
1391}
1392
1393static int get_fstein_dither(void)
1394{
1395    return 0x80;
1396}
1397
1398static void increment_fstein_dither(void)
1399{
1400    return;
1401}
1402
1403/*
1404 * Ordered 2 dithering
1405 */
1406static int const *ordered2_table;
1407static int ordered2_index;
1408
1409static 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
1421static int get_ordered2_dither(void)
1422{
1423    return ordered2_table[ordered2_index];
1424}
1425
1426static 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};*/
1438static int const *ordered4_table;
1439static int ordered4_index;
1440
1441static 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
1455static int get_ordered4_dither(void)
1456{
1457    return ordered4_table[ordered4_index];
1458}
1459
1460static void increment_ordered4_dither(void)
1461{
1462    ordered4_index = (ordered4_index + 1) % 4;
1463}
1464
1465/*
1466 * Ordered 8 dithering
1467 */
1468static int const *ordered8_table;
1469static int ordered8_index;
1470
1471static 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
1489static int get_ordered8_dither(void)
1490{
1491    return ordered8_table[ordered8_index];
1492}
1493
1494static void increment_ordered8_dither(void)
1495{
1496    ordered8_index = (ordered8_index + 1) % 8;
1497}
1498
1499/*
1500 * Random dithering
1501 */
1502static void init_random_dither(int line)
1503{
1504    ;
1505}
1506
1507static int get_random_dither(void)
1508{
1509    return caca_rand(0x00, 0x100);
1510}
1511
1512static void increment_random_dither(void)
1513{
1514    return;
1515}
1516
1517/*
1518 * Lookup tables
1519 */
1520static 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
1578/*
1579 * XXX: The following functions are aliases.
1580 */
1581
1582cucul_dither_t *cucul_create_dither(int, int, int, int, uint32_t, uint32_t,
1583                                    uint32_t, uint32_t)
1584         CACA_ALIAS(caca_create_dither);
1585int cucul_set_dither_palette(cucul_dither_t *, uint32_t r[], uint32_t g[],
1586                             uint32_t b[], uint32_t a[])
1587         CACA_ALIAS(caca_set_dither_palette);
1588int cucul_set_dither_brightness(cucul_dither_t *, float)
1589         CACA_ALIAS(caca_set_dither_brightness);
1590float cucul_get_dither_brightness(cucul_dither_t const *)
1591         CACA_ALIAS(caca_get_dither_brightness);
1592int cucul_set_dither_gamma(cucul_dither_t *, float)
1593         CACA_ALIAS(caca_set_dither_gamma);
1594float cucul_get_dither_gamma(cucul_dither_t const *)
1595         CACA_ALIAS(caca_get_dither_gamma);
1596int cucul_set_dither_contrast(cucul_dither_t *, float)
1597         CACA_ALIAS(caca_set_dither_contrast);
1598float cucul_get_dither_contrast(cucul_dither_t const *)
1599         CACA_ALIAS(caca_get_dither_contrast);
1600int cucul_set_dither_antialias(cucul_dither_t *, char const *)
1601         CACA_ALIAS(caca_set_dither_antialias);
1602char const * const * cucul_get_dither_antialias_list(cucul_dither_t const *)
1603         CACA_ALIAS(caca_get_dither_antialias_list);
1604char const * cucul_get_dither_antialias(cucul_dither_t const *)
1605         CACA_ALIAS(caca_get_dither_antialias);
1606int cucul_set_dither_color(cucul_dither_t *, char const *)
1607         CACA_ALIAS(caca_set_dither_color);
1608char const * const * cucul_get_dither_color_list(cucul_dither_t const *)
1609         CACA_ALIAS(caca_get_dither_color_list);
1610char const * cucul_get_dither_color(cucul_dither_t const *)
1611         CACA_ALIAS(caca_get_dither_color);
1612int cucul_set_dither_charset(cucul_dither_t *, char const *)
1613         CACA_ALIAS(caca_set_dither_charset);
1614char const * const * cucul_get_dither_charset_list(cucul_dither_t const *)
1615         CACA_ALIAS(caca_get_dither_charset_list);
1616char const * cucul_get_dither_charset(cucul_dither_t const *)
1617         CACA_ALIAS(caca_get_dither_charset);
1618int cucul_set_dither_algorithm(cucul_dither_t *, char const *)
1619         CACA_ALIAS(caca_set_dither_algorithm);
1620char const * const * cucul_get_dither_algorithm_list(cucul_dither_t const *)
1621         CACA_ALIAS(caca_get_dither_algorithm_list);
1622char const * cucul_get_dither_algorithm(cucul_dither_t const *)
1623         CACA_ALIAS(caca_get_dither_algorithm);
1624int cucul_dither_bitmap(cucul_canvas_t *, int, int, int, int,
1625                        cucul_dither_t const *, void *)
1626         CACA_ALIAS(caca_dither_bitmap);
1627int cucul_free_dither(cucul_dither_t *) CACA_ALIAS(caca_free_dither);
1628
Note: See TracBrowser for help on using the repository browser.