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

Last change on this file since 715 was 715, checked in by Sam Hocevar, 16 years ago
  • Set the default dithering mode to Floyd-Steinberg.
  • Property svn:keywords set to Id
File size: 35.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 715 2006-04-01 15:58:10Z 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 enum cucul_color 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 Set the contrast of a bitmap object.
406 *
407 * Set the contrast of bitmap.
408 *
409 * \param bitmap Bitmap object.
410 * \param contrast contrast value.
411 */
412void cucul_set_bitmap_contrast(struct cucul_bitmap *bitmap, float contrast)
413{
414    /* FIXME */
415}
416
417/**
418 * \brief Set bitmap antialiasing
419 *
420 * Tell the renderer whether to antialias the bitmap. Antialiasing smoothen
421 * the rendered image and avoids the commonly seen staircase effect. The
422 * method used is a simple prefilter antialiasing.
423 *
424 * \param bitmap Bitmap object.
425 * \param value 0 to disable antialiasing, 1 to activate it.
426 */
427void cucul_set_bitmap_antialias(struct cucul_bitmap *bitmap, int value)
428{
429    bitmap->antialias = value ? 1 : 0;
430}
431
432/**
433 * \brief Invert colors of bitmap
434 *
435 * Invert colors of bitmap
436 *
437 * \param bitmap Bitmap object.
438 * \param value 0 for normal behaviour, 1 for invert
439 */
440void cucul_set_bitmap_invert(struct cucul_bitmap *bitmap, int value)
441{
442    bitmap->invert = value ? 1 : 0;
443}
444
445/**
446 * \brief Choose colours used for bitmap rendering
447 *
448 * Tell the renderer which colours should be used to render the
449 * bitmap. Valid values for \e str are:
450 *
451 * \li \e "mono": use light gray on a black background.
452 *
453 * \li \e "gray": use white and two shades of gray on a black background.
454 *
455 * \li \e "8": use the 8 ANSI colours on a black background.
456 *
457 * \li \e "16": use the 16 ANSI colours on a black background.
458 *
459 * \li \e "fullgray": use black, white and two shades of gray for both the
460 *     characters and the background.
461 *
462 * \li \e "full8": use the 8 ANSI colours for both the characters and the
463 *     background.
464 *
465 * \li \e "full16": use the 16 ANSI colours for both the characters and the
466 *     background. This is the default value.
467 *
468 * \param bitmap Bitmap object.
469 * \param str A string describing the colour set that will be used
470 *        for the bitmap rendering.
471 */
472void cucul_set_bitmap_color(struct cucul_bitmap *bitmap, char const *str)
473{
474    if(!strcasecmp(str, "mono"))
475        bitmap->color_mode = COLOR_MODE_MONO;
476    else if(!strcasecmp(str, "gray"))
477        bitmap->color_mode = COLOR_MODE_GRAY;
478    else if(!strcasecmp(str, "8"))
479        bitmap->color_mode = COLOR_MODE_8;
480    else if(!strcasecmp(str, "16"))
481        bitmap->color_mode = COLOR_MODE_16;
482    else if(!strcasecmp(str, "fullgray"))
483        bitmap->color_mode = COLOR_MODE_FULLGRAY;
484    else if(!strcasecmp(str, "full8"))
485        bitmap->color_mode = COLOR_MODE_FULL8;
486    else /* "full16" is the default */
487        bitmap->color_mode = COLOR_MODE_FULL16;
488}
489
490/**
491 * \brief Get available colour modes
492 *
493 * Return a list of available colour modes for a given bitmap. The list
494 * is a NULL-terminated array of strings, interleaving a string containing
495 * the internal value for the colour mode, to be used with
496 * \e cucul_set_bitmap_color(), and a string containing the natural
497 * language description for that colour mode.
498 *
499 * \param bitmap Bitmap object.
500 * \return An array of strings.
501 */
502char const * const *
503    cucul_get_bitmap_color_list(struct cucul_bitmap const *bitmap)
504{
505    static char const * const list[] =
506    {
507        "mono", "white on black",
508        "gray", "grayscale on black",
509        "8", "8 colours on black",
510        "16", "16 colours on black",
511        "fullgray", "full grayscale",
512        "full8", "full 8 colours",
513        "full16", "full 16 colours",
514        NULL, NULL
515    };
516
517    return list;
518}
519
520/**
521 * \brief Choose characters used for bitmap rendering
522 *
523 * Tell the renderer which characters should be used to render the
524 * bitmap. Valid values for \e str are:
525 *
526 * \li \e "ascii": use only ASCII characters. This is the default value.
527 *
528 * \li \e "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592
529 *     MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also
530 *     present in the CP437 codepage available on DOS and VGA.
531 *
532 * \li \e "blocks": use Unicode quarter-cell block combinations. These
533 *     characters are only found in the Unicode set.
534 *
535 * \param bitmap Bitmap object.
536 * \param str A string describing the characters that need to be used
537 *        for the bitmap rendering.
538 */
539void cucul_set_bitmap_charset(struct cucul_bitmap *bitmap, char const *str)
540{
541    if(!strcasecmp(str, "shades"))
542    {
543        bitmap->glyphs = shades_glyphs;
544        bitmap->glyph_count = sizeof(shades_glyphs) / sizeof(*shades_glyphs);
545    }
546    else if(!strcasecmp(str, "blocks"))
547    {
548        bitmap->glyphs = blocks_glyphs;
549        bitmap->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
550    }
551    else /* "ascii" is the default */
552    {
553        bitmap->glyphs = ascii_glyphs;
554        bitmap->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
555    }
556}
557
558/**
559 * \brief Get available bitmap character sets
560 *
561 * Return a list of available character sets for a given bitmap. The list
562 * is a NULL-terminated array of strings, interleaving a string containing
563 * the internal value for the character set, to be used with
564 * \e cucul_set_bitmap_charset(), and a string containing the natural
565 * language description for that character set.
566 *
567 * \param bitmap Bitmap object.
568 * \return An array of strings.
569 */
570char const * const *
571    cucul_get_bitmap_charset_list(struct cucul_bitmap const *bitmap)
572{
573    static char const * const list[] =
574    {
575        "ascii", "plain ASCII",
576        "shades", "CP437 shades",
577        "blocks", "Unicode blocks",
578        NULL, NULL
579    };
580
581    return list;
582}
583
584/**
585 * \brief Set bitmap dithering method
586 *
587 * Tell the renderer which dithering method should be used to render the
588 * bitmap. Dithering is necessary because the picture being rendered has
589 * usually far more colours than the available palette. Valid values for
590 * \e str are:
591 *
592 * \li \e "none": no dithering is used, the nearest matching colour is used.
593 *
594 * \li \e "ordered2": use a 2x2 Bayer matrix for dithering.
595 *
596 * \li \e "ordered4": use a 4x4 Bayer matrix for dithering.
597 *
598 * \li \e "ordered8": use a 8x8 Bayer matrix for dithering.
599 *
600 * \li \e "random": use random dithering.
601 *
602 * \li \e "fstein": use Floyd-Steinberg dithering. This is the default value.
603 *
604 * \param bitmap Bitmap object.
605 * \param str A string describing the dithering method that needs to be used
606 *        for the bitmap rendering.
607 */
608void cucul_set_bitmap_dithering(struct cucul_bitmap *bitmap, char const *str)
609{
610    if(!strcasecmp(str, "none"))
611    {
612        bitmap->init_dither = init_no_dither;
613        bitmap->get_dither = get_no_dither;
614        bitmap->increment_dither = increment_no_dither;
615    }
616    else if(!strcasecmp(str, "ordered2"))
617    {
618        bitmap->init_dither = init_ordered2_dither;
619        bitmap->get_dither = get_ordered2_dither;
620        bitmap->increment_dither = increment_ordered2_dither;
621    }
622    else if(!strcasecmp(str, "ordered4"))
623    {
624        bitmap->init_dither = init_ordered4_dither;
625        bitmap->get_dither = get_ordered4_dither;
626        bitmap->increment_dither = increment_ordered4_dither;
627    }
628    else if(!strcasecmp(str, "ordered4"))
629    {
630        bitmap->init_dither = init_ordered8_dither;
631        bitmap->get_dither = get_ordered8_dither;
632        bitmap->increment_dither = increment_ordered8_dither;
633    }
634    else if(!strcasecmp(str, "random"))
635    {
636        bitmap->init_dither = init_random_dither;
637        bitmap->get_dither = get_random_dither;
638        bitmap->increment_dither = increment_random_dither;
639    }
640    else /* "fstein" is the default */
641    {
642        bitmap->init_dither = init_fstein_dither;
643        bitmap->get_dither = get_fstein_dither;
644        bitmap->increment_dither = increment_fstein_dither;
645    }
646}
647
648/**
649 * \brief Get bitmap dithering methods
650 *
651 * Return a list of available dithering methods for a given bitmap. The list
652 * is a NULL-terminated array of strings, interleaving a string containing
653 * the internal value for the dithering method, to be used with
654 * \e cucul_set_bitmap_dithering(), and a string containing the natural
655 * language description for that dithering method.
656 *
657 * \param bitmap Bitmap object.
658 * \return An array of strings.
659 */
660char const * const *
661    cucul_get_bitmap_dithering_list(struct cucul_bitmap const *bitmap)
662{
663    static char const * const list[] =
664    {
665        "none", "no dithering",
666        "ordered2", "2x2 ordered dithering",
667        "ordered2", "2x2 ordered dithering",
668        "ordered2", "2x2 ordered dithering",
669        "random", "random dithering",
670        "fstein", "Floyd-Steinberg dithering",
671        NULL, NULL
672    };
673
674    return list;
675}
676
677/**
678 * \brief Draw a bitmap on the screen.
679 *
680 * Draw a bitmap at the given coordinates. The bitmap can be of any size and
681 * will be stretched to the text area.
682 *
683 * \param x1 X coordinate of the upper-left corner of the drawing area.
684 * \param y1 Y coordinate of the upper-left corner of the drawing area.
685 * \param x2 X coordinate of the lower-right corner of the drawing area.
686 * \param y2 Y coordinate of the lower-right corner of the drawing area.
687 * \param bitmap Bitmap object to be drawn.
688 * \param pixels Bitmap's pixels.
689 */
690void cucul_draw_bitmap(cucul_t *qq, int x1, int y1, int x2, int y2,
691                       struct cucul_bitmap const *bitmap, void *pixels)
692{
693    int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
694    int fs_length;
695    int x, y, w, h, pitch, deltax, deltay;
696    unsigned int dchmax;
697
698    if(!bitmap || !pixels)
699        return;
700
701    w = bitmap->w;
702    h = bitmap->h;
703    pitch = bitmap->pitch;
704
705    if(x1 > x2)
706    {
707        int tmp = x2; x2 = x1; x1 = tmp;
708    }
709
710    if(y1 > y2)
711    {
712        int tmp = y2; y2 = y1; y1 = tmp;
713    }
714
715    deltax = x2 - x1 + 1;
716    deltay = y2 - y1 + 1;
717    dchmax = bitmap->glyph_count;
718
719    fs_length = ((int)qq->width <= x2 ? (int)qq->width : x2) + 1;
720    floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
721    memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
722    fs_r = floyd_steinberg + 1;
723    fs_g = fs_r + fs_length + 2;
724    fs_b = fs_g + fs_length + 2;
725
726    for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)qq->height; y++)
727    {
728        int remain_r = 0, remain_g = 0, remain_b = 0;
729
730        for(x = x1 > 0 ? x1 : 0, bitmap->init_dither(y);
731            x <= x2 && x <= (int)qq->width;
732            x++)
733    {
734        unsigned int i;
735        int ch = 0, distmin;
736        unsigned int rgba[4];
737        int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
738        int fromx, fromy, tox, toy, myx, myy, dots, dist;
739        int error[3];
740
741        enum cucul_color outfg = 0, outbg = 0;
742        char const *outch;
743
744        rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
745
746        /* First get RGB */
747        if(bitmap->antialias)
748        {
749            fromx = (x - x1) * w / deltax;
750            fromy = (y - y1) * h / deltay;
751            tox = (x - x1 + 1) * w / deltax;
752            toy = (y - y1 + 1) * h / deltay;
753
754            /* We want at least one pixel */
755            if(tox == fromx) tox++;
756            if(toy == fromy) toy++;
757
758            dots = 0;
759
760            for(myx = fromx; myx < tox; myx++)
761                for(myy = fromy; myy < toy; myy++)
762            {
763                dots++;
764                get_rgba_default(bitmap, pixels, myx, myy, rgba);
765            }
766
767            /* Normalize */
768            rgba[0] /= dots;
769            rgba[1] /= dots;
770            rgba[2] /= dots;
771            rgba[3] /= dots;
772        }
773        else
774        {
775            fromx = (x - x1) * w / deltax;
776            fromy = (y - y1) * h / deltay;
777            tox = (x - x1 + 1) * w / deltax;
778            toy = (y - y1 + 1) * h / deltay;
779
780            /* tox and toy can overflow the screen, but they cannot overflow
781             * when averaged with fromx and fromy because these are guaranteed
782             * to be within the pixel boundaries. */
783            myx = (fromx + tox) / 2;
784            myy = (fromy + toy) / 2;
785
786            get_rgba_default(bitmap, pixels, myx, myy, rgba);
787        }
788
789        if(bitmap->has_alpha && rgba[3] < 0x800)
790        {
791            remain_r = remain_g = remain_b = 0;
792            fs_r[x] = 0;
793            fs_g[x] = 0;
794            fs_b[x] = 0;
795            continue;
796        }
797
798        /* XXX: OMG HAX */
799        if(bitmap->init_dither == init_fstein_dither)
800        {
801            rgba[0] += remain_r;
802            rgba[1] += remain_g;
803            rgba[2] += remain_b;
804        }
805        else
806        {
807            rgba[0] += (bitmap->get_dither() - 0x80) * 4;
808            rgba[1] += (bitmap->get_dither() - 0x80) * 4;
809            rgba[2] += (bitmap->get_dither() - 0x80) * 4;
810        }
811
812        distmin = INT_MAX;
813        for(i = 0; i < 16; i++)
814        {
815            dist = sq(rgba[0] - rgb_palette[i * 3])
816                 + sq(rgba[1] - rgb_palette[i * 3 + 1])
817                 + sq(rgba[2] - rgb_palette[i * 3 + 2]);
818            dist *= rgb_weight[i];
819            if(dist < distmin)
820            {
821                outbg = i;
822                distmin = dist;
823            }
824        }
825        bg_r = rgb_palette[outbg * 3];
826        bg_g = rgb_palette[outbg * 3 + 1];
827        bg_b = rgb_palette[outbg * 3 + 2];
828
829        /* FIXME: we currently only honour "full16" */
830        if(bitmap->color_mode == COLOR_MODE_FULL16)
831        {
832            distmin = INT_MAX;
833            for(i = 0; i < 16; i++)
834            {
835                if(i == outbg)
836                    continue;
837                dist = sq(rgba[0] - rgb_palette[i * 3])
838                     + sq(rgba[1] - rgb_palette[i * 3 + 1])
839                     + sq(rgba[2] - rgb_palette[i * 3 + 2]);
840                dist *= rgb_weight[i];
841                if(dist < distmin)
842                {
843                    outfg = i;
844                    distmin = dist;
845                }
846            }
847            fg_r = rgb_palette[outfg * 3];
848            fg_g = rgb_palette[outfg * 3 + 1];
849            fg_b = rgb_palette[outfg * 3 + 2];
850
851            distmin = INT_MAX;
852            for(i = 0; i < dchmax - 1; i++)
853            {
854                int newr = i * fg_r + ((2*dchmax-1) - i) * bg_r;
855                int newg = i * fg_g + ((2*dchmax-1) - i) * bg_g;
856                int newb = i * fg_b + ((2*dchmax-1) - i) * bg_b;
857                dist = abs(rgba[0] * (2*dchmax-1) - newr)
858                     + abs(rgba[1] * (2*dchmax-1) - newg)
859                     + abs(rgba[2] * (2*dchmax-1) - newb);
860
861                if(dist < distmin)
862                {
863                    ch = i;
864                    distmin = dist;
865                }
866            }
867            outch = bitmap->glyphs[ch];
868
869            /* XXX: OMG HAX */
870            if(bitmap->init_dither == init_fstein_dither)
871            {
872                error[0] = rgba[0] - (fg_r * ch + bg_r * ((2*dchmax-1) - ch)) / (2*dchmax-1);
873                error[1] = rgba[1] - (fg_g * ch + bg_g * ((2*dchmax-1) - ch)) / (2*dchmax-1);
874                error[2] = rgba[2] - (fg_b * ch + bg_b * ((2*dchmax-1) - ch)) / (2*dchmax-1);
875            }
876        }
877        else
878        {
879            unsigned int lum = rgba[0];
880            if(rgba[1] > lum) lum = rgba[1];
881            if(rgba[2] > lum) lum = rgba[2];
882            outfg = outbg;
883            outbg = CUCUL_COLOR_BLACK;
884
885            ch = lum * dchmax / 0x1000;
886            if(ch < 0)
887                ch = 0;
888            else if(ch > (int)(dchmax - 1))
889                ch = dchmax - 1;
890            outch = bitmap->glyphs[ch];
891
892            /* XXX: OMG HAX */
893            if(bitmap->init_dither == init_fstein_dither)
894            {
895                error[0] = rgba[0] - bg_r * ch / (dchmax-1);
896                error[1] = rgba[1] - bg_g * ch / (dchmax-1);
897                error[2] = rgba[2] - bg_b * ch / (dchmax-1);
898            }
899        }
900
901        /* XXX: OMG HAX */
902        if(bitmap->init_dither == init_fstein_dither)
903        {
904            remain_r = fs_r[x+1] + 7 * error[0] / 16;
905            remain_g = fs_g[x+1] + 7 * error[1] / 16;
906            remain_b = fs_b[x+1] + 7 * error[2] / 16;
907            fs_r[x-1] += 3 * error[0] / 16;
908            fs_g[x-1] += 3 * error[1] / 16;
909            fs_b[x-1] += 3 * error[2] / 16;
910            fs_r[x] = 5 * error[0] / 16;
911            fs_g[x] = 5 * error[1] / 16;
912            fs_b[x] = 5 * error[2] / 16;
913            fs_r[x+1] = 1 * error[0] / 16;
914            fs_g[x+1] = 1 * error[1] / 16;
915            fs_b[x+1] = 1 * error[2] / 16;
916        }
917
918        if(bitmap->invert)
919        {
920            outfg = 15 - outfg;
921            outbg = 15 - outbg;
922        }
923
924        /* Now output the character */
925        cucul_set_color(qq, outfg, outbg);
926        cucul_putstr(qq, x, y, outch);
927
928       bitmap->increment_dither();
929    }
930        /* end loop */
931    }
932
933    free(floyd_steinberg);
934}
935
936/**
937 * \brief Free the memory associated with a bitmap.
938 *
939 * Free the memory allocated by cucul_create_bitmap().
940 *
941 * \param bitmap Bitmap object.
942 */
943void cucul_free_bitmap(struct cucul_bitmap *bitmap)
944{
945    if(!bitmap)
946        return;
947
948    free(bitmap);
949}
950
951/*
952 * XXX: The following functions are local.
953 */
954
955/* Convert a mask, eg. 0x0000ff00, to shift values, eg. 8 and -4. */
956static void mask2shift(unsigned int mask, int *right, int *left)
957{
958    int rshift = 0, lshift = 0;
959
960    if(!mask)
961    {
962        *right = *left = 0;
963        return;
964    }
965
966    while(!(mask & 1))
967    {
968        mask >>= 1;
969        rshift++;
970    }
971    *right = rshift;
972
973    while(mask & 1)
974    {
975        mask >>= 1;
976        lshift++;
977    }
978    *left = 12 - lshift;
979}
980
981/* Compute x^y without relying on the math library */
982static float gammapow(float x, float y)
983{
984#ifdef HAVE_FLDLN2
985    register double logx;
986    register long double v, e;
987#else
988    register float tmp, t, t2, r;
989    int i;
990#endif
991
992    if(x == 0.0)
993        return y == 0.0 ? 1.0 : 0.0;
994
995#ifdef HAVE_FLDLN2
996    /* FIXME: this can be optimised by directly calling fyl2x for x and y */
997    asm volatile("fldln2; fxch; fyl2x"
998                 : "=t" (logx) : "0" (x) : "st(1)");
999
1000    asm volatile("fldl2e\n\t"
1001                 "fmul %%st(1)\n\t"
1002                 "fst %%st(1)\n\t"
1003                 "frndint\n\t"
1004                 "fxch\n\t"
1005                 "fsub %%st(1)\n\t"
1006                 "f2xm1\n\t"
1007                 : "=t" (v), "=u" (e) : "0" (y * logx));
1008    v += 1.0;
1009    asm volatile("fscale"
1010                 : "=t" (v) : "0" (v), "u" (e));
1011    return v;
1012#else
1013    /* Compute ln(x) for x ∈ ]0,1]
1014     *   ln(x) = 2 * (t + t^3/3 + t^5/5 + ...) with t = (x-1)/(x+1)
1015     * The convergence is a bit slow, especially when x is near 0. */
1016    t = (x - 1.0) / (x + 1.0);
1017    t2 = t * t;
1018    tmp = r = t;
1019    for(i = 3; i < 20; i += 2)
1020    {
1021        r *= t2;
1022        tmp += r / i;
1023    }
1024
1025    /* Compute -y*ln(x) */
1026    tmp = - y * 2.0 * tmp;
1027
1028    /* Compute x^-y as e^t where t = -y*ln(x):
1029     *   e^t = 1 + t/1! + t^2/2! + t^3/3! + t^4/4! + t^5/5! ...
1030     * The convergence is quite faster here, thanks to the factorial. */
1031    r = t = tmp;
1032    tmp = 1.0 + t;
1033    for(i = 2; i < 16; i++)
1034    {
1035        r = r * t / i;
1036        tmp += r;
1037    }
1038
1039    /* Return x^y as 1/(x^-y) */
1040    return 1.0 / tmp;
1041#endif
1042}
1043
1044static void get_rgba_default(struct cucul_bitmap const *bitmap, uint8_t *pixels,
1045                             int x, int y, unsigned int *rgba)
1046{
1047    uint32_t bits;
1048
1049    pixels += (bitmap->bpp / 8) * x + bitmap->pitch * y;
1050
1051    switch(bitmap->bpp / 8)
1052    {
1053        case 4:
1054            bits = *(uint32_t *)pixels;
1055            break;
1056        case 3:
1057        {
1058#if defined(HAVE_ENDIAN_H)
1059            if(__BYTE_ORDER == __BIG_ENDIAN)
1060#else
1061            /* This is compile-time optimised with at least -O1 or -Os */
1062            uint32_t const rmask = 0x12345678;
1063            if(*(uint8_t const *)&rmask == 0x12)
1064#endif
1065                bits = ((uint32_t)pixels[0] << 16) |
1066                       ((uint32_t)pixels[1] << 8) |
1067                       ((uint32_t)pixels[2]);
1068            else
1069                bits = ((uint32_t)pixels[2] << 16) |
1070                       ((uint32_t)pixels[1] << 8) |
1071                       ((uint32_t)pixels[0]);
1072            break;
1073        }
1074        case 2:
1075            bits = *(uint16_t *)pixels;
1076            break;
1077        case 1:
1078        default:
1079            bits = pixels[0];
1080            break;
1081    }
1082
1083    if(bitmap->has_palette)
1084    {
1085        rgba[0] += bitmap->gammatab[bitmap->red[bits]];
1086        rgba[1] += bitmap->gammatab[bitmap->green[bits]];
1087        rgba[2] += bitmap->gammatab[bitmap->blue[bits]];
1088        rgba[3] += bitmap->alpha[bits];
1089    }
1090    else
1091    {
1092        rgba[0] += bitmap->gammatab[((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft];
1093        rgba[1] += bitmap->gammatab[((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft];
1094        rgba[2] += bitmap->gammatab[((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft];
1095        rgba[3] += ((bits & bitmap->amask) >> bitmap->aright) << bitmap->aleft;
1096    }
1097}
1098
1099/*
1100 * No dithering
1101 */
1102static void init_no_dither(int line)
1103{
1104    ;
1105}
1106
1107static unsigned int get_no_dither(void)
1108{
1109    return 0x80;
1110}
1111
1112static void increment_no_dither(void)
1113{
1114    return;
1115}
1116
1117/*
1118 * Floyd-Steinberg dithering
1119 */
1120static void init_fstein_dither(int line)
1121{
1122    ;
1123}
1124
1125static unsigned int get_fstein_dither(void)
1126{
1127    return 0x80;
1128}
1129
1130static void increment_fstein_dither(void)
1131{
1132    return;
1133}
1134
1135/*
1136 * Ordered 2 dithering
1137 */
1138static unsigned int const *ordered2_table;
1139static unsigned int ordered2_index;
1140
1141static void init_ordered2_dither(int line)
1142{
1143    static unsigned int const dither2x2[] =
1144    {
1145        0x00, 0x80,
1146        0xc0, 0x40,
1147    };
1148
1149    ordered2_table = dither2x2 + (line % 2) * 2;
1150    ordered2_index = 0;
1151}
1152
1153static unsigned int get_ordered2_dither(void)
1154{
1155    return ordered2_table[ordered2_index];
1156}
1157
1158static void increment_ordered2_dither(void)
1159{
1160    ordered2_index = (ordered2_index + 1) % 2;
1161}
1162
1163/*
1164 * Ordered 4 dithering
1165 */
1166/*static int dither4x4[] = { 5,  0,  1,  6,
1167                          -1, -6, -5,  2,
1168                          -2, -7, -8,  3,
1169                           4, -3, -4, -7};*/
1170static unsigned int const *ordered4_table;
1171static unsigned int ordered4_index;
1172
1173static void init_ordered4_dither(int line)
1174{
1175    static unsigned int const dither4x4[] =
1176    {
1177        0x00, 0x80, 0x20, 0xa0,
1178        0xc0, 0x40, 0xe0, 0x60,
1179        0x30, 0xb0, 0x10, 0x90,
1180        0xf0, 0x70, 0xd0, 0x50
1181    };
1182
1183    ordered4_table = dither4x4 + (line % 4) * 4;
1184    ordered4_index = 0;
1185}
1186
1187static unsigned int get_ordered4_dither(void)
1188{
1189    return ordered4_table[ordered4_index];
1190}
1191
1192static void increment_ordered4_dither(void)
1193{
1194    ordered4_index = (ordered4_index + 1) % 4;
1195}
1196
1197/*
1198 * Ordered 8 dithering
1199 */
1200static unsigned int const *ordered8_table;
1201static unsigned int ordered8_index;
1202
1203static void init_ordered8_dither(int line)
1204{
1205    static unsigned int const dither8x8[] =
1206    {
1207        0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1208        0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
1209        0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
1210        0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
1211        0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
1212        0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
1213        0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
1214        0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
1215    };
1216
1217    ordered8_table = dither8x8 + (line % 8) * 8;
1218    ordered8_index = 0;
1219}
1220
1221static unsigned int get_ordered8_dither(void)
1222{
1223    return ordered8_table[ordered8_index];
1224}
1225
1226static void increment_ordered8_dither(void)
1227{
1228    ordered8_index = (ordered8_index + 1) % 8;
1229}
1230
1231/*
1232 * Random dithering
1233 */
1234static void init_random_dither(int line)
1235{
1236    ;
1237}
1238
1239static unsigned int get_random_dither(void)
1240{
1241    return cucul_rand(0x00, 0xff);
1242}
1243
1244static void increment_random_dither(void)
1245{
1246    return;
1247}
1248
1249#if !defined(_DOXYGEN_SKIP_ME)
1250int _cucul_init_bitmap(void)
1251{
1252    unsigned int v, s, h;
1253
1254    /* These ones are constant */
1255    lookup_colors[0] = CUCUL_COLOR_BLACK;
1256    lookup_colors[1] = CUCUL_COLOR_DARKGRAY;
1257    lookup_colors[2] = CUCUL_COLOR_LIGHTGRAY;
1258    lookup_colors[3] = CUCUL_COLOR_WHITE;
1259
1260    /* These ones will be overwritten */
1261    lookup_colors[4] = CUCUL_COLOR_MAGENTA;
1262    lookup_colors[5] = CUCUL_COLOR_LIGHTMAGENTA;
1263    lookup_colors[6] = CUCUL_COLOR_RED;
1264    lookup_colors[7] = CUCUL_COLOR_LIGHTRED;
1265
1266    for(v = 0; v < LOOKUP_VAL; v++)
1267        for(s = 0; s < LOOKUP_SAT; s++)
1268            for(h = 0; h < LOOKUP_HUE; h++)
1269    {
1270        int i, distbg, distfg, dist;
1271        int val, sat, hue;
1272        unsigned char outbg, outfg;
1273
1274        val = 0xfff * v / (LOOKUP_VAL - 1);
1275        sat = 0xfff * s / (LOOKUP_SAT - 1);
1276        hue = 0xfff * h / (LOOKUP_HUE - 1);
1277
1278        /* Initialise distances to the distance between pure black HSV
1279         * coordinates and our white colour (3) */
1280        outbg = outfg = 3;
1281        distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
1282
1283        /* Calculate distances to eight major colour values and store the
1284         * two nearest points in our lookup table. */
1285        for(i = 0; i < 8; i++)
1286        {
1287            dist = HSV_DISTANCE(hue, sat, val, i);
1288            if(dist <= distbg)
1289            {
1290                outfg = outbg;
1291                distfg = distbg;
1292                outbg = i;
1293                distbg = dist;
1294            }
1295            else if(dist <= distfg)
1296            {
1297                outfg = i;
1298                distfg = dist;
1299            }
1300        }
1301
1302        hsv_distances[v][s][h] = (outfg << 4) | outbg;
1303    }
1304
1305    return 0;
1306}
1307
1308int _cucul_end_bitmap(void)
1309{
1310    return 0;
1311}
1312#endif /* _DOXYGEN_SKIP_ME */
1313
1314
Note: See TracBrowser for help on using the repository browser.