From cda43d356365801769127865060555167d359c5d Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sun, 30 Nov 2003 15:01:55 +0000 Subject: [PATCH] * src/bitmap.c: + Fixed an endianness issue in the byte reader. + Decreased precision in RGB and HSV values to avoid overflows. + New dithering method: 2x2 ordered. + New renderer, with background colour awareness. * configure.ac: + Check for . * examples/demo.c examples/view.c: + Fixed an endianness issue in cacaview. + Adapted code to the additional dithering method. --- configure.ac | 4 +- examples/demo.c | 2 +- examples/view.c | 28 ++++- src/bitmap.c | 290 +++++++++++++++++++++++++++++++++++++----------- src/caca.c | 3 +- src/caca.h | 7 +- 6 files changed, 257 insertions(+), 77 deletions(-) diff --git a/configure.ac b/configure.ac index 906ec8c..fc5c807 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_PREREQ(2.50) AC_CONFIG_AUX_DIR(autotools) AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(libcaca, 0.1) +AM_INIT_AUTOMAKE(libcaca, 0.2) AM_CONFIG_HEADER(config.h) AM_PROG_CC_C_O @@ -24,7 +24,7 @@ AC_ARG_ENABLE(slang, AC_ARG_ENABLE(conio, [ --enable-conio DOS conio.h graphics support (default disabled)]) -AC_CHECK_HEADERS(inttypes.h) +AC_CHECK_HEADERS(inttypes.h endian.h) AC_CHECK_FUNCS(vsnprintf getenv putenv) USE_SLANG=false diff --git a/examples/demo.c b/examples/demo.c index b1f24a4..a4d5860 100644 --- a/examples/demo.c +++ b/examples/demo.c @@ -100,7 +100,7 @@ int main(int argc, char **argv) break; case 'd': case 'D': - dithering = (dithering + 1) % 4; + dithering = (dithering + 1) % 5; caca_set_dithering(dithering); display_menu(); break; diff --git a/examples/view.c b/examples/view.c index ee1292a..fa827d4 100644 --- a/examples/view.c +++ b/examples/view.c @@ -28,6 +28,10 @@ #include #include +#ifdef HAVE_ENDIAN_H +# include +#endif + #include #include "caca.h" @@ -36,6 +40,7 @@ Imlib_Image image = NULL; char *pixels = NULL; struct caca_bitmap *bitmap = NULL; int x, y, w, h; +unsigned int rmask, gmask, bmask; int dithering = CACA_DITHERING_ORDERED4; @@ -49,6 +54,20 @@ int main(int argc, char **argv) char **list = NULL; int current = 0, items = 0, opts = 1; +#ifdef HAVE_ENDIAN_H + if(__BYTE_ORDER == __BIG_ENDIAN) +#else + rmask = 0x12345678; + if(*(char *)&rmask == 0x12) +#endif + { + rmask = 0x00ff0000; gmask = 0x0000ff00; bmask = 0x000000ff; + } + else + { + rmask = 0x0000ff00; gmask = 0x00ff0000; bmask = 0xff000000; + } + /* Initialise libcaca */ if(caca_init()) { @@ -101,11 +120,11 @@ int main(int argc, char **argv) reload = 1; break; case CACA_EVENT_KEY_PRESS | 'd': - dithering = (dithering + 1) % 4; + dithering = (dithering + 1) % 5; update = 1; break; case CACA_EVENT_KEY_PRESS | 'D': - dithering = (dithering - 1) % 4; + dithering = (dithering + 4) % 5; update = 1; break; case CACA_EVENT_KEY_PRESS | '+': @@ -215,7 +234,7 @@ int main(int argc, char **argv) if(xn + x > w) x = w - xn; if(yn + y > h) y = h - yn; newbitmap = caca_create_bitmap(32, 2 * xn, 2 * yn, 4 * w, - 0x0000ff00, 0x00ff0000, 0xff000000); + rmask, gmask, bmask); caca_draw_bitmap(0, 0, ww - 1, wh - 1, newbitmap, pixels + 4 * (x - xn) + 4 * w * (y - yn)); caca_free_bitmap(newbitmap); @@ -297,8 +316,7 @@ static void load_image(const char *name) y = h / 2; /* Create the libcaca bitmap */ - bitmap = caca_create_bitmap(32, w, h, 4 * w, - 0x0000ff00, 0x00ff0000, 0xff000000); + bitmap = caca_create_bitmap(32, w, h, 4 * w, rmask, gmask, bmask); if(!bitmap) { imlib_free_image(); diff --git a/src/bitmap.c b/src/bitmap.c index aa4dd37..423ed02 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -53,6 +53,10 @@ static void init_no_dither(int); static unsigned int get_no_dither(void); static void increment_no_dither(void); +static void init_ordered2_dither(int); +static unsigned int get_ordered2_dither(void); +static void increment_ordered2_dither(void); + static void init_ordered4_dither(int); static unsigned int get_ordered4_dither(void); static void increment_ordered4_dither(void); @@ -82,6 +86,12 @@ void caca_set_dithering(enum caca_dithering dither) _increment_dither = increment_no_dither; break; + case CACA_DITHERING_ORDERED2: + _init_dither = init_ordered2_dither; + _get_dither = get_ordered2_dither; + _increment_dither = increment_ordered2_dither; + break; + case CACA_DITHERING_ORDERED4: _init_dither = init_ordered4_dither; _get_dither = get_ordered4_dither; @@ -140,10 +150,9 @@ static void mask2shift(unsigned int mask, int *right, int *left) mask >>= 1; lshift++; } - *left = 16 - lshift; + *left = 12 - lshift; } -#include struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch, int rmask, int gmask, int bmask) { @@ -175,7 +184,6 @@ struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch, mask2shift(gmask, &bitmap->gright, &bitmap->gleft); mask2shift(bmask, &bitmap->bright, &bitmap->bleft); } -fprintf(stderr, "shifts: %i %i %i %i %i %i\n", bitmap->rright, bitmap->rleft, bitmap->gright, bitmap->gleft, bitmap->bright, bitmap->bleft); /* In 8 bpp mode, default to a grayscale palette */ if(bpp == 8) @@ -184,9 +192,9 @@ fprintf(stderr, "shifts: %i %i %i %i %i %i\n", bitmap->rright, bitmap->rleft, bi bitmap->palette = 1; for(i = 0; i < 256; i++) { - bitmap->red[i] = i * 0x100; - bitmap->green[i] = i * 0x100; - bitmap->blue[i] = i * 0x100; + bitmap->red[i] = i * 0x10; + bitmap->green[i] = i * 0x10; + bitmap->blue[i] = i * 0x10; } } @@ -203,9 +211,9 @@ void caca_set_bitmap_palette(struct caca_bitmap *bitmap, for(i = 0; i < 256; i++) { - if(red[i] >= 0 && red[i] < 65536 && - green[i] >= 0 && green[i] < 65536 && - blue[i] >= 0 && blue[i] < 65536) + if(red[i] >= 0 && red[i] < 0x1000 && + green[i] >= 0 && green[i] < 0x1000 && + blue[i] >= 0 && blue[i] < 0x1000) { bitmap->red[i] = red[i]; bitmap->green[i] = green[i]; @@ -280,15 +288,15 @@ static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val) if(delta) { - *sat = 0x1000 * delta / max * 0x10; /* 0 - 0xffff */ + *sat = 0x1000 * delta / max; /* 0 - 0xfff */ - /* Generate *hue between 0 and 0x5ffff */ + /* Generate *hue between 0 and 0x5fff */ if( r == max ) - *hue = 0x10000 + 0x100 * (g - b) / delta * 0x100; + *hue = 0x1000 + 0x1000 * (g - b) / delta; else if( g == max ) - *hue = 0x30000 + 0x100 * (b - r) / delta * 0x100; + *hue = 0x3000 + 0x1000 * (b - r) / delta; else - *hue = 0x50000 + 0x100 * (r - g) / delta * 0x100; + *hue = 0x5000 + 0x1000 * (r - g) / delta; } else { @@ -303,6 +311,7 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2, /* FIXME: this code is shite! */ static int white_colors[] = { + CACA_COLOR_BLACK, CACA_COLOR_DARKGRAY, CACA_COLOR_LIGHTGRAY, CACA_COLOR_WHITE @@ -330,19 +339,23 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2, CACA_COLOR_MAGENTA }; - static char foo[] = + /* FIXME: choose better characters! */ +# define DENSITY_CHARS 13 + static char density_chars[] = + " " " " - " ,' " + ".` " ",`.'" - "i-:^" - "|/;\\" - "=+ox" - "" - "&z$w" + "i:-^" + "|=+;" + "ox/\\" + "<>x%" + "&$zw" "WXKM" "#8##" "8@8#" - "@8@8"; + "@8@8" + "????"; int x, y, w, h, pitch; @@ -364,53 +377,172 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2, } for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)caca_get_height(); y++) + for(x = x1 > 0 ? x1 : 0, _init_dither(y); + x <= x2 && x <= (int)caca_get_width(); + x++) { - /* Initialize dither tables for the current line */ - _init_dither(y); + int ch; + unsigned int r, g, b, R, G, B; + int hue, sat, val; + int fromx = w * (x - x1) / (x2 - x1 + 1); + int fromy = h * (y - y1) / (y2 - y1 + 1); + enum caca_color outfg, outbg; + char outch; +#define NEW_DITHERER 1 +#ifdef NEW_DITHERER + int distbg, distfg, dist; +#endif + + /* Clip values (yuck) */ + if(fromx == 0) fromx = 1; + if(fromy == 0) fromy = 1; + + /* First get RGB */ + R = 0, G = 0, B = 0; + get_rgb_default(bitmap, pixels, fromx, fromy, &r, &g, &b); +#if 0 + R += r; G += g; B += b; + get_rgb_default(bitmap, pixels, fromx - 1, fromy, &r, &g, &b); + R += r; G += g; B += b; + get_rgb_default(bitmap, pixels, fromx, fromy - 1, &r, &g, &b); + R += r; G += g; B += b; + get_rgb_default(bitmap, pixels, fromx + 1, fromy, &r, &g, &b); + R += r; G += g; B += b; + get_rgb_default(bitmap, pixels, fromx, fromy + 1, &r, &g, &b); + R += r; G += g; B += b; + R /= 5; G /= 5; B /= 5; +#else + R += r; G += g; B += b; +#endif + + /* Now get HSV from RGB */ + rgb2hsv_default(R, G, B, &hue, &sat, &val); + + /* The hard work: calculate foreground and background colours, + * as well as the most appropriate character to output. */ +#if NEW_DITHERER +#define XRATIO 5*5 +#define YRATIO 3*3 + /* distance to black */ + distbg = XRATIO * val * val; + distbg += XRATIO * 0x1000 * _get_dither() - XRATIO * 0x8000; + outbg = CACA_COLOR_BLACK; + + /* distance to 30% */ + dist = XRATIO * (val - 0x600) * (val - 0x600) + + YRATIO * sat * sat; + dist += XRATIO * 0x1000 * _get_dither() - XRATIO * 0x8000; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = CACA_COLOR_DARKGRAY; + distbg = dist; + } + else + { + outfg = CACA_COLOR_DARKGRAY; + distfg = dist; + } + + /* check dist to 70% */ + dist = XRATIO * (val - 0xa00) * (val - 0xa00) + + YRATIO * sat * sat; + dist += XRATIO * 0x1000 * _get_dither() - XRATIO * 0x8000; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = CACA_COLOR_LIGHTGRAY; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = CACA_COLOR_LIGHTGRAY; + distfg = dist; + } + + /* check dist to white */ + dist = XRATIO * (val - 0x1000) * (val - 0x1000) + + YRATIO * sat * sat; + dist += XRATIO * 0x1000 * _get_dither() - XRATIO * 0x8000; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = CACA_COLOR_WHITE; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = CACA_COLOR_WHITE; + distfg = dist; + } + + /* check dist to dark */ + dist = XRATIO * (val - 0x600) * (val - 0x600) + + YRATIO * (sat - 0x1000) * (sat - 0x1000); + dist += XRATIO * 0x1000 * _get_dither() - XRATIO * 0x8000; + dist = dist * 3 / 4; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = dark_colors[(hue + _get_dither() * 0x10) / 0x1000]; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = dark_colors[(hue + _get_dither() * 0x10) / 0x1000]; + distfg = dist; + } - /* Dither the current line */ - for(x = x1 > 0 ? x1 : 0; x <= x2 && x <= (int)caca_get_width(); x++) + /* check dist to light */ + dist = XRATIO * (val - 0x1000) * (val - 0x1000) + + YRATIO * (sat - 0x1000) * (sat - 0x1000); + dist += XRATIO * 0x1000 * _get_dither() - XRATIO * 0x8000; + dist = dist / 2; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = light_colors[(hue + _get_dither() * 0x10) / 0x1000]; + distbg = dist; + } + else if(dist <= distfg) { - int ch; - unsigned int hue, sat, val, r, g, b, R, G, B; - int fromx = w * (x - x1) / (x2 - x1 + 1); - int fromy = h * (y - y1) / (y2 - y1 + 1); - - /* Clip values (yuck) */ - if(fromx == 0) fromx = 1; - if(fromy == 0) fromy = 1; - - /* First get RGB */ - R = 0, G = 0, B = 0; - get_rgb_default(bitmap, pixels, fromx, fromy, &r, &g, &b); - R += r; G += g; B += b; - get_rgb_default(bitmap, pixels, fromx - 1, fromy, &r, &g, &b); - R += r; G += g; B += b; - get_rgb_default(bitmap, pixels, fromx, fromy - 1, &r, &g, &b); - R += r; G += g; B += b; - get_rgb_default(bitmap, pixels, fromx + 1, fromy, &r, &g, &b); - R += r; G += g; B += b; - get_rgb_default(bitmap, pixels, fromx, fromy + 1, &r, &g, &b); - R += r; G += g; B += b; - R /= 5; G /= 5; B /= 5; - - /* Now get HSV from RGB */ - rgb2hsv_default(R, G, B, &hue, &sat, &val); - - if(sat < 0x2000 + _get_dither() * 0x80) - caca_set_color(white_colors[val * 3 / 0x10000], CACA_COLOR_BLACK); - else if(val > 0x8000 + _get_dither() * 0x40) - caca_set_color(light_colors[(hue + _get_dither() * 0x100) / 0x10000], CACA_COLOR_BLACK); - else - caca_set_color(dark_colors[(hue + _get_dither() * 0x100) / 0x10000], CACA_COLOR_BLACK); - - /* FIXME: choose better characters! */ - ch = (val + 0x20 * _get_dither() - 0x1000 /*???*/) * 10 / 0x10000; - ch = 4 * ch + (_get_dither() + 8) / 0x40; - caca_putchar(x, y, foo[ch]); - - _increment_dither(); + outfg = light_colors[(hue + _get_dither() * 0x10) / 0x1000]; + distfg = dist; } + + if(distbg <= 0) distbg = 1; + if(distfg <= 0) distfg = 1; + + /* distbg can be > distfg because of dithering fuzziness */ + ch = distbg * 2 * (DENSITY_CHARS - 1) / (distbg + distfg); + ch = 4 * ch /*+ _get_dither() / 0x40*/; + outch = density_chars[ch]; + +#else + outbg = CACA_COLOR_BLACK; + if(sat < 0x200 + _get_dither() * 0x8) + outfg = white_colors[1 + (val * 2 + _get_dither() * 0x10) / 0x1000]; + else if(val > 0x800 + _get_dither() * 0x4) + outfg = light_colors[(hue + _get_dither() * 0x10) / 0x1000]; + else + outfg = dark_colors[(hue + _get_dither() * 0x10) / 0x1000]; + + ch = (val + 0x2 * _get_dither()) * 10 / 0x1000; + ch = 4 * ch + _get_dither() / 0x40; + outch = density_chars[ch]; + +#endif + + /* Now output the character */ + caca_set_color(outfg, outbg); + caca_putchar(x, y, outch); + + _increment_dither(); } } @@ -436,6 +568,34 @@ static void increment_no_dither(void) return; } +/* + * Ordered 2 dithering + */ +static unsigned int *ordered2_table; +static unsigned int ordered2_index; + +static void init_ordered2_dither(int line) +{ + static unsigned int dither2x2[] = + { + 0x00, 0x80, + 0xc0, 0x40, + }; + + ordered2_table = dither2x2 + (line % 2) * 2; + ordered2_index = 0; +} + +static unsigned int get_ordered2_dither(void) +{ + return ordered2_table[ordered2_index]; +} + +static void increment_ordered2_dither(void) +{ + ordered2_index = (ordered2_index + 1) % 2; +} + /* * Ordered 4 dithering */ diff --git a/src/caca.c b/src/caca.c index 62632c4..9d8d368 100644 --- a/src/caca.c +++ b/src/caca.c @@ -185,12 +185,13 @@ const char *caca_get_dithering_name(enum caca_dithering dithering) static const char *dithering_names[] = { "no", + "2x2 ordered", "4x4 ordered", "8x8 ordered", "random" }; - if(dithering < 0 || dithering > 3) + if(dithering < 0 || dithering > 4) return "unknown"; return dithering_names[dithering]; diff --git a/src/caca.h b/src/caca.h index d0231db..df24154 100644 --- a/src/caca.h +++ b/src/caca.h @@ -89,9 +89,10 @@ const char *caca_get_color_name(enum caca_color); enum caca_dithering { CACA_DITHERING_NONE = 0, - CACA_DITHERING_ORDERED4 = 1, - CACA_DITHERING_ORDERED8 = 2, - CACA_DITHERING_RANDOM = 3 + CACA_DITHERING_ORDERED2 = 1, + CACA_DITHERING_ORDERED4 = 2, + CACA_DITHERING_ORDERED8 = 3, + CACA_DITHERING_RANDOM = 4 }; const char *caca_get_dithering_name(enum caca_dithering);