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

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