source: libcaca/trunk/src/bitmap.c @ 237

Last change on this file since 237 was 237, checked in by Sam Hocevar, 18 years ago
  • src/bitmap.c examples/view.c: + Fixed an endianness issue in caca_draw_bitmap(). + Code cleanup.
  • Property svn:keywords set to Id
File size: 13.0 KB
Line 
1/*
2 *   libcaca       ASCII-Art library
3 *   Copyright (c) 2002, 2003 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 GNU Lesser General Public
8 *   License as published by the Free Software Foundation; either
9 *   version 2 of the License, or (at your option) any later version.
10 *
11 *   This library is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 *   Lesser General Public License for more details.
15 *
16 *   You should have received a copy of the GNU Lesser General Public
17 *   License along with this library; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 *   02111-1307  USA
20 */
21
22/**  \file bitmap.c
23 *   \version \$Id: bitmap.c 237 2003-11-30 02:11:37Z sam $
24 *   \author Sam Hocevar <sam@zoy.org>
25 *   \brief Bitmap functions
26 *
27 *   This file contains bitmap blitting functions.
28 */
29
30#include "config.h"
31
32#ifdef HAVE_INTTYPES_H
33#   include <inttypes.h>
34#else
35typedef unsigned char uint8_t;
36typedef unsigned short uint16_t;
37typedef unsigned int uint32_t;
38#endif
39
40#include <stdlib.h>
41
42#include "caca.h"
43#include "caca_internals.h"
44
45static void mask2shift(unsigned int, int *, int *);
46
47static void get_rgb_default(struct caca_bitmap *, uint8_t *, int, int,
48                            unsigned int *, unsigned int *, unsigned int *);
49static void rgb2hsv_default(int, int, int, int *, int *, int *);
50
51/* Dithering methods */
52static void init_no_dither(int);
53static unsigned int get_no_dither(void);
54static void increment_no_dither(void);
55
56static void init_ordered4_dither(int);
57static unsigned int get_ordered4_dither(void);
58static void increment_ordered4_dither(void);
59
60static void init_ordered8_dither(int);
61static unsigned int get_ordered8_dither(void);
62static void increment_ordered8_dither(void);
63
64static void init_random_dither(int);
65static unsigned int get_random_dither(void);
66static void increment_random_dither(void);
67
68/* Current dithering method */
69static enum caca_dithering _caca_dithering = CACA_DITHERING_NONE;
70
71static void (*_init_dither) (int) = init_no_dither;
72static unsigned int (*_get_dither) (void) = get_no_dither;
73static void (*_increment_dither) (void) = increment_no_dither;
74
75void caca_set_dithering(enum caca_dithering dither)
76{
77    switch(dither)
78    {
79    case CACA_DITHERING_NONE:
80        _init_dither = init_no_dither;
81        _get_dither = get_no_dither;
82        _increment_dither = increment_no_dither;
83        break;
84
85    case CACA_DITHERING_ORDERED4:
86        _init_dither = init_ordered4_dither;
87        _get_dither = get_ordered4_dither;
88        _increment_dither = increment_ordered4_dither;
89        break;
90
91    case CACA_DITHERING_ORDERED8:
92        _init_dither = init_ordered8_dither;
93        _get_dither = get_ordered8_dither;
94        _increment_dither = increment_ordered8_dither;
95        break;
96
97    case CACA_DITHERING_RANDOM:
98        _init_dither = init_random_dither;
99        _get_dither = get_random_dither;
100        _increment_dither = increment_random_dither;
101        break;
102
103    default:
104        return;
105    }
106
107    _caca_dithering = dither;
108}
109
110struct caca_bitmap
111{
112    int bpp, palette;
113    int w, h, pitch;
114    int rmask, gmask, bmask;
115    int rright, gright, bright;
116    int rleft, gleft, bleft;
117    void (*get_hsv)(struct caca_bitmap *, char *, int, int);
118    int red[256], green[256], blue[256];
119};
120
121static void mask2shift(unsigned int mask, int *right, int *left)
122{
123    int rshift = 0, lshift = 0;
124
125    if(!mask)
126    {
127        *right = *left = 0;
128        return;
129    }
130
131    while(!(mask & 1))
132    {
133        mask >>= 1;
134        rshift++;
135    }
136    *right = rshift;
137
138    while(mask & 1)
139    {
140        mask >>= 1;
141        lshift++;
142    }
143    *left = 16 - lshift;
144}
145
146#include <stdio.h>
147struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch,
148                                       int rmask, int gmask, int bmask)
149{
150    struct caca_bitmap *bitmap;
151
152    /* Currently only this format is supported. Will improve later. */
153    if(!w || !h || !pitch || bpp > 32 || bpp < 8)
154        return NULL;
155
156    bitmap = malloc(sizeof(struct caca_bitmap));
157    if(!bitmap)
158        return NULL;
159
160    bitmap->bpp = bpp;
161    bitmap->palette = 0;
162
163    bitmap->w = w;
164    bitmap->h = h;
165    bitmap->pitch = pitch;
166
167    bitmap->rmask = rmask;
168    bitmap->gmask = gmask;
169    bitmap->bmask = bmask;
170
171    /* Load bitmasks */
172    if(rmask || gmask || bmask)
173    {
174        mask2shift(rmask, &bitmap->rright, &bitmap->rleft);
175        mask2shift(gmask, &bitmap->gright, &bitmap->gleft);
176        mask2shift(bmask, &bitmap->bright, &bitmap->bleft);
177    }
178fprintf(stderr, "shifts: %i %i %i %i %i %i\n", bitmap->rright, bitmap->rleft, bitmap->gright, bitmap->gleft, bitmap->bright, bitmap->bleft);
179
180    /* In 8 bpp mode, default to a grayscale palette */
181    if(bpp == 8)
182    {
183        int i;
184        bitmap->palette = 1;
185        for(i = 0; i < 256; i++)
186        {
187            bitmap->red[i] = i * 0x100;
188            bitmap->green[i] = i * 0x100;
189            bitmap->blue[i] = i * 0x100;
190        }
191    }
192
193    return bitmap;
194}
195
196void caca_set_bitmap_palette(struct caca_bitmap *bitmap,
197                             int red[], int green[], int blue[])
198{
199    int i;
200
201    if(bitmap->bpp != 8)
202        return;
203
204    for(i = 0; i < 256; i++)
205    {
206        if(red[i] >= 0 && red[i] < 65536 &&
207           green[i] >= 0 && green[i] < 65536 &&
208           blue[i] >= 0 && blue[i] < 65536)
209        {
210            bitmap->red[i] = red[i];
211            bitmap->green[i] = green[i];
212            bitmap->blue[i] = blue[i];
213        }
214    }
215}
216
217void caca_free_bitmap(struct caca_bitmap *bitmap)
218{
219    if(!bitmap)
220        return;
221
222    free(bitmap);
223}
224
225static void get_rgb_default(struct caca_bitmap *bitmap, uint8_t *pixels,
226                            int x, int y, unsigned int *r,
227                            unsigned int *g, unsigned int *b)
228{
229    unsigned int bits;
230
231    pixels += (bitmap->bpp / 8) * x + bitmap->pitch * y;
232
233    switch(bitmap->bpp / 8)
234    {
235        case 4:
236            bits = ((uint32_t)pixels[0] << 24) |
237                   ((uint32_t)pixels[1] << 16) |
238                   ((uint32_t)pixels[2] << 8) |
239                   ((uint32_t)pixels[3]);
240            break;
241        case 3:
242            bits = ((uint32_t)pixels[0] << 16) |
243                   ((uint32_t)pixels[1] << 8) |
244                   ((uint32_t)pixels[2]);
245            break;
246        case 2:
247            bits = ((uint16_t)pixels[0] << 8) |
248                   ((uint16_t)pixels[1]);
249            break;
250        case 1:
251        default:
252            bits = pixels[0];
253            break;
254    }
255
256    if(bitmap->palette)
257    {
258        *r = bitmap->red[bits];
259        *g = bitmap->green[bits];
260        *b = bitmap->blue[bits];
261    }
262    else
263    {
264        *r = ((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft;
265        *g = ((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft;
266        *b = ((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft;
267    }
268}
269
270static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val)
271{
272    int min, max, delta;
273
274    min = r; max = r;
275    if(min > g) min = g; if(max < g) max = g;
276    if(min > b) min = b; if(max < b) max = b;
277
278    delta = max - min; /* 0 - 0xffff */
279    *val = max; /* 0 - 0xffff */
280
281    if(delta)
282    {
283        *sat = 0x1000 * delta / max * 0x10; /* 0 - 0xffff */
284
285        /* Generate *hue between 0 and 0x5ffff */
286        if( r == max )
287            *hue = 0x10000 + 0x100 * (g - b) / delta * 0x100;
288        else if( g == max )
289            *hue = 0x30000 + 0x100 * (b - r) / delta * 0x100;
290        else
291            *hue = 0x50000 + 0x100 * (r - g) / delta * 0x100;
292    }
293    else
294    {
295        *sat = 0;
296        *hue = 0;
297    }
298}
299
300void caca_draw_bitmap(int x1, int y1, int x2, int y2,
301                      struct caca_bitmap *bitmap, char *pixels)
302{
303    /* FIXME: this code is shite! */
304    static int white_colors[] =
305    {
306        CACA_COLOR_DARKGRAY,
307        CACA_COLOR_LIGHTGRAY,
308        CACA_COLOR_WHITE
309    };
310
311    static int light_colors[] =
312    {
313        CACA_COLOR_LIGHTMAGENTA,
314        CACA_COLOR_LIGHTRED,
315        CACA_COLOR_YELLOW,
316        CACA_COLOR_LIGHTGREEN,
317        CACA_COLOR_LIGHTCYAN,
318        CACA_COLOR_LIGHTBLUE,
319        CACA_COLOR_LIGHTMAGENTA
320    };
321
322    static int dark_colors[] =
323    {
324        CACA_COLOR_MAGENTA,
325        CACA_COLOR_RED,
326        CACA_COLOR_BROWN,
327        CACA_COLOR_GREEN,
328        CACA_COLOR_CYAN,
329        CACA_COLOR_BLUE,
330        CACA_COLOR_MAGENTA
331    };
332
333    static char foo[] =
334        "    "
335        " ,' "
336        ",`.'"
337        "i-:^"
338        "|/;\\"
339        "=+ox"
340        "<x%>"
341        "&z$w"
342        "WXKM"
343        "#8##"
344        "8@8#"
345        "@8@8";
346
347    int x, y, w, h, pitch;
348
349    if(!bitmap || !pixels)
350        return;
351
352    w = bitmap->w;
353    h = bitmap->h;
354    pitch = bitmap->pitch;
355
356    if(x1 > x2)
357    {
358        int tmp = x2; x2 = x1; x1 = tmp;
359    }
360
361    if(y1 > y2)
362    {
363        int tmp = y2; y2 = y1; y1 = tmp;
364    }
365
366    for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)caca_get_height(); y++)
367    {
368        /* Initialize dither tables for the current line */
369        _init_dither(y);
370
371        /* Dither the current line */
372        for(x = x1 > 0 ? x1 : 0; x <= x2 && x <= (int)caca_get_width(); x++)
373        {
374            int ch;
375            unsigned int hue, sat, val, r, g, b, R, G, B;
376            int fromx = w * (x - x1) / (x2 - x1 + 1);
377            int fromy = h * (y - y1) / (y2 - y1 + 1);
378
379            /* Clip values (yuck) */
380            if(fromx == 0) fromx = 1;
381            if(fromy == 0) fromy = 1;
382
383            /* First get RGB */
384            R = 0, G = 0, B = 0;
385            get_rgb_default(bitmap, pixels, fromx, fromy, &r, &g, &b);
386            R += r; G += g; B += b;
387            get_rgb_default(bitmap, pixels, fromx - 1, fromy, &r, &g, &b);
388            R += r; G += g; B += b;
389            get_rgb_default(bitmap, pixels, fromx, fromy - 1, &r, &g, &b);
390            R += r; G += g; B += b;
391            get_rgb_default(bitmap, pixels, fromx + 1, fromy, &r, &g, &b);
392            R += r; G += g; B += b;
393            get_rgb_default(bitmap, pixels, fromx, fromy + 1, &r, &g, &b);
394            R += r; G += g; B += b;
395            R /= 5; G /= 5; B /= 5;
396
397            /* Now get HSV from RGB */
398            rgb2hsv_default(R, G, B, &hue, &sat, &val);
399
400            if(sat < 0x2000 + _get_dither() * 0x80)
401                caca_set_color(white_colors[val * 3 / 0x10000], CACA_COLOR_BLACK);
402            else if(val > 0x8000 + _get_dither() * 0x40)
403                caca_set_color(light_colors[(hue + _get_dither() * 0x100) / 0x10000], CACA_COLOR_BLACK);
404            else
405                caca_set_color(dark_colors[(hue + _get_dither() * 0x100) / 0x10000], CACA_COLOR_BLACK);
406
407            /* FIXME: choose better characters! */
408            ch = (val + 0x20 * _get_dither() - 0x1000 /*???*/) * 10 / 0x10000;
409            ch = 4 * ch + (_get_dither() + 8) / 0x40;
410            caca_putchar(x, y, foo[ch]);
411
412            _increment_dither();
413        }
414    }
415}
416
417/*
418 * XXX: The following functions are local.
419 */
420
421/*
422 * No dithering
423 */
424static void init_no_dither(int line)
425{
426    ;
427}
428
429static unsigned int get_no_dither(void)
430{
431    return 0x80;
432}
433
434static void increment_no_dither(void)
435{
436    return;
437}
438
439/*
440 * Ordered 4 dithering
441 */
442/*static int dither4x4[] = { 5,  0,  1,  6,
443                          -1, -6, -5,  2,
444                          -2, -7, -8,  3,
445                           4, -3, -4, -7};*/
446static unsigned int *ordered4_table;
447static unsigned int ordered4_index;
448
449static void init_ordered4_dither(int line)
450{
451    static unsigned int dither4x4[] =
452    {
453        0x00, 0x80, 0x20, 0xa0,
454        0xc0, 0x40, 0xe0, 0x60,
455        0x30, 0xb0, 0x10, 0x90,
456        0xf0, 0x70, 0xd0, 0x50
457    };
458
459    ordered4_table = dither4x4 + (line % 4) * 4;
460    ordered4_index = 0;
461}
462
463static unsigned int get_ordered4_dither(void)
464{
465    return ordered4_table[ordered4_index];
466}
467
468static void increment_ordered4_dither(void)
469{
470    ordered4_index = (ordered4_index + 1) % 4;
471}
472
473/*
474 * Ordered 8 dithering
475 */
476static unsigned int *ordered8_table;
477static unsigned int ordered8_index;
478
479static void init_ordered8_dither(int line)
480{
481    static unsigned int dither8x8[] =
482    {
483        0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
484        0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
485        0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
486        0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
487        0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
488        0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
489        0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
490        0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
491    };
492
493    ordered8_table = dither8x8 + (line % 8) * 8;
494    ordered8_index = 0;
495}
496
497static unsigned int get_ordered8_dither(void)
498{
499    return ordered8_table[ordered8_index];
500}
501
502static void increment_ordered8_dither(void)
503{
504    ordered8_index = (ordered8_index + 1) % 8;
505}
506
507/*
508 * Random dithering
509 */
510static void init_random_dither(int line)
511{
512    ;
513}
514
515static unsigned int get_random_dither(void)
516{
517    return caca_rand(0x00, 0xff);
518}
519
520static void increment_random_dither(void)
521{
522    return;
523}
524
Note: See TracBrowser for help on using the repository browser.