source: libcaca/trunk/cucul/bitmap.c @ 540

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