source: libcaca/trunk/src/bitmap.c @ 521

Last change on this file since 521 was 513, checked in by Jean-Yves Lamoureux, 17 years ago
  • Fixed warnings under GCC 4.x
  • Property svn:keywords set to Id
File size: 25.2 KB
Line 
1/*
2 *  libcaca       ASCII-Art library
3 *  Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  This library is free software; you can redistribute it and/or
7 *  modify it under the terms of the GNU Lesser General Public
8 *  License as published by the Free Software Foundation; either
9 *  version 2 of the License, or (at your option) any later version.
10 *
11 *  This library is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *  Lesser General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Lesser General Public
17 *  License along with this library; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *  02111-1307  USA
20 */
21
22/** \file bitmap.c
23 *  \version \$Id: bitmap.c 513 2005-11-17 14:33:43Z jylam $
24 *  \author Sam Hocevar <sam@zoy.org>
25 *  \brief Bitmap blitting
26 *
27 *  This file contains bitmap blitting functions.
28 */
29
30#include "config.h"
31
32#if defined(HAVE_INTTYPES_H) || defined(_DOXYGEN_SKIP_ME)
33#   include <inttypes.h>
34#else
35typedef unsigned char uint8_t;
36typedef unsigned short uint16_t;
37typedef unsigned int uint32_t;
38#endif
39
40#if defined(HAVE_ENDIAN_H)
41#   include <endian.h>
42#endif
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <limits.h>
47#include <string.h>
48
49#include "caca.h"
50#include "caca_internals.h"
51
52/*
53 * Global variables
54 */
55#if !defined(_DOXYGEN_SKIP_ME)
56enum caca_feature _caca_background;
57enum caca_feature _caca_dithering;
58enum caca_feature _caca_antialiasing;
59#endif
60
61/*
62 * Local variables
63 */
64#if !defined(_DOXYGEN_SKIP_ME)
65#   define LOOKUP_VAL 32
66#   define LOOKUP_SAT 32
67#   define LOOKUP_HUE 16
68#endif
69static unsigned char hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
70static enum caca_color lookup_colors[8];
71
72static int const hsv_palette[] =
73{
74    /* weight, hue, saturation, value */
75    4,    0x0,    0x0,    0x0,   /* black */
76    5,    0x0,    0x0,    0x5ff, /* 30% */
77    5,    0x0,    0x0,    0x9ff, /* 70% */
78    4,    0x0,    0x0,    0xfff, /* white */
79    3,    0x1000, 0xfff,  0x5ff, /* dark yellow */
80    2,    0x1000, 0xfff,  0xfff, /* light yellow */
81    3,    0x0,    0xfff,  0x5ff, /* dark red */
82    2,    0x0,    0xfff,  0xfff  /* light red */
83};
84
85/* RGB palette for the new colour picker */
86static int rgb_palette[] =
87{
88    0x0,   0x0,   0x0,
89    0x0,   0x0,   0x7ff,
90    0x0,   0x7ff, 0x0,
91    0x0,   0x7ff, 0x7ff,
92    0x7ff, 0x0,   0x0,
93    0x7ff, 0x0,   0x7ff,
94    0x7ff, 0x7ff, 0x0,
95    0xaaa, 0xaaa, 0xaaa,
96    0x555, 0x555, 0x555,
97    0x000, 0x000, 0xfff,
98    0x000, 0xfff, 0x000,
99    0x000, 0xfff, 0xfff,
100    0xfff, 0x000, 0x000,
101    0xfff, 0x000, 0xfff,
102    0xfff, 0xfff, 0x000,
103    0xfff, 0xfff, 0xfff,
104};
105
106static int rgb_weight[] =
107{
108    //2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2
109    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
110};
111
112#if !defined(_DOXYGEN_SKIP_ME)
113#define HSV_XRATIO 6
114#define HSV_YRATIO 3
115#define HSV_HRATIO 3
116
117#define HSV_DISTANCE(h, s, v, index) \
118    (hsv_palette[index * 4] \
119     * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
120                    * ((v) - hsv_palette[index * 4 + 3])) \
121       + (hsv_palette[index * 4 + 3] \
122           ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
123                         * ((s) - hsv_palette[index * 4 + 2])) \
124           : 0) \
125       + (hsv_palette[index * 4 + 2] \
126           ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
127                         * ((h) - hsv_palette[index * 4 + 1])) \
128           : 0)))
129#endif
130
131/*
132 * Local prototypes
133 */
134static void mask2shift(unsigned int, int *, int *);
135
136static void get_rgba_default(struct caca_bitmap const *, uint8_t *, int, int,
137                             unsigned int *, unsigned int *, unsigned int *,
138                             unsigned int *);
139static inline void rgb2hsv_default(int, int, int, int *, int *, int *);
140static inline int sq(int);
141
142/* Dithering methods */
143static void init_no_dither(int);
144static unsigned int get_no_dither(void);
145static void increment_no_dither(void);
146
147static void init_ordered2_dither(int);
148static unsigned int get_ordered2_dither(void);
149static void increment_ordered2_dither(void);
150
151static void init_ordered4_dither(int);
152static unsigned int get_ordered4_dither(void);
153static void increment_ordered4_dither(void);
154
155static void init_ordered8_dither(int);
156static unsigned int get_ordered8_dither(void);
157static void increment_ordered8_dither(void);
158
159static void init_random_dither(int);
160static unsigned int get_random_dither(void);
161static void increment_random_dither(void);
162
163#if !defined(_DOXYGEN_SKIP_ME)
164struct caca_bitmap
165{
166    int bpp, has_palette, has_alpha;
167    int w, h, pitch;
168    int rmask, gmask, bmask, amask;
169    int rright, gright, bright, aright;
170    int rleft, gleft, bleft, aleft;
171    void (*get_hsv)(struct caca_bitmap *, char *, int, int);
172    int red[256], green[256], blue[256], alpha[256];
173    float gamma;
174    int gammatab[4097];
175};
176#endif
177
178static void mask2shift(unsigned int mask, int *right, int *left)
179{
180    int rshift = 0, lshift = 0;
181
182    if(!mask)
183    {
184        *right = *left = 0;
185        return;
186    }
187
188    while(!(mask & 1))
189    {
190        mask >>= 1;
191        rshift++;
192    }
193    *right = rshift;
194
195    while(mask & 1)
196    {
197        mask >>= 1;
198        lshift++;
199    }
200    *left = 12 - lshift;
201}
202
203/**
204 * \brief Create an internal bitmap object.
205 *
206 * Create a bitmap structure from its coordinates (depth, width, height and
207 * pitch) and pixel mask values. If the depth is 8 bits per pixel, the mask
208 * values are ignored and the colour palette should be set using the
209 * caca_set_bitmap_palette() function. For depths greater than 8 bits per
210 * pixel, a zero alpha mask causes the alpha values to be ignored.
211 *
212 * \param bpp Bitmap depth in bits per pixel.
213 * \param w Bitmap width in pixels.
214 * \param h Bitmap height in pixels.
215 * \param pitch Bitmap pitch in bytes.
216 * \param rmask Bitmask for red values.
217 * \param gmask Bitmask for green values.
218 * \param bmask Bitmask for blue values.
219 * \param amask Bitmask for alpha values.
220 * \return Bitmap object, or NULL upon error.
221 */
222struct caca_bitmap *caca_create_bitmap(unsigned int bpp, unsigned int w,
223                                       unsigned int h, unsigned int pitch,
224                                       unsigned int rmask, unsigned int gmask,
225                                       unsigned int bmask, unsigned int amask)
226{
227    struct caca_bitmap *bitmap;
228    int i;
229
230    /* Minor sanity test */
231    if(!w || !h || !pitch || bpp > 32 || bpp < 8)
232        return NULL;
233
234    bitmap = malloc(sizeof(struct caca_bitmap));
235    if(!bitmap)
236        return NULL;
237
238    bitmap->bpp = bpp;
239    bitmap->has_palette = 0;
240    bitmap->has_alpha = amask ? 1 : 0;
241
242    bitmap->w = w;
243    bitmap->h = h;
244    bitmap->pitch = pitch;
245
246    bitmap->rmask = rmask;
247    bitmap->gmask = gmask;
248    bitmap->bmask = bmask;
249    bitmap->amask = amask;
250
251    /* Load bitmasks */
252    if(rmask || gmask || bmask || amask)
253    {
254        mask2shift(rmask, &bitmap->rright, &bitmap->rleft);
255        mask2shift(gmask, &bitmap->gright, &bitmap->gleft);
256        mask2shift(bmask, &bitmap->bright, &bitmap->bleft);
257        mask2shift(amask, &bitmap->aright, &bitmap->aleft);
258    }
259
260    /* In 8 bpp mode, default to a grayscale palette */
261    if(bpp == 8)
262    {
263        bitmap->has_palette = 1;
264        bitmap->has_alpha = 0;
265        for(i = 0; i < 256; i++)
266        {
267            bitmap->red[i] = i * 0xfff / 256;
268            bitmap->green[i] = i * 0xfff / 256;
269            bitmap->blue[i] = i * 0xfff / 256;
270        }
271    }
272
273    /* Default gamma value */
274    for(i = 0; i < 4096; i++)
275        bitmap->gammatab[i] = i;
276
277    return bitmap;
278}
279
280/**
281 * \brief Set the palette of an 8bpp bitmap object.
282 *
283 * Set the palette of an 8 bits per pixel bitmap. Values should be between
284 * 0 and 4095 (0xfff).
285 *
286 * \param bitmap Bitmap object.
287 * \param red Array of 256 red values.
288 * \param green Array of 256 green values.
289 * \param blue Array of 256 blue values.
290 * \param alpha Array of 256 alpha values.
291 */
292void caca_set_bitmap_palette(struct caca_bitmap *bitmap,
293                             unsigned int red[], unsigned int green[],
294                             unsigned int blue[], unsigned int alpha[])
295{
296    int i, has_alpha = 0;
297
298    if(bitmap->bpp != 8)
299        return;
300
301    for(i = 0; i < 256; i++)
302    {
303        if(red[i] >= 0 && red[i] < 0x1000 &&
304           green[i] >= 0 && green[i] < 0x1000 &&
305           blue[i] >= 0 && blue[i] < 0x1000 &&
306           alpha[i] >= 0 && alpha[i] < 0x1000)
307        {
308            bitmap->red[i] = red[i];
309            bitmap->green[i] = green[i];
310            bitmap->blue[i] = blue[i];
311            if(alpha[i])
312            {
313                bitmap->alpha[i] = alpha[i];
314                has_alpha = 1;
315            }
316        }
317    }
318
319    bitmap->has_alpha = has_alpha;
320}
321
322/**
323 * \brief Set the gamma of a bitmap object.
324 *
325 * Set the gamma of bitmap.
326 *
327 * \param bitmap Bitmap object.
328 * \param gamma Gamma value.
329 */
330void caca_set_bitmap_gamma(struct caca_bitmap *bitmap, float gamma)
331{
332    int i;
333
334    if(gamma <= 0.0)
335        return;
336
337    bitmap->gamma = gamma;
338
339    for(i = 0; i < 4096; i++)
340        bitmap->gammatab[i] = 4096.0 * caca_powf((float)i / 4096.0, 1.0 / gamma);
341}
342
343/**
344 * \brief Free the memory associated with a bitmap.
345 *
346 * Free the memory allocated by caca_create_bitmap().
347 *
348 * \param bitmap Bitmap object.
349 */
350void caca_free_bitmap(struct caca_bitmap *bitmap)
351{
352    if(!bitmap)
353        return;
354
355    free(bitmap);
356}
357
358static void get_rgba_default(struct caca_bitmap const *bitmap, uint8_t *pixels,
359                             int x, int y, unsigned int *r, unsigned int *g,
360                             unsigned int *b, unsigned int *a)
361{
362    uint32_t bits;
363
364    pixels += (bitmap->bpp / 8) * x + bitmap->pitch * y;
365
366    switch(bitmap->bpp / 8)
367    {
368        case 4:
369            bits = *(uint32_t *)pixels;
370            break;
371        case 3:
372        {
373#if defined(HAVE_ENDIAN_H)
374            if(__BYTE_ORDER == __BIG_ENDIAN)
375#else
376            /* This is compile-time optimised with at least -O1 or -Os */
377            uint32_t const rmask = 0x12345678;
378            if(*(uint8_t const *)&rmask == 0x12)
379#endif
380                bits = ((uint32_t)pixels[0] << 16) |
381                       ((uint32_t)pixels[1] << 8) |
382                       ((uint32_t)pixels[2]);
383            else
384                bits = ((uint32_t)pixels[2] << 16) |
385                       ((uint32_t)pixels[1] << 8) |
386                       ((uint32_t)pixels[0]);
387            break;
388        }
389        case 2:
390            bits = *(uint16_t *)pixels;
391            break;
392        case 1:
393        default:
394            bits = pixels[0];
395            break;
396    }
397
398    if(bitmap->has_palette)
399    {
400        *r += bitmap->gammatab[bitmap->red[bits]];
401        *g += bitmap->gammatab[bitmap->green[bits]];
402        *b += bitmap->gammatab[bitmap->blue[bits]];
403        *a += bitmap->alpha[bits];
404    }
405    else
406    {
407        *r += bitmap->gammatab[((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft];
408        *g += bitmap->gammatab[((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft];
409        *b += bitmap->gammatab[((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft];
410        *a += ((bits & bitmap->amask) >> bitmap->aright) << bitmap->aleft;
411    }
412}
413
414static inline void rgb2hsv_default(int r, int g, int b,
415                                   int *hue, int *sat, int *val)
416{
417    int min, max, delta;
418
419    min = r; max = r;
420    if(min > g) min = g; if(max < g) max = g;
421    if(min > b) min = b; if(max < b) max = b;
422
423    delta = max - min; /* 0 - 0xfff */
424    *val = max; /* 0 - 0xfff */
425
426    if(delta)
427    {
428        *sat = 0xfff * delta / max; /* 0 - 0xfff */
429
430        /* Generate *hue between 0 and 0x5fff */
431        if( r == max )
432            *hue = 0x1000 + 0x1000 * (g - b) / delta;
433        else if( g == max )
434            *hue = 0x3000 + 0x1000 * (b - r) / delta;
435        else
436            *hue = 0x5000 + 0x1000 * (r - g) / delta;
437    }
438    else
439    {
440        *sat = 0;
441        *hue = 0;
442    }
443}
444
445static inline int sq(int x)
446{
447    return x * x;
448}
449
450/**
451 * \brief Draw a bitmap on the screen.
452 *
453 * Draw a bitmap at the given coordinates. The bitmap can be of any size and
454 * will be stretched to the text area.
455 *
456 * \param x1 X coordinate of the upper-left corner of the drawing area.
457 * \param y1 Y coordinate of the upper-left corner of the drawing area.
458 * \param x2 X coordinate of the lower-right corner of the drawing area.
459 * \param y2 Y coordinate of the lower-right corner of the drawing area.
460 * \param bitmap Bitmap object to be drawn.
461 * \param pixels Bitmap's pixels.
462 */
463void caca_draw_bitmap(int x1, int y1, int x2, int y2,
464                      struct caca_bitmap const *bitmap, void *pixels)
465{
466    /* Current dithering method */
467    void (*_init_dither) (int);
468    unsigned int (*_get_dither) (void);
469    void (*_increment_dither) (void);
470
471    int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
472    int fs_length;
473
474    /* FIXME: choose better characters! */
475#if !defined(_DOXYGEN_SKIP_ME)
476#   define DCHMAX ((sizeof(density_chars)/sizeof(char const)/4)-1)
477#endif
478    static char const density_chars[] =
479        "    "
480        "...."
481        "::::"
482        ";=;="
483        "tftf"
484        "%$%$"
485        "SK&Z"
486        "XWGM"
487        "@@@@"
488        "8888"
489        "####"
490        "????";
491
492    int x, y, w, h, pitch, deltax, deltay;
493
494    if(!bitmap || !pixels)
495        return;
496
497    w = bitmap->w;
498    h = bitmap->h;
499    pitch = bitmap->pitch;
500
501    if(x1 > x2)
502    {
503        int tmp = x2; x2 = x1; x1 = tmp;
504    }
505
506    if(y1 > y2)
507    {
508        int tmp = y2; y2 = y1; y1 = tmp;
509    }
510
511    deltax = x2 - x1 + 1;
512    deltay = y2 - y1 + 1;
513
514    switch(_caca_dithering)
515    {
516    case CACA_DITHERING_NONE:
517        _init_dither = init_no_dither;
518        _get_dither = get_no_dither;
519        _increment_dither = increment_no_dither;
520        break;
521
522    case CACA_DITHERING_ORDERED2:
523        _init_dither = init_ordered2_dither;
524        _get_dither = get_ordered2_dither;
525        _increment_dither = increment_ordered2_dither;
526        break;
527
528    case CACA_DITHERING_ORDERED4:
529        _init_dither = init_ordered4_dither;
530        _get_dither = get_ordered4_dither;
531        _increment_dither = increment_ordered4_dither;
532        break;
533
534    case CACA_DITHERING_ORDERED8:
535        _init_dither = init_ordered8_dither;
536        _get_dither = get_ordered8_dither;
537        _increment_dither = increment_ordered8_dither;
538        break;
539
540    case CACA_DITHERING_RANDOM:
541        _init_dither = init_random_dither;
542        _get_dither = get_random_dither;
543        _increment_dither = increment_random_dither;
544        break;
545
546    case CACA_DITHERING_FSTEIN:
547        _init_dither = init_no_dither;
548        _get_dither = get_no_dither;
549        _increment_dither = increment_no_dither;
550        break;
551
552    default:
553        /* Something wicked happened! */
554        return;
555    }
556
557    fs_length = ((int)_caca_width <= x2 ? (int)_caca_width : x2) + 1;
558    floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
559    memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
560    fs_r = floyd_steinberg + 1;
561    fs_g = fs_r + fs_length + 2;
562    fs_b = fs_g + fs_length + 2;
563
564    for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)_caca_height; y++)
565    {
566        int remain_r = 0, remain_g = 0, remain_b = 0;
567
568        for(x = x1 > 0 ? x1 : 0, _init_dither(y);
569            x <= x2 && x <= (int)_caca_width;
570            x++)
571    {
572        unsigned int i;
573        int ch = 0, distmin;
574        unsigned int r, g, b, a;
575        int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
576        int fromx, fromy, tox, toy, myx, myy, dots, dist;
577        int error[3];
578
579        enum caca_color outfg = 0, outbg = 0;
580        char outch;
581
582        r = g = b = a = 0;
583
584        /* First get RGB */
585        if(_caca_antialiasing == CACA_ANTIALIASING_PREFILTER)
586        {
587            fromx = (x - x1) * w / deltax;
588            fromy = (y - y1) * h / deltay;
589            tox = (x - x1 + 1) * w / deltax;
590            toy = (y - y1 + 1) * h / deltay;
591
592            /* We want at least one pixel */
593            if(tox == fromx) tox++;
594            if(toy == fromy) toy++;
595
596            dots = 0;
597
598            for(myx = fromx; myx < tox; myx++)
599                for(myy = fromy; myy < toy; myy++)
600            {
601                dots++;
602                get_rgba_default(bitmap, pixels, myx, myy, &r, &g, &b, &a);
603            }
604
605            /* Normalize */
606            r /= dots;
607            g /= dots;
608            b /= dots;
609            a /= dots;
610        }
611        else
612        {
613            fromx = (x - x1) * w / deltax;
614            fromy = (y - y1) * h / deltay;
615            tox = (x - x1 + 1) * w / deltax;
616            toy = (y - y1 + 1) * h / deltay;
617
618            /* tox and toy can overflow the screen, but they cannot overflow
619             * when averaged with fromx and fromy because these are guaranteed
620             * to be within the pixel boundaries. */
621            myx = (fromx + tox) / 2;
622            myy = (fromy + toy) / 2;
623
624            get_rgba_default(bitmap, pixels, myx, myy, &r, &g, &b, &a);
625        }
626
627        if(bitmap->has_alpha && a < 0x800)
628        {
629            remain_r = remain_g = remain_b = 0;
630            fs_r[x] = 0;
631            fs_g[x] = 0;
632            fs_b[x] = 0;
633            continue;
634        }
635
636        if(_caca_dithering == CACA_DITHERING_FSTEIN)
637        {
638            r += remain_r;
639            g += remain_g;
640            b += remain_b;
641        }
642        else
643        {
644            r += (_get_dither() - 0x80) * 4;
645            g += (_get_dither() - 0x80) * 4;
646            b += (_get_dither() - 0x80) * 4;
647        }
648
649        distmin = INT_MAX;
650        for(i = 0; i < 16; i++)
651        {
652            dist = sq(r - rgb_palette[i * 3])
653                 + sq(g - rgb_palette[i * 3 + 1])
654                 + sq(b - rgb_palette[i * 3 + 2]);
655            dist *= rgb_weight[i];
656            if(dist < distmin)
657            {
658                outbg = i;
659                distmin = dist;
660            }
661        }
662        bg_r = rgb_palette[outbg * 3];
663        bg_g = rgb_palette[outbg * 3 + 1];
664        bg_b = rgb_palette[outbg * 3 + 2];
665
666        if(_caca_background == CACA_BACKGROUND_SOLID)
667        {
668            distmin = INT_MAX;
669            for(i = 0; i < 16; i++)
670            {
671                if(i == outbg)
672                    continue;
673                dist = sq(r - rgb_palette[i * 3])
674                     + sq(g - rgb_palette[i * 3 + 1])
675                     + sq(b - rgb_palette[i * 3 + 2]);
676                dist *= rgb_weight[i];
677                if(dist < distmin)
678                {
679                    outfg = i;
680                    distmin = dist;
681                }
682            }
683            fg_r = rgb_palette[outfg * 3];
684            fg_g = rgb_palette[outfg * 3 + 1];
685            fg_b = rgb_palette[outfg * 3 + 2];
686
687            distmin = INT_MAX;
688            for(i = 0; i < DCHMAX - 1; i++)
689            {
690                int newr = i * fg_r + ((2*DCHMAX-1) - i) * bg_r;
691                int newg = i * fg_g + ((2*DCHMAX-1) - i) * bg_g;
692                int newb = i * fg_b + ((2*DCHMAX-1) - i) * bg_b;
693                dist = abs(r * (2*DCHMAX-1) - newr)
694                     + abs(g * (2*DCHMAX-1) - newg)
695                     + abs(b * (2*DCHMAX-1) - newb);
696
697                if(dist < distmin)
698                {
699                    ch = i;
700                    distmin = dist;
701                }
702            }
703            outch = density_chars[4 * ch];
704
705            if(_caca_dithering == CACA_DITHERING_FSTEIN)
706            {
707                error[0] = r - (fg_r * ch + bg_r * ((2*DCHMAX-1) - ch)) / (2*DCHMAX-1);
708                error[1] = g - (fg_g * ch + bg_g * ((2*DCHMAX-1) - ch)) / (2*DCHMAX-1);
709                error[2] = b - (fg_b * ch + bg_b * ((2*DCHMAX-1) - ch)) / (2*DCHMAX-1);
710            }
711        }
712        else
713        {
714            unsigned int lum = r; if(g > lum) lum = g; if(b > lum) lum = b;
715            outfg = outbg;
716            outbg = CACA_COLOR_BLACK;
717
718            ch = lum * DCHMAX / 0x1000;
719            if(ch < 0)
720                ch = 0;
721            else if(ch > (int)(DCHMAX - 1))
722                ch = DCHMAX - 1;
723            outch = density_chars[4 * ch];
724
725            if(_caca_dithering == CACA_DITHERING_FSTEIN)
726            {
727                error[0] = r - bg_r * ch / (DCHMAX-1);
728                error[1] = g - bg_g * ch / (DCHMAX-1);
729                error[2] = b - bg_b * ch / (DCHMAX-1);
730            }
731        }
732
733        if(_caca_dithering == CACA_DITHERING_FSTEIN)
734        {
735            remain_r = fs_r[x+1] + 7 * error[0] / 16;
736            remain_g = fs_g[x+1] + 7 * error[1] / 16;
737            remain_b = fs_b[x+1] + 7 * error[2] / 16;
738            fs_r[x-1] += 3 * error[0] / 16;
739            fs_g[x-1] += 3 * error[1] / 16;
740            fs_b[x-1] += 3 * error[2] / 16;
741            fs_r[x] = 5 * error[0] / 16;
742            fs_g[x] = 5 * error[1] / 16;
743            fs_b[x] = 5 * error[2] / 16;
744            fs_r[x+1] = 1 * error[0] / 16;
745            fs_g[x+1] = 1 * error[1] / 16;
746            fs_b[x+1] = 1 * error[2] / 16;
747        }
748
749        /* Now output the character */
750        caca_set_color(outfg, outbg);
751        caca_putchar(x, y, outch);
752
753        _increment_dither();
754    }
755        /* end loop */
756    }
757
758    free(floyd_steinberg);
759}
760
761#if !defined(_DOXYGEN_SKIP_ME)
762int _caca_init_bitmap(void)
763{
764    unsigned int v, s, h;
765
766    /* These ones are constant */
767    lookup_colors[0] = CACA_COLOR_BLACK;
768    lookup_colors[1] = CACA_COLOR_DARKGRAY;
769    lookup_colors[2] = CACA_COLOR_LIGHTGRAY;
770    lookup_colors[3] = CACA_COLOR_WHITE;
771
772    /* These ones will be overwritten */
773    lookup_colors[4] = CACA_COLOR_MAGENTA;
774    lookup_colors[5] = CACA_COLOR_LIGHTMAGENTA;
775    lookup_colors[6] = CACA_COLOR_RED;
776    lookup_colors[7] = CACA_COLOR_LIGHTRED;
777
778    for(v = 0; v < LOOKUP_VAL; v++)
779        for(s = 0; s < LOOKUP_SAT; s++)
780            for(h = 0; h < LOOKUP_HUE; h++)
781    {
782        int i, distbg, distfg, dist;
783        int val, sat, hue;
784        unsigned char outbg, outfg;
785
786        val = 0xfff * v / (LOOKUP_VAL - 1);
787        sat = 0xfff * s / (LOOKUP_SAT - 1);
788        hue = 0xfff * h / (LOOKUP_HUE - 1);
789
790        /* Initialise distances to the distance between pure black HSV
791         * coordinates and our white colour (3) */
792        outbg = outfg = 3;
793        distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
794
795        /* Calculate distances to eight major colour values and store the
796         * two nearest points in our lookup table. */
797        for(i = 0; i < 8; i++)
798        {
799            dist = HSV_DISTANCE(hue, sat, val, i);
800            if(dist <= distbg)
801            {
802                outfg = outbg;
803                distfg = distbg;
804                outbg = i;
805                distbg = dist;
806            }
807            else if(dist <= distfg)
808            {
809                outfg = i;
810                distfg = dist;
811            }
812        }
813
814        hsv_distances[v][s][h] = (outfg << 4) | outbg;
815    }
816
817    return 0;
818}
819
820int _caca_end_bitmap(void)
821{
822    return 0;
823}
824#endif /* _DOXYGEN_SKIP_ME */
825
826/*
827 * XXX: The following functions are local.
828 */
829
830/*
831 * No dithering
832 */
833static void init_no_dither(int line)
834{
835    ;
836}
837
838static unsigned int get_no_dither(void)
839{
840    return 0x80;
841}
842
843static void increment_no_dither(void)
844{
845    return;
846}
847
848/*
849 * Ordered 2 dithering
850 */
851static unsigned int *ordered2_table;
852static unsigned int ordered2_index;
853
854static void init_ordered2_dither(int line)
855{
856    static unsigned int dither2x2[] =
857    {
858        0x00, 0x80,
859        0xc0, 0x40,
860    };
861
862    ordered2_table = dither2x2 + (line % 2) * 2;
863    ordered2_index = 0;
864}
865
866static unsigned int get_ordered2_dither(void)
867{
868    return ordered2_table[ordered2_index];
869}
870
871static void increment_ordered2_dither(void)
872{
873    ordered2_index = (ordered2_index + 1) % 2;
874}
875
876/*
877 * Ordered 4 dithering
878 */
879/*static int dither4x4[] = { 5,  0,  1,  6,
880                          -1, -6, -5,  2,
881                          -2, -7, -8,  3,
882                           4, -3, -4, -7};*/
883static unsigned int *ordered4_table;
884static unsigned int ordered4_index;
885
886static void init_ordered4_dither(int line)
887{
888    static unsigned int dither4x4[] =
889    {
890        0x00, 0x80, 0x20, 0xa0,
891        0xc0, 0x40, 0xe0, 0x60,
892        0x30, 0xb0, 0x10, 0x90,
893        0xf0, 0x70, 0xd0, 0x50
894    };
895
896    ordered4_table = dither4x4 + (line % 4) * 4;
897    ordered4_index = 0;
898}
899
900static unsigned int get_ordered4_dither(void)
901{
902    return ordered4_table[ordered4_index];
903}
904
905static void increment_ordered4_dither(void)
906{
907    ordered4_index = (ordered4_index + 1) % 4;
908}
909
910/*
911 * Ordered 8 dithering
912 */
913static unsigned int *ordered8_table;
914static unsigned int ordered8_index;
915
916static void init_ordered8_dither(int line)
917{
918    static unsigned int dither8x8[] =
919    {
920        0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
921        0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
922        0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
923        0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
924        0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
925        0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
926        0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
927        0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
928    };
929
930    ordered8_table = dither8x8 + (line % 8) * 8;
931    ordered8_index = 0;
932}
933
934static unsigned int get_ordered8_dither(void)
935{
936    return ordered8_table[ordered8_index];
937}
938
939static void increment_ordered8_dither(void)
940{
941    ordered8_index = (ordered8_index + 1) % 8;
942}
943
944/*
945 * Random dithering
946 */
947static void init_random_dither(int line)
948{
949    ;
950}
951
952static unsigned int get_random_dither(void)
953{
954    return caca_rand(0x00, 0xff);
955}
956
957static void increment_random_dither(void)
958{
959    return;
960}
961
Note: See TracBrowser for help on using the repository browser.