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

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