diff --git a/examples/demo.c b/examples/demo.c index a5ad840..e03e321 100644 --- a/examples/demo.c +++ b/examples/demo.c @@ -47,6 +47,7 @@ static void demo_blit(void); int bounds = 0; int outline = 0; +int dithering = 0; struct caca_sprite *sprite = NULL; GdkPixbuf *pixbuf; @@ -76,10 +77,13 @@ gdk_init (&argc, &argv); //pixbuf = gdk_pixbuf_new_from_file("/home/sam/pix/union.png", NULL); //pixbuf = gdk_pixbuf_new_from_file("/home/sam/pix/pikachu.jpeg", NULL); //pixbuf = gdk_pixbuf_new_from_file("/home/sam/pix/gradient.png", NULL); + //pixbuf = gdk_pixbuf_new_from_file("/home/sam/pix/beastie.png", NULL); + pixbuf = gdk_pixbuf_new_from_file("/home/sam/pix/stitch.jpg", NULL); + //pixbuf = gdk_pixbuf_new_from_file("/home/sam/pix/dranac.jpeg", NULL); //pixbuf = gdk_pixbuf_new_from_file("/home/sam/artwork/aboire.png", NULL); //pixbuf = gdk_pixbuf_new_from_file("/home/sam/web/sam.zoy.org/artwork/goret.png", NULL); //pixbuf = gdk_pixbuf_new_from_file("/home/sam/lilkim02.jpg", NULL); - pixbuf = gdk_pixbuf_new_from_file("/home/sam/etw.bmp", NULL); + //pixbuf = gdk_pixbuf_new_from_file("/home/sam/etw.bmp", NULL); if(!pixbuf) return -2; pixels = gdk_pixbuf_get_pixels(pixbuf); bufx = gdk_pixbuf_get_width(pixbuf); @@ -123,6 +127,14 @@ fprintf(stderr, "w %i, h %i, stride %i\n", bufx, bufy, bufpitch); bounds = (bounds + 1) % 2; display_menu(); break; + case 'd': + case 'D': + dithering = (dithering + 1) % 3; + caca_set_dithering(dithering == 0 ? CACA_DITHER_NONE : + dithering == 1 ? CACA_DITHER_ORDERED : + CACA_DITHER_RANDOM); + display_menu(); + break; case 'c': demo = demo_color; break; @@ -213,6 +225,8 @@ static void display_menu(void) outline == 0 ? "none" : outline == 1 ? "solid" : "thin"); caca_printf(4, 19, "'b': drawing boundaries: %s", bounds == 0 ? "screen" : "infinite"); + caca_printf(4, 20, "'d': %s dithering", + dithering == 0 ? "no" : dithering == 1 ? "ordered" : "random"); caca_putstr(4, yo - 2, "'q': quit"); } @@ -464,6 +478,7 @@ static void demo_sprites(void) static void demo_blit(void) { - caca_blit(6, 4, caca_get_width() - 6, caca_get_height() - 4, pixels, bufx, bufy); + caca_blit(6, 4, caca_get_width() - 6, caca_get_height() - 4, + pixels, bufx, bufy); } diff --git a/src/blit.c b/src/blit.c index 62ac4d6..c2cff5e 100644 --- a/src/blit.c +++ b/src/blit.c @@ -34,19 +34,60 @@ typedef unsigned char uint8_t; #include "caca.h" #include "caca_internals.h" +/* Dithering methods */ +static void init_no_dither(int); +static int get_no_dither(void); +static void increment_no_dither(void); + +static void init_ordered_dither(int); +static int get_ordered_dither(void); +static void increment_ordered_dither(void); + +static void init_random_dither(int); +static int get_random_dither(void); +static void increment_random_dither(void); + +/* Current dithering method */ static enum caca_dithering _caca_dithering = CACA_DITHER_NONE; +static void (*_init_dither) (int) = init_no_dither; +static int (*_get_dither) (void) = get_no_dither; +static void (*_increment_dither) (void) = increment_no_dither; + void caca_set_dithering(enum caca_dithering dither) { - if(dither < 0 || dither > 1) + switch(dither) + { + case CACA_DITHER_NONE: + _init_dither = init_no_dither; + _get_dither = get_no_dither; + _increment_dither = increment_no_dither; + break; + + case CACA_DITHER_ORDERED: + _init_dither = init_ordered_dither; + _get_dither = get_ordered_dither; + _increment_dither = increment_ordered_dither; + break; + + case CACA_DITHER_RANDOM: + _init_dither = init_random_dither; + _get_dither = get_random_dither; + _increment_dither = increment_random_dither; + break; + + default: return; + } _caca_dithering = dither; } void caca_blit(int x1, int y1, int x2, int y2, void *pixels, int w, int h) { - char foo[] = { ' ', '.', ':', ';', '=', '%', '$', 'W', '#', '8', '@' }; + static int light_colors[] = {CACA_COLOR_LIGHTMAGENTA, CACA_COLOR_LIGHTRED, CACA_COLOR_YELLOW, CACA_COLOR_LIGHTGREEN, CACA_COLOR_LIGHTCYAN, CACA_COLOR_LIGHTBLUE, CACA_COLOR_LIGHTMAGENTA}; + static int dark_colors[] = {CACA_COLOR_MAGENTA, CACA_COLOR_RED, CACA_COLOR_BROWN, CACA_COLOR_GREEN, CACA_COLOR_CYAN, CACA_COLOR_BLUE, CACA_COLOR_MAGENTA}; + static char foo[] = { ' ', '.', ':', ';', '=', '%', '$', 'W', '#', '8', '@' }; int x, y, pitch; if(x1 > x2) @@ -62,10 +103,13 @@ void caca_blit(int x1, int y1, int x2, int y2, void *pixels, int w, int h) pitch = (3 * w + 3) / 4 * 4; for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)caca_get_height(); y++) + { + /* Initialize dither tables for the current line */ + _init_dither(y); + + /* Dither the current line */ for(x = x1 > 0 ? x1 : 0; x <= x2 && x <= (int)caca_get_width(); x++) { -static int light_colors[] = {CACA_COLOR_LIGHTMAGENTA, CACA_COLOR_LIGHTRED, CACA_COLOR_YELLOW, CACA_COLOR_LIGHTGREEN, CACA_COLOR_LIGHTCYAN, CACA_COLOR_LIGHTBLUE, CACA_COLOR_LIGHTMAGENTA}; -static int dark_colors[] = {CACA_COLOR_MAGENTA, CACA_COLOR_RED, CACA_COLOR_BROWN, CACA_COLOR_GREEN, CACA_COLOR_CYAN, CACA_COLOR_BLUE, CACA_COLOR_MAGENTA}; int fromx = w * (x - x1) / (x2 - x1 + 1); int fromy = h * (y - y1) / (y2 - y1 + 1); int r = ((unsigned char *)pixels)[3 * fromx + pitch * fromy]; @@ -81,18 +125,21 @@ static int dark_colors[] = {CACA_COLOR_MAGENTA, CACA_COLOR_RED, CACA_COLOR_BROWN val = max; /* 0 - 255 */ sat = max ? 256 * delta / max : 0; /* 0 - 255 */ - if(sat > caca_rand(64, 128)) + if(sat > (_get_dither() + 24) * 4) { - /* XXX: Values are automatically clipped between 0 and 6 - * because of delta/2 */ + /* XXX: Values should be between 1 and 6, but since we + * are dithering, there may be overflows, hence our bigger + * *_colors[] tables. */ if( r == max ) - hue = 1 + (float)(g - b + delta / 2 + caca_rand(-40, 40)) / delta; + hue = 256 + 256 * (g - b) / delta; else if( g == max ) - hue = 3 + (float)(b - r + delta / 2 + caca_rand(-40, 40)) / delta; + hue = 768 + 256 * (b - r) / delta; else - hue = 5 + (float)(r - g + delta / 2 + caca_rand(-40, 40)) / delta; + hue = 1280 + 256 * (r - g) / delta; + + hue = (hue + 128 + 8 * _get_dither()) / 256; - if(val > caca_rand(128, 192)) + if(val > (_get_dither() + 40) * 4) caca_set_color(light_colors[hue]); else caca_set_color(dark_colors[hue]); @@ -102,7 +149,76 @@ static int dark_colors[] = {CACA_COLOR_MAGENTA, CACA_COLOR_RED, CACA_COLOR_BROWN caca_set_color(CACA_COLOR_LIGHTGRAY); } - caca_putchar(x, y, foo[(r + g + b + caca_rand(-10, 10)) / 3 / 25]); + caca_putchar(x, y, foo[(r + g + b + 2 * _get_dither()) / 3 / 25]); + + _increment_dither(); } + } +} + +/* + * XXX: The following functions are local. + */ + +/* + * No dithering + */ +static void init_no_dither(int line) +{ + ; +} + +static int get_no_dither(void) +{ + return 0; +} + +static void increment_no_dither(void) +{ + return; +} + +/* + * Ordered dithering + */ +static int dither4x4[] = {-8, 0, -6, 2, + 4, -4, 6, -2, + -5, 3, -7, 1, + 7, -1, 5, -3}; +static int *dither_table; +static int dither_index; + +static void init_ordered_dither(int line) +{ + dither_table = dither4x4 + (line % 4) * 4; + dither_index = 0; +} + +static int get_ordered_dither(void) +{ + return dither_table[dither_index]; +} + +static void increment_ordered_dither(void) +{ + dither_index = (dither_index + 1) % 4; +} + +/* + * Random dithering + */ +static void init_random_dither(int line) +{ + ; +} + +static int get_random_dither(void) +{ + return caca_rand(-8, 7); +} + +static void increment_random_dither(void) +{ + return; } diff --git a/src/caca.h b/src/caca.h index 49d1de4..47225c0 100644 --- a/src/caca.h +++ b/src/caca.h @@ -57,8 +57,9 @@ enum caca_color */ enum caca_dithering { - CACA_DITHER_NONE = 0, - CACA_DITHER_RANDOM = 1 + CACA_DITHER_NONE, + CACA_DITHER_ORDERED, + CACA_DITHER_RANDOM }; /*