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

Last change on this file since 733 was 733, checked in by Sam Hocevar, 15 years ago
  • Replaced enum cucul_color with unsigned int. The size of an enum is not really portable, and Visual Studio complains when they are not explicitely cast.
  • Property svn:keywords set to Id
File size: 36.2 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
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 733 2006-04-10 09:17:51Z 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#define CP437 0
36
37/*
38 * Local variables
39 */
40#if !defined(_DOXYGEN_SKIP_ME)
41#   define LOOKUP_VAL 32
42#   define LOOKUP_SAT 32
43#   define LOOKUP_HUE 16
44#endif
45static unsigned char hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
46static uint16_t lookup_colors[8];
47
48static int const hsv_palette[] =
49{
50    /* weight, hue, saturation, value */
51    4,    0x0,    0x0,    0x0,   /* black */
52    5,    0x0,    0x0,    0x5ff, /* 30% */
53    5,    0x0,    0x0,    0x9ff, /* 70% */
54    4,    0x0,    0x0,    0xfff, /* white */
55    3,    0x1000, 0xfff,  0x5ff, /* dark yellow */
56    2,    0x1000, 0xfff,  0xfff, /* light yellow */
57    3,    0x0,    0xfff,  0x5ff, /* dark red */
58    2,    0x0,    0xfff,  0xfff  /* light red */
59};
60
61/* RGB palette for the new colour picker */
62static int const rgb_palette[] =
63{
64    0x0,   0x0,   0x0,
65    0x0,   0x0,   0x7ff,
66    0x0,   0x7ff, 0x0,
67    0x0,   0x7ff, 0x7ff,
68    0x7ff, 0x0,   0x0,
69    0x7ff, 0x0,   0x7ff,
70    0x7ff, 0x7ff, 0x0,
71    0xaaa, 0xaaa, 0xaaa,
72    0x555, 0x555, 0x555,
73    0x000, 0x000, 0xfff,
74    0x000, 0xfff, 0x000,
75    0x000, 0xfff, 0xfff,
76    0xfff, 0x000, 0x000,
77    0xfff, 0x000, 0xfff,
78    0xfff, 0xfff, 0x000,
79    0xfff, 0xfff, 0xfff,
80};
81
82static int const rgb_weight[] =
83{
84    //2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2
85    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
86};
87
88/* List of glyphs */
89static char const * ascii_glyphs[] =
90{
91    " ", ".", ":", ";", "t", "%", "S", "X", "@", "8", "?"
92};
93
94static char const * shades_glyphs[] =
95{
96    " ", ":", "░", "▒", "?"
97};
98
99static char const * blocks_glyphs[] =
100{
101    " ", "▘", "▚", "?"
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 cucul_bitmap
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)(struct cucul_bitmap *, char *, int, int);
124    int red[256], green[256], blue[256], alpha[256];
125    float gamma;
126    int gammatab[4097];
127
128    /* Bitmap features */
129    int invert, antialias;
130
131    /* Colour mode used for rendering */
132    enum color_mode color_mode;
133
134    /* Glyphs used for rendering */
135    char const * const * glyphs;
136    unsigned glyph_count;
137
138    /* Current dithering method */
139    void (*init_dither) (int);
140    unsigned int (*get_dither) (void);
141    void (*increment_dither) (void);
142};
143
144#define HSV_XRATIO 6
145#define HSV_YRATIO 3
146#define HSV_HRATIO 3
147
148#define HSV_DISTANCE(h, s, v, index) \
149    (hsv_palette[index * 4] \
150     * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
151                    * ((v) - hsv_palette[index * 4 + 3])) \
152       + (hsv_palette[index * 4 + 3] \
153           ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
154                         * ((s) - hsv_palette[index * 4 + 2])) \
155           : 0) \
156       + (hsv_palette[index * 4 + 2] \
157           ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
158                         * ((h) - hsv_palette[index * 4 + 1])) \
159           : 0)))
160#endif
161
162/*
163 * Local prototypes
164 */
165static void mask2shift(unsigned int, int *, int *);
166static float gammapow(float x, float y);
167
168static void get_rgba_default(struct cucul_bitmap const *, uint8_t *, int, int,
169                             unsigned int *);
170
171/* Dithering methods */
172static void init_no_dither(int);
173static unsigned int get_no_dither(void);
174static void increment_no_dither(void);
175
176static void init_fstein_dither(int);
177static unsigned int get_fstein_dither(void);
178static void increment_fstein_dither(void);
179
180static void init_ordered2_dither(int);
181static unsigned int get_ordered2_dither(void);
182static void increment_ordered2_dither(void);
183
184static void init_ordered4_dither(int);
185static unsigned int get_ordered4_dither(void);
186static void increment_ordered4_dither(void);
187
188static void init_ordered8_dither(int);
189static unsigned int get_ordered8_dither(void);
190static void increment_ordered8_dither(void);
191
192static void init_random_dither(int);
193static unsigned int get_random_dither(void);
194static void increment_random_dither(void);
195
196static inline int sq(int x)
197{
198    return x * x;
199}
200
201static inline void rgb2hsv_default(int r, int g, int b,
202                                   int *hue, int *sat, int *val)
203{
204    int min, max, delta;
205
206    min = r; max = r;
207    if(min > g) min = g; if(max < g) max = g;
208    if(min > b) min = b; if(max < b) max = b;
209
210    delta = max - min; /* 0 - 0xfff */
211    *val = max; /* 0 - 0xfff */
212
213    if(delta)
214    {
215        *sat = 0xfff * delta / max; /* 0 - 0xfff */
216
217        /* Generate *hue between 0 and 0x5fff */
218        if( r == max )
219            *hue = 0x1000 + 0x1000 * (g - b) / delta;
220        else if( g == max )
221            *hue = 0x3000 + 0x1000 * (b - r) / delta;
222        else
223            *hue = 0x5000 + 0x1000 * (r - g) / delta;
224    }
225    else
226    {
227        *sat = 0;
228        *hue = 0;
229    }
230}
231
232/**
233 * \brief Create an internal bitmap object.
234 *
235 * Create a bitmap structure from its coordinates (depth, width, height and
236 * pitch) and pixel mask values. If the depth is 8 bits per pixel, the mask
237 * values are ignored and the colour palette should be set using the
238 * cucul_set_bitmap_palette() function. For depths greater than 8 bits per
239 * pixel, a zero alpha mask causes the alpha values to be ignored.
240 *
241 * \param bpp Bitmap depth in bits per pixel.
242 * \param w Bitmap width in pixels.
243 * \param h Bitmap height in pixels.
244 * \param pitch Bitmap pitch in bytes.
245 * \param rmask Bitmask for red values.
246 * \param gmask Bitmask for green values.
247 * \param bmask Bitmask for blue values.
248 * \param amask Bitmask for alpha values.
249 * \return Bitmap object, or NULL upon error.
250 */
251struct cucul_bitmap *cucul_create_bitmap(unsigned int bpp, unsigned int w,
252                                         unsigned int h, unsigned int pitch,
253                                         unsigned int rmask, unsigned int gmask,
254                                         unsigned int bmask, unsigned int amask)
255{
256    struct cucul_bitmap *bitmap;
257    int i;
258
259    /* Minor sanity test */
260    if(!w || !h || !pitch || bpp > 32 || bpp < 8)
261        return NULL;
262
263    bitmap = malloc(sizeof(struct cucul_bitmap));
264    if(!bitmap)
265        return NULL;
266
267    bitmap->bpp = bpp;
268    bitmap->has_palette = 0;
269    bitmap->has_alpha = amask ? 1 : 0;
270
271    bitmap->w = w;
272    bitmap->h = h;
273    bitmap->pitch = pitch;
274
275    bitmap->rmask = rmask;
276    bitmap->gmask = gmask;
277    bitmap->bmask = bmask;
278    bitmap->amask = amask;
279
280    /* Load bitmasks */
281    if(rmask || gmask || bmask || amask)
282    {
283        mask2shift(rmask, &bitmap->rright, &bitmap->rleft);
284        mask2shift(gmask, &bitmap->gright, &bitmap->gleft);
285        mask2shift(bmask, &bitmap->bright, &bitmap->bleft);
286        mask2shift(amask, &bitmap->aright, &bitmap->aleft);
287    }
288
289    /* In 8 bpp mode, default to a grayscale palette */
290    if(bpp == 8)
291    {
292        bitmap->has_palette = 1;
293        bitmap->has_alpha = 0;
294        for(i = 0; i < 256; i++)
295        {
296            bitmap->red[i] = i * 0xfff / 256;
297            bitmap->green[i] = i * 0xfff / 256;
298            bitmap->blue[i] = i * 0xfff / 256;
299        }
300    }
301
302    /* Default features */
303    bitmap->invert = 0;
304    bitmap->antialias = 1;
305
306    /* Default gamma value */
307    for(i = 0; i < 4096; i++)
308        bitmap->gammatab[i] = i;
309
310    /* Default colour mode */
311    bitmap->color_mode = COLOR_MODE_FULL16;
312
313    /* Default character set */
314    bitmap->glyphs = ascii_glyphs;
315    bitmap->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
316
317    /* Default dithering mode */
318    bitmap->init_dither = init_fstein_dither;
319    bitmap->get_dither = get_fstein_dither;
320    bitmap->increment_dither = increment_fstein_dither;
321
322    return bitmap;
323}
324
325/**
326 * \brief Set the palette of an 8bpp bitmap object.
327 *
328 * Set the palette of an 8 bits per pixel bitmap. Values should be between
329 * 0 and 4095 (0xfff).
330 *
331 * \param bitmap Bitmap object.
332 * \param red Array of 256 red values.
333 * \param green Array of 256 green values.
334 * \param blue Array of 256 blue values.
335 * \param alpha Array of 256 alpha values.
336 */
337void cucul_set_bitmap_palette(struct cucul_bitmap *bitmap,
338                              unsigned int red[], unsigned int green[],
339                              unsigned int blue[], unsigned int alpha[])
340{
341    int i, has_alpha = 0;
342
343    if(bitmap->bpp != 8)
344        return;
345
346    for(i = 0; i < 256; i++)
347    {
348        if(red[i] >= 0 && red[i] < 0x1000 &&
349           green[i] >= 0 && green[i] < 0x1000 &&
350           blue[i] >= 0 && blue[i] < 0x1000 &&
351           alpha[i] >= 0 && alpha[i] < 0x1000)
352        {
353            bitmap->red[i] = red[i];
354            bitmap->green[i] = green[i];
355            bitmap->blue[i] = blue[i];
356            if(alpha[i])
357            {
358                bitmap->alpha[i] = alpha[i];
359                has_alpha = 1;
360            }
361        }
362    }
363
364    bitmap->has_alpha = has_alpha;
365}
366
367/**
368 * \brief Set the brightness of a bitmap object.
369 *
370 * Set the brightness of bitmap.
371 *
372 * \param bitmap Bitmap object.
373 * \param brightness brightness value.
374 */
375void cucul_set_bitmap_brightness(struct cucul_bitmap *bitmap, float brightness)
376{
377    /* FIXME */
378}
379
380/**
381 * \brief Set the gamma of a bitmap object.
382 *
383 * Set the gamma of bitmap.
384 *
385 * \param bitmap Bitmap object.
386 * \param gamma Gamma value.
387 */
388void cucul_set_bitmap_gamma(struct cucul_bitmap *bitmap, float gamma)
389{
390    /* FIXME: we don't need 4096 calls to gammapow(), we can just compute
391     * 128 of them and do linear interpolation for the rest. This will
392     * probably speed up things a lot. */
393    int i;
394
395    if(gamma <= 0.0)
396        return;
397
398    bitmap->gamma = gamma;
399
400    for(i = 0; i < 4096; i++)
401        bitmap->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma);
402}
403
404/**
405 * \brief Invert colors of bitmap
406 *
407 * Invert colors of bitmap
408 *
409 * \param bitmap Bitmap object.
410 * \param value 0 for normal behaviour, 1 for invert
411 */
412void cucul_set_bitmap_invert(struct cucul_bitmap *bitmap, int value)
413{
414    bitmap->invert = value ? 1 : 0;
415}
416
417/**
418 * \brief Set the contrast of a bitmap object.
419 *
420 * Set the contrast of bitmap.
421 *
422 * \param bitmap Bitmap object.
423 * \param contrast contrast value.
424 */
425void cucul_set_bitmap_contrast(struct cucul_bitmap *bitmap, float contrast)
426{
427    /* FIXME */
428}
429
430/**
431 * \brief Set bitmap antialiasing
432 *
433 * Tell the renderer whether to antialias the bitmap. Antialiasing smoothen
434 * the rendered image and avoids the commonly seen staircase effect.
435 *
436 * \li \e "none": no antialiasing.
437 *
438 * \li \e "prefilter": simple prefilter antialiasing. This is the default
439 *     value.
440 *
441 * \param bitmap Bitmap object.
442 * \param str A string describing the antialiasing method that will be used
443 *        for the bitmap rendering.
444 */
445void cucul_set_bitmap_antialias(struct cucul_bitmap *bitmap, char const *str)
446{
447    if(!strcasecmp(str, "none"))
448        bitmap->antialias = 0;
449    else /* "prefilter" is the default */
450        bitmap->antialias = 1;
451}
452
453/**
454 * \brief Get available antialiasing methods
455 *
456 * Return a list of available antialiasing methods for a given bitmap. The
457 * list is a NULL-terminated array of strings, interleaving a string
458 * containing the internal value for the antialiasing method to be used with
459 * \e cucul_set_bitmap_antialias(), and a string containing the natural
460 * language description for that antialiasing method.
461 *
462 * \param bitmap Bitmap object.
463 * \return An array of strings.
464 */
465char const * const *
466    cucul_get_bitmap_antialias_list(struct cucul_bitmap const *bitmap)
467{
468    static char const * const list[] =
469    {
470        "none", "No antialiasing",
471        "prefilter", "Prefilter antialiasing",
472        NULL, NULL
473    };
474
475    return list;
476}
477
478/**
479 * \brief Choose colours used for bitmap rendering
480 *
481 * Tell the renderer which colours should be used to render the
482 * bitmap. Valid values for \e str are:
483 *
484 * \li \e "mono": use light gray on a black background.
485 *
486 * \li \e "gray": use white and two shades of gray on a black background.
487 *
488 * \li \e "8": use the 8 ANSI colours on a black background.
489 *
490 * \li \e "16": use the 16 ANSI colours on a black background.
491 *
492 * \li \e "fullgray": use black, white and two shades of gray for both the
493 *     characters and the background.
494 *
495 * \li \e "full8": use the 8 ANSI colours for both the characters and the
496 *     background.
497 *
498 * \li \e "full16": use the 16 ANSI colours for both the characters and the
499 *     background. This is the default value.
500 *
501 * \param bitmap Bitmap object.
502 * \param str A string describing the colour set that will be used
503 *        for the bitmap rendering.
504 */
505void cucul_set_bitmap_color(struct cucul_bitmap *bitmap, char const *str)
506{
507    if(!strcasecmp(str, "mono"))
508        bitmap->color_mode = COLOR_MODE_MONO;
509    else if(!strcasecmp(str, "gray"))
510        bitmap->color_mode = COLOR_MODE_GRAY;
511    else if(!strcasecmp(str, "8"))
512        bitmap->color_mode = COLOR_MODE_8;
513    else if(!strcasecmp(str, "16"))
514        bitmap->color_mode = COLOR_MODE_16;
515    else if(!strcasecmp(str, "fullgray"))
516        bitmap->color_mode = COLOR_MODE_FULLGRAY;
517    else if(!strcasecmp(str, "full8"))
518        bitmap->color_mode = COLOR_MODE_FULL8;
519    else /* "full16" is the default */
520        bitmap->color_mode = COLOR_MODE_FULL16;
521}
522
523/**
524 * \brief Get available colour modes
525 *
526 * Return a list of available colour modes for a given bitmap. The list
527 * is a NULL-terminated array of strings, interleaving a string containing
528 * the internal value for the colour mode, to be used with
529 * \e cucul_set_bitmap_color(), and a string containing the natural
530 * language description for that colour mode.
531 *
532 * \param bitmap Bitmap object.
533 * \return An array of strings.
534 */
535char const * const *
536    cucul_get_bitmap_color_list(struct cucul_bitmap const *bitmap)
537{
538    static char const * const list[] =
539    {
540        "mono", "white on black",
541        "gray", "grayscale on black",
542        "8", "8 colours on black",
543        "16", "16 colours on black",
544        "fullgray", "full grayscale",
545        "full8", "full 8 colours",
546        "full16", "full 16 colours",
547        NULL, NULL
548    };
549
550    return list;
551}
552
553/**
554 * \brief Choose characters used for bitmap rendering
555 *
556 * Tell the renderer which characters should be used to render the
557 * bitmap. Valid values for \e str are:
558 *
559 * \li \e "ascii": use only ASCII characters. This is the default value.
560 *
561 * \li \e "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592
562 *     MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also
563 *     present in the CP437 codepage available on DOS and VGA.
564 *
565 * \li \e "blocks": use Unicode quarter-cell block combinations. These
566 *     characters are only found in the Unicode set.
567 *
568 * \param bitmap Bitmap object.
569 * \param str A string describing the characters that need to be used
570 *        for the bitmap rendering.
571 */
572void cucul_set_bitmap_charset(struct cucul_bitmap *bitmap, char const *str)
573{
574    if(!strcasecmp(str, "shades"))
575    {
576        bitmap->glyphs = shades_glyphs;
577        bitmap->glyph_count = sizeof(shades_glyphs) / sizeof(*shades_glyphs);
578    }
579    else if(!strcasecmp(str, "blocks"))
580    {
581        bitmap->glyphs = blocks_glyphs;
582        bitmap->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
583    }
584    else /* "ascii" is the default */
585    {
586        bitmap->glyphs = ascii_glyphs;
587        bitmap->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
588    }
589}
590
591/**
592 * \brief Get available bitmap character sets
593 *
594 * Return a list of available character sets for a given bitmap. The list
595 * is a NULL-terminated array of strings, interleaving a string containing
596 * the internal value for the character set, to be used with
597 * \e cucul_set_bitmap_charset(), and a string containing the natural
598 * language description for that character set.
599 *
600 * \param bitmap Bitmap object.
601 * \return An array of strings.
602 */
603char const * const *
604    cucul_get_bitmap_charset_list(struct cucul_bitmap const *bitmap)
605{
606    static char const * const list[] =
607    {
608        "ascii", "plain ASCII",
609        "shades", "CP437 shades",
610        "blocks", "Unicode blocks",
611        NULL, NULL
612    };
613
614    return list;
615}
616
617/**
618 * \brief Set bitmap dithering method
619 *
620 * Tell the renderer which dithering method should be used to render the
621 * bitmap. Dithering is necessary because the picture being rendered has
622 * usually far more colours than the available palette. Valid values for
623 * \e str are:
624 *
625 * \li \e "none": no dithering is used, the nearest matching colour is used.
626 *
627 * \li \e "ordered2": use a 2x2 Bayer matrix for dithering.
628 *
629 * \li \e "ordered4": use a 4x4 Bayer matrix for dithering.
630 *
631 * \li \e "ordered8": use a 8x8 Bayer matrix for dithering.
632 *
633 * \li \e "random": use random dithering.
634 *
635 * \li \e "fstein": use Floyd-Steinberg dithering. This is the default value.
636 *
637 * \param bitmap Bitmap object.
638 * \param str A string describing the dithering method that needs to be used
639 *        for the bitmap rendering.
640 */
641void cucul_set_bitmap_dithering(struct cucul_bitmap *bitmap, char const *str)
642{
643    if(!strcasecmp(str, "none"))
644    {
645        bitmap->init_dither = init_no_dither;
646        bitmap->get_dither = get_no_dither;
647        bitmap->increment_dither = increment_no_dither;
648    }
649    else if(!strcasecmp(str, "ordered2"))
650    {
651        bitmap->init_dither = init_ordered2_dither;
652        bitmap->get_dither = get_ordered2_dither;
653        bitmap->increment_dither = increment_ordered2_dither;
654    }
655    else if(!strcasecmp(str, "ordered4"))
656    {
657        bitmap->init_dither = init_ordered4_dither;
658        bitmap->get_dither = get_ordered4_dither;
659        bitmap->increment_dither = increment_ordered4_dither;
660    }
661    else if(!strcasecmp(str, "ordered4"))
662    {
663        bitmap->init_dither = init_ordered8_dither;
664        bitmap->get_dither = get_ordered8_dither;
665        bitmap->increment_dither = increment_ordered8_dither;
666    }
667    else if(!strcasecmp(str, "random"))
668    {
669        bitmap->init_dither = init_random_dither;
670        bitmap->get_dither = get_random_dither;
671        bitmap->increment_dither = increment_random_dither;
672    }
673    else /* "fstein" is the default */
674    {
675        bitmap->init_dither = init_fstein_dither;
676        bitmap->get_dither = get_fstein_dither;
677        bitmap->increment_dither = increment_fstein_dither;
678    }
679}
680
681/**
682 * \brief Get bitmap dithering methods
683 *
684 * Return a list of available dithering methods for a given bitmap. The list
685 * is a NULL-terminated array of strings, interleaving a string containing
686 * the internal value for the dithering method, to be used with
687 * \e cucul_set_bitmap_dithering(), and a string containing the natural
688 * language description for that dithering method.
689 *
690 * \param bitmap Bitmap object.
691 * \return An array of strings.
692 */
693char const * const *
694    cucul_get_bitmap_dithering_list(struct cucul_bitmap const *bitmap)
695{
696    static char const * const list[] =
697    {
698        "none", "no dithering",
699        "ordered2", "2x2 ordered dithering",
700        "ordered2", "2x2 ordered dithering",
701        "ordered2", "2x2 ordered dithering",
702        "random", "random dithering",
703        "fstein", "Floyd-Steinberg dithering",
704        NULL, NULL
705    };
706
707    return list;
708}
709
710/**
711 * \brief Draw a bitmap on the screen.
712 *
713 * Draw a bitmap at the given coordinates. The bitmap can be of any size and
714 * will be stretched to the text area.
715 *
716 * \param x1 X coordinate of the upper-left corner of the drawing area.
717 * \param y1 Y coordinate of the upper-left corner of the drawing area.
718 * \param x2 X coordinate of the lower-right corner of the drawing area.
719 * \param y2 Y coordinate of the lower-right corner of the drawing area.
720 * \param bitmap Bitmap object to be drawn.
721 * \param pixels Bitmap's pixels.
722 */
723void cucul_draw_bitmap(cucul_t *qq, int x1, int y1, int x2, int y2,
724                       struct cucul_bitmap const *bitmap, void *pixels)
725{
726    int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
727    int fs_length;
728    int x, y, w, h, pitch, deltax, deltay;
729    unsigned int dchmax;
730
731    if(!bitmap || !pixels)
732        return;
733
734    w = bitmap->w;
735    h = bitmap->h;
736    pitch = bitmap->pitch;
737
738    if(x1 > x2)
739    {
740        int tmp = x2; x2 = x1; x1 = tmp;
741    }
742
743    if(y1 > y2)
744    {
745        int tmp = y2; y2 = y1; y1 = tmp;
746    }
747
748    deltax = x2 - x1 + 1;
749    deltay = y2 - y1 + 1;
750    dchmax = bitmap->glyph_count;
751
752    fs_length = ((int)qq->width <= x2 ? (int)qq->width : x2) + 1;
753    floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
754    memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
755    fs_r = floyd_steinberg + 1;
756    fs_g = fs_r + fs_length + 2;
757    fs_b = fs_g + fs_length + 2;
758
759    for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)qq->height; y++)
760    {
761        int remain_r = 0, remain_g = 0, remain_b = 0;
762
763        for(x = x1 > 0 ? x1 : 0, bitmap->init_dither(y);
764            x <= x2 && x <= (int)qq->width;
765            x++)
766    {
767        unsigned int i;
768        int ch = 0, distmin;
769        unsigned int rgba[4];
770        int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
771        int fromx, fromy, tox, toy, myx, myy, dots, dist;
772        int error[3];
773
774        unsigned int outfg = 0, outbg = 0;
775        char const *outch;
776
777        rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
778
779        /* First get RGB */
780        if(bitmap->antialias)
781        {
782            fromx = (x - x1) * w / deltax;
783            fromy = (y - y1) * h / deltay;
784            tox = (x - x1 + 1) * w / deltax;
785            toy = (y - y1 + 1) * h / deltay;
786
787            /* We want at least one pixel */
788            if(tox == fromx) tox++;
789            if(toy == fromy) toy++;
790
791            dots = 0;
792
793            for(myx = fromx; myx < tox; myx++)
794                for(myy = fromy; myy < toy; myy++)
795            {
796                dots++;
797                get_rgba_default(bitmap, pixels, myx, myy, rgba);
798            }
799
800            /* Normalize */
801            rgba[0] /= dots;
802            rgba[1] /= dots;
803            rgba[2] /= dots;
804            rgba[3] /= dots;
805        }
806        else
807        {
808            fromx = (x - x1) * w / deltax;
809            fromy = (y - y1) * h / deltay;
810            tox = (x - x1 + 1) * w / deltax;
811            toy = (y - y1 + 1) * h / deltay;
812
813            /* tox and toy can overflow the screen, but they cannot overflow
814             * when averaged with fromx and fromy because these are guaranteed
815             * to be within the pixel boundaries. */
816            myx = (fromx + tox) / 2;
817            myy = (fromy + toy) / 2;
818
819            get_rgba_default(bitmap, pixels, myx, myy, rgba);
820        }
821
822        if(bitmap->has_alpha && rgba[3] < 0x800)
823        {
824            remain_r = remain_g = remain_b = 0;
825            fs_r[x] = 0;
826            fs_g[x] = 0;
827            fs_b[x] = 0;
828            continue;
829        }
830
831        /* XXX: OMG HAX */
832        if(bitmap->init_dither == init_fstein_dither)
833        {
834            rgba[0] += remain_r;
835            rgba[1] += remain_g;
836            rgba[2] += remain_b;
837        }
838        else
839        {
840            rgba[0] += (bitmap->get_dither() - 0x80) * 4;
841            rgba[1] += (bitmap->get_dither() - 0x80) * 4;
842            rgba[2] += (bitmap->get_dither() - 0x80) * 4;
843        }
844
845        distmin = INT_MAX;
846        for(i = 0; i < 16; i++)
847        {
848            dist = sq(rgba[0] - rgb_palette[i * 3])
849                 + sq(rgba[1] - rgb_palette[i * 3 + 1])
850                 + sq(rgba[2] - rgb_palette[i * 3 + 2]);
851            dist *= rgb_weight[i];
852            if(dist < distmin)
853            {
854                outbg = i;
855                distmin = dist;
856            }
857        }
858        bg_r = rgb_palette[outbg * 3];
859        bg_g = rgb_palette[outbg * 3 + 1];
860        bg_b = rgb_palette[outbg * 3 + 2];
861
862        /* FIXME: we currently only honour "full16" */
863        if(bitmap->color_mode == COLOR_MODE_FULL16)
864        {
865            distmin = INT_MAX;
866            for(i = 0; i < 16; i++)
867            {
868                if(i == outbg)
869                    continue;
870                dist = sq(rgba[0] - rgb_palette[i * 3])
871                     + sq(rgba[1] - rgb_palette[i * 3 + 1])
872                     + sq(rgba[2] - rgb_palette[i * 3 + 2]);
873                dist *= rgb_weight[i];
874                if(dist < distmin)
875                {
876                    outfg = i;
877                    distmin = dist;
878                }
879            }
880            fg_r = rgb_palette[outfg * 3];
881            fg_g = rgb_palette[outfg * 3 + 1];
882            fg_b = rgb_palette[outfg * 3 + 2];
883
884            distmin = INT_MAX;
885            for(i = 0; i < dchmax - 1; i++)
886            {
887                int newr = i * fg_r + ((2*dchmax-1) - i) * bg_r;
888                int newg = i * fg_g + ((2*dchmax-1) - i) * bg_g;
889                int newb = i * fg_b + ((2*dchmax-1) - i) * bg_b;
890                dist = abs(rgba[0] * (2*dchmax-1) - newr)
891                     + abs(rgba[1] * (2*dchmax-1) - newg)
892                     + abs(rgba[2] * (2*dchmax-1) - newb);
893
894                if(dist < distmin)
895                {
896                    ch = i;
897                    distmin = dist;
898                }
899            }
900            outch = bitmap->glyphs[ch];
901
902            /* XXX: OMG HAX */
903            if(bitmap->init_dither == init_fstein_dither)
904            {
905                error[0] = rgba[0] - (fg_r * ch + bg_r * ((2*dchmax-1) - ch)) / (2*dchmax-1);
906                error[1] = rgba[1] - (fg_g * ch + bg_g * ((2*dchmax-1) - ch)) / (2*dchmax-1);
907                error[2] = rgba[2] - (fg_b * ch + bg_b * ((2*dchmax-1) - ch)) / (2*dchmax-1);
908            }
909        }
910        else
911        {
912            unsigned int lum = rgba[0];
913            if(rgba[1] > lum) lum = rgba[1];
914            if(rgba[2] > lum) lum = rgba[2];
915            outfg = outbg;
916            outbg = CUCUL_COLOR_BLACK;
917
918            ch = lum * dchmax / 0x1000;
919            if(ch < 0)
920                ch = 0;
921            else if(ch > (int)(dchmax - 1))
922                ch = dchmax - 1;
923            outch = bitmap->glyphs[ch];
924
925            /* XXX: OMG HAX */
926            if(bitmap->init_dither == init_fstein_dither)
927            {
928                error[0] = rgba[0] - bg_r * ch / (dchmax-1);
929                error[1] = rgba[1] - bg_g * ch / (dchmax-1);
930                error[2] = rgba[2] - bg_b * ch / (dchmax-1);
931            }
932        }
933
934        /* XXX: OMG HAX */
935        if(bitmap->init_dither == init_fstein_dither)
936        {
937            remain_r = fs_r[x+1] + 7 * error[0] / 16;
938            remain_g = fs_g[x+1] + 7 * error[1] / 16;
939            remain_b = fs_b[x+1] + 7 * error[2] / 16;
940            fs_r[x-1] += 3 * error[0] / 16;
941            fs_g[x-1] += 3 * error[1] / 16;
942            fs_b[x-1] += 3 * error[2] / 16;
943            fs_r[x] = 5 * error[0] / 16;
944            fs_g[x] = 5 * error[1] / 16;
945            fs_b[x] = 5 * error[2] / 16;
946            fs_r[x+1] = 1 * error[0] / 16;
947            fs_g[x+1] = 1 * error[1] / 16;
948            fs_b[x+1] = 1 * error[2] / 16;
949        }
950
951        if(bitmap->invert)
952        {
953            outfg = 15 - outfg;
954            outbg = 15 - outbg;
955        }
956
957        /* Now output the character */
958        cucul_set_color(qq, outfg, outbg);
959        cucul_putstr(qq, x, y, outch);
960
961       bitmap->increment_dither();
962    }
963        /* end loop */
964    }
965
966    free(floyd_steinberg);
967}
968
969/**
970 * \brief Free the memory associated with a bitmap.
971 *
972 * Free the memory allocated by cucul_create_bitmap().
973 *
974 * \param bitmap Bitmap object.
975 */
976void cucul_free_bitmap(struct cucul_bitmap *bitmap)
977{
978    if(!bitmap)
979        return;
980
981    free(bitmap);
982}
983
984/*
985 * XXX: The following functions are local.
986 */
987
988/* Convert a mask, eg. 0x0000ff00, to shift values, eg. 8 and -4. */
989static void mask2shift(unsigned int mask, int *right, int *left)
990{
991    int rshift = 0, lshift = 0;
992
993    if(!mask)
994    {
995        *right = *left = 0;
996        return;
997    }
998
999    while(!(mask & 1))
1000    {
1001        mask >>= 1;
1002        rshift++;
1003    }
1004    *right = rshift;
1005
1006    while(mask & 1)
1007    {
1008        mask >>= 1;
1009        lshift++;
1010    }
1011    *left = 12 - lshift;
1012}
1013
1014/* Compute x^y without relying on the math library */
1015static float gammapow(float x, float y)
1016{
1017#ifdef HAVE_FLDLN2
1018    register double logx;
1019    register long double v, e;
1020#else
1021    register float tmp, t, t2, r;
1022    int i;
1023#endif
1024
1025    if(x == 0.0)
1026        return y == 0.0 ? 1.0 : 0.0;
1027
1028#ifdef HAVE_FLDLN2
1029    /* FIXME: this can be optimised by directly calling fyl2x for x and y */
1030    asm volatile("fldln2; fxch; fyl2x"
1031                 : "=t" (logx) : "0" (x) : "st(1)");
1032
1033    asm volatile("fldl2e\n\t"
1034                 "fmul %%st(1)\n\t"
1035                 "fst %%st(1)\n\t"
1036                 "frndint\n\t"
1037                 "fxch\n\t"
1038                 "fsub %%st(1)\n\t"
1039                 "f2xm1\n\t"
1040                 : "=t" (v), "=u" (e) : "0" (y * logx));
1041    v += 1.0;
1042    asm volatile("fscale"
1043                 : "=t" (v) : "0" (v), "u" (e));
1044    return v;
1045#else
1046    /* Compute ln(x) for x ∈ ]0,1]
1047     *   ln(x) = 2 * (t + t^3/3 + t^5/5 + ...) with t = (x-1)/(x+1)
1048     * The convergence is a bit slow, especially when x is near 0. */
1049    t = (x - 1.0) / (x + 1.0);
1050    t2 = t * t;
1051    tmp = r = t;
1052    for(i = 3; i < 20; i += 2)
1053    {
1054        r *= t2;
1055        tmp += r / i;
1056    }
1057
1058    /* Compute -y*ln(x) */
1059    tmp = - y * 2.0 * tmp;
1060
1061    /* Compute x^-y as e^t where t = -y*ln(x):
1062     *   e^t = 1 + t/1! + t^2/2! + t^3/3! + t^4/4! + t^5/5! ...
1063     * The convergence is quite faster here, thanks to the factorial. */
1064    r = t = tmp;
1065    tmp = 1.0 + t;
1066    for(i = 2; i < 16; i++)
1067    {
1068        r = r * t / i;
1069        tmp += r;
1070    }
1071
1072    /* Return x^y as 1/(x^-y) */
1073    return 1.0 / tmp;
1074#endif
1075}
1076
1077static void get_rgba_default(struct cucul_bitmap const *bitmap, uint8_t *pixels,
1078                             int x, int y, unsigned int *rgba)
1079{
1080    uint32_t bits;
1081
1082    pixels += (bitmap->bpp / 8) * x + bitmap->pitch * y;
1083
1084    switch(bitmap->bpp / 8)
1085    {
1086        case 4:
1087            bits = *(uint32_t *)pixels;
1088            break;
1089        case 3:
1090        {
1091#if defined(HAVE_ENDIAN_H)
1092            if(__BYTE_ORDER == __BIG_ENDIAN)
1093#else
1094            /* This is compile-time optimised with at least -O1 or -Os */
1095            uint32_t const rmask = 0x12345678;
1096            if(*(uint8_t const *)&rmask == 0x12)
1097#endif
1098                bits = ((uint32_t)pixels[0] << 16) |
1099                       ((uint32_t)pixels[1] << 8) |
1100                       ((uint32_t)pixels[2]);
1101            else
1102                bits = ((uint32_t)pixels[2] << 16) |
1103                       ((uint32_t)pixels[1] << 8) |
1104                       ((uint32_t)pixels[0]);
1105            break;
1106        }
1107        case 2:
1108            bits = *(uint16_t *)pixels;
1109            break;
1110        case 1:
1111        default:
1112            bits = pixels[0];
1113            break;
1114    }
1115
1116    if(bitmap->has_palette)
1117    {
1118        rgba[0] += bitmap->gammatab[bitmap->red[bits]];
1119        rgba[1] += bitmap->gammatab[bitmap->green[bits]];
1120        rgba[2] += bitmap->gammatab[bitmap->blue[bits]];
1121        rgba[3] += bitmap->alpha[bits];
1122    }
1123    else
1124    {
1125        rgba[0] += bitmap->gammatab[((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft];
1126        rgba[1] += bitmap->gammatab[((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft];
1127        rgba[2] += bitmap->gammatab[((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft];
1128        rgba[3] += ((bits & bitmap->amask) >> bitmap->aright) << bitmap->aleft;
1129    }
1130}
1131
1132/*
1133 * No dithering
1134 */
1135static void init_no_dither(int line)
1136{
1137    ;
1138}
1139
1140static unsigned int get_no_dither(void)
1141{
1142    return 0x80;
1143}
1144
1145static void increment_no_dither(void)
1146{
1147    return;
1148}
1149
1150/*
1151 * Floyd-Steinberg dithering
1152 */
1153static void init_fstein_dither(int line)
1154{
1155    ;
1156}
1157
1158static unsigned int get_fstein_dither(void)
1159{
1160    return 0x80;
1161}
1162
1163static void increment_fstein_dither(void)
1164{
1165    return;
1166}
1167
1168/*
1169 * Ordered 2 dithering
1170 */
1171static unsigned int const *ordered2_table;
1172static unsigned int ordered2_index;
1173
1174static void init_ordered2_dither(int line)
1175{
1176    static unsigned int const dither2x2[] =
1177    {
1178        0x00, 0x80,
1179        0xc0, 0x40,
1180    };
1181
1182    ordered2_table = dither2x2 + (line % 2) * 2;
1183    ordered2_index = 0;
1184}
1185
1186static unsigned int get_ordered2_dither(void)
1187{
1188    return ordered2_table[ordered2_index];
1189}
1190
1191static void increment_ordered2_dither(void)
1192{
1193    ordered2_index = (ordered2_index + 1) % 2;
1194}
1195
1196/*
1197 * Ordered 4 dithering
1198 */
1199/*static int dither4x4[] = { 5,  0,  1,  6,
1200                          -1, -6, -5,  2,
1201                          -2, -7, -8,  3,
1202                           4, -3, -4, -7};*/
1203static unsigned int const *ordered4_table;
1204static unsigned int ordered4_index;
1205
1206static void init_ordered4_dither(int line)
1207{
1208    static unsigned int const dither4x4[] =
1209    {
1210        0x00, 0x80, 0x20, 0xa0,
1211        0xc0, 0x40, 0xe0, 0x60,
1212        0x30, 0xb0, 0x10, 0x90,
1213        0xf0, 0x70, 0xd0, 0x50
1214    };
1215
1216    ordered4_table = dither4x4 + (line % 4) * 4;
1217    ordered4_index = 0;
1218}
1219
1220static unsigned int get_ordered4_dither(void)
1221{
1222    return ordered4_table[ordered4_index];
1223}
1224
1225static void increment_ordered4_dither(void)
1226{
1227    ordered4_index = (ordered4_index + 1) % 4;
1228}
1229
1230/*
1231 * Ordered 8 dithering
1232 */
1233static unsigned int const *ordered8_table;
1234static unsigned int ordered8_index;
1235
1236static void init_ordered8_dither(int line)
1237{
1238    static unsigned int const dither8x8[] =
1239    {
1240        0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1241        0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
1242        0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
1243        0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
1244        0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
1245        0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
1246        0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
1247        0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
1248    };
1249
1250    ordered8_table = dither8x8 + (line % 8) * 8;
1251    ordered8_index = 0;
1252}
1253
1254static unsigned int get_ordered8_dither(void)
1255{
1256    return ordered8_table[ordered8_index];
1257}
1258
1259static void increment_ordered8_dither(void)
1260{
1261    ordered8_index = (ordered8_index + 1) % 8;
1262}
1263
1264/*
1265 * Random dithering
1266 */
1267static void init_random_dither(int line)
1268{
1269    ;
1270}
1271
1272static unsigned int get_random_dither(void)
1273{
1274    return cucul_rand(0x00, 0xff);
1275}
1276
1277static void increment_random_dither(void)
1278{
1279    return;
1280}
1281
1282#if !defined(_DOXYGEN_SKIP_ME)
1283int _cucul_init_bitmap(void)
1284{
1285    unsigned int v, s, h;
1286
1287    /* These ones are constant */
1288    lookup_colors[0] = CUCUL_COLOR_BLACK;
1289    lookup_colors[1] = CUCUL_COLOR_DARKGRAY;
1290    lookup_colors[2] = CUCUL_COLOR_LIGHTGRAY;
1291    lookup_colors[3] = CUCUL_COLOR_WHITE;
1292
1293    /* These ones will be overwritten */
1294    lookup_colors[4] = CUCUL_COLOR_MAGENTA;
1295    lookup_colors[5] = CUCUL_COLOR_LIGHTMAGENTA;
1296    lookup_colors[6] = CUCUL_COLOR_RED;
1297    lookup_colors[7] = CUCUL_COLOR_LIGHTRED;
1298
1299    for(v = 0; v < LOOKUP_VAL; v++)
1300        for(s = 0; s < LOOKUP_SAT; s++)
1301            for(h = 0; h < LOOKUP_HUE; h++)
1302    {
1303        int i, distbg, distfg, dist;
1304        int val, sat, hue;
1305        unsigned char outbg, outfg;
1306
1307        val = 0xfff * v / (LOOKUP_VAL - 1);
1308        sat = 0xfff * s / (LOOKUP_SAT - 1);
1309        hue = 0xfff * h / (LOOKUP_HUE - 1);
1310
1311        /* Initialise distances to the distance between pure black HSV
1312         * coordinates and our white colour (3) */
1313        outbg = outfg = 3;
1314        distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
1315
1316        /* Calculate distances to eight major colour values and store the
1317         * two nearest points in our lookup table. */
1318        for(i = 0; i < 8; i++)
1319        {
1320            dist = HSV_DISTANCE(hue, sat, val, i);
1321            if(dist <= distbg)
1322            {
1323                outfg = outbg;
1324                distfg = distbg;
1325                outbg = i;
1326                distbg = dist;
1327            }
1328            else if(dist <= distfg)
1329            {
1330                outfg = i;
1331                distfg = dist;
1332            }
1333        }
1334
1335        hsv_distances[v][s][h] = (outfg << 4) | outbg;
1336    }
1337
1338    return 0;
1339}
1340
1341int _cucul_end_bitmap(void)
1342{
1343    return 0;
1344}
1345#endif /* _DOXYGEN_SKIP_ME */
1346
1347
Note: See TracBrowser for help on using the repository browser.