From d734f1d05723c03b2b8aac65f7fca4e123542930 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Fri, 12 Dec 2003 14:49:41 +0000 Subject: [PATCH] * src/bitmap.c: + Added antialiasing support. + Dithering, antialiasing and background mode can now be selected at runtime. * src/caca.c src/caca.h: + Renamed caca_dithering into caca_feature and extended the type to express background colour and antialiasing mode. * examples/demo.c: + Fixed a bug that disabled the sprite demo. + Draw solid flares. * examples/view.c: + Select antialiasing and background mode at runtime. --- examples/aafire.c | 1 - examples/demo.c | 18 +- examples/view.c | 67 ++++-- src/bitmap.c | 510 ++++++++++++++++++++++--------------------- src/caca.c | 83 ++++++- src/caca.h | 43 +++- src/caca_internals.h | 6 + 7 files changed, 430 insertions(+), 298 deletions(-) diff --git a/examples/aafire.c b/examples/aafire.c index 077c6b4..d19e026 100644 --- a/examples/aafire.c +++ b/examples/aafire.c @@ -133,7 +133,6 @@ initialize (void) caca_bitmap = caca_create_bitmap(8, XSIZ, YSIZ - 2, XSIZ, 0, 0, 0, 0); caca_set_bitmap_palette(caca_bitmap, r, g, b, a); bitmap = malloc(XSIZ * YSIZ * sizeof(char)); - caca_set_dithering(CACA_DITHERING_ORDERED8); #else aa_hidecursor (context); #endif diff --git a/examples/demo.c b/examples/demo.c index 69b840a..eee919b 100644 --- a/examples/demo.c +++ b/examples/demo.c @@ -131,6 +131,7 @@ int main(int argc, char **argv) case 'S': if(sprite) demo = demo_sprites; + break; case 'r': case 'R': demo = demo_render; @@ -501,7 +502,7 @@ static void demo_render(void) struct caca_bitmap *bitmap; int buffer[256*256]; int *dest; - int x, y, z, t, xo, yo; + int x, y, z, xo, yo; static int i = 0; i++; @@ -510,31 +511,26 @@ static void demo_render(void) for(x = 0; x < 256; x++) for(y = 0; y < 256; y++) { - *dest++ = 0; + *dest++ = 0xff000000; } /* red */ xo = 128 + 48 * sin(0.02 * i); yo = 128 + 48 * cos(0.03 * i); - t = 256 * (2.0 + sin(4 + 0.017 * i)) / 3; for(z = 0; z < 240; z++) - draw_circle(buffer, xo, yo, z, 0x00ff0000, - ((255 - z) * t / 256) << 16); + draw_circle(buffer, xo, yo, z, 0x00ff0000, 200 << 16); /* green */ xo = 128 + 48 * sin(2 + 0.06 * i); yo = 128 + 48 * cos(2 + 0.05 * i); - t = 256 * (2.0 + sin(8 + 0.021 * i)) / 3; for(z = 0; z < 240; z++) - draw_circle(buffer, xo, yo, z, 0x0000ff00, - ((255 - z) * t / 256) << 8); + draw_circle(buffer, xo, yo, z, 0x0000ff00, 200 << 8); /* blue */ xo = 128 + 48 * sin(1 + 0.04 * i); yo = 128 + 48 * cos(1 + 0.03 * i); - t = 256 * (2.0 + sin(3 + 0.033 * i)) / 3; for(z = 0; z < 240; z++) - draw_circle(buffer, xo, yo, z, 0x000000ff, (255 - z) * t / 256); + draw_circle(buffer, xo, yo, z, 0x000000ff, 200); bitmap = caca_create_bitmap(32, 256, 256, 4 * 256, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); caca_draw_bitmap(0, 0, caca_get_width() - 1, caca_get_height() - 1, @@ -547,7 +543,7 @@ static void draw_circle(int *buffer, int x, int y, int r, int mask, int val) int t, dx, dy; #define POINT(X,Y) \ - buffer[(X) + 256 * (Y)] = (buffer[(X) + 256 * (Y)] & ~mask) | val; + buffer[(X) + 256 * (Y)] = 0xff000000 | (buffer[(X) + 256 * (Y)] & ~mask) | val; for(t = 0, dx = 0, dy = r; dx <= dy; dx++) { diff --git a/examples/view.c b/examples/view.c index 5b011a8..a09db88 100644 --- a/examples/view.c +++ b/examples/view.c @@ -46,7 +46,6 @@ int x, y, w, h; int main(int argc, char **argv) { int quit = 0, update = 1, help = 0, reload = 0, fullscreen = 0, zoom = 0; - int dithering = CACA_DITHERING_ORDERED4; char **list = NULL; int current = 0, items = 0, opts = 1; @@ -108,12 +107,40 @@ int main(int argc, char **argv) fullscreen = ~fullscreen; update = 1; break; + case CACA_EVENT_KEY_PRESS | 'b': + i = 1 + caca_get_feature(CACA_BACKGROUND); + if(i > CACA_BACKGROUND_MAX) i = CACA_BACKGROUND_MIN; + caca_set_feature(i); + update = 1; + break; + case CACA_EVENT_KEY_PRESS | 'B': + i = -1 + caca_get_feature(CACA_BACKGROUND); + if(i < CACA_BACKGROUND_MIN) i = CACA_BACKGROUND_MAX; + caca_set_feature(i); + update = 1; + break; + case CACA_EVENT_KEY_PRESS | 'a': + i = 1 + caca_get_feature(CACA_ANTIALIASING); + if(i > CACA_ANTIALIASING_MAX) i = CACA_ANTIALIASING_MIN; + caca_set_feature(i); + update = 1; + break; + case CACA_EVENT_KEY_PRESS | 'A': + i = -1 + caca_get_feature(CACA_ANTIALIASING); + if(i < CACA_ANTIALIASING_MIN) i = CACA_ANTIALIASING_MAX; + caca_set_feature(i); + update = 1; + break; case CACA_EVENT_KEY_PRESS | 'd': - dithering = (dithering + 1) % 5; + i = 1 + caca_get_feature(CACA_DITHERING); + if(i > CACA_DITHERING_MAX) i = CACA_DITHERING_MIN; + caca_set_feature(i); update = 1; break; case CACA_EVENT_KEY_PRESS | 'D': - dithering = (dithering + 4) % 5; + i = -1 + caca_get_feature(CACA_DITHERING); + if(i < CACA_DITHERING_MIN) i = CACA_DITHERING_MAX; + caca_set_feature(i); update = 1; break; case CACA_EVENT_KEY_PRESS | '+': @@ -191,7 +218,6 @@ int main(int argc, char **argv) } caca_clear(); - caca_set_dithering(dithering); caca_set_color(CACA_COLOR_WHITE, CACA_COLOR_BLUE); if(!items) @@ -249,29 +275,30 @@ int main(int argc, char **argv) { caca_draw_line(0, 0, ww - 1, 0, ' '); caca_draw_line(0, wh - 1, ww - 1, wh - 1, '-'); - caca_putstr(0, 0, "q:Quit n/p:Next/Prev +/-/x:Zoom " - "h/j/k/l: Move d:Dithering"); + caca_putstr(0, 0, "q:Quit np:Next/Prev +-x:Zoom " + "hjkl:Move d:Dithering a:Antialias"); caca_putstr(ww - strlen("?:Help"), 0, "?:Help"); - caca_printf(3, wh - 1, "cacaview %s", VERSION); - caca_printf(ww / 2 - 5, wh - 1, "(%s dithering)", - caca_get_dithering_name(dithering)); + caca_printf(3, wh - 1, "cacaview %s (%s, %s)", VERSION, + caca_get_feature_name(caca_get_feature(CACA_DITHERING)), + caca_get_feature_name(caca_get_feature(CACA_ANTIALIASING))); caca_printf(ww - 14, wh - 1, "(zoom: %s%i)", zoom > 0 ? "+" : "", zoom); } if(help) { - caca_putstr(ww - 22, 2, " +: zoom in "); - caca_putstr(ww - 22, 3, " -: zoom out "); - caca_putstr(ww - 22, 4, " x: reset zoom "); - caca_putstr(ww - 22, 5, " ------------------- "); - caca_putstr(ww - 22, 6, " hjkl: move view "); - caca_putstr(ww - 22, 7, " arrows: move view "); - caca_putstr(ww - 22, 8, " ------------------- "); - caca_putstr(ww - 22, 9, " d: dithering method "); - caca_putstr(ww - 22, 10, " ------------------- "); - caca_putstr(ww - 22, 11, " ?: help "); - caca_putstr(ww - 22, 12, " q: quit "); + caca_putstr(ww - 22, 2, " +: zoom in "); + caca_putstr(ww - 22, 3, " -: zoom out "); + caca_putstr(ww - 22, 4, " x: reset zoom "); + caca_putstr(ww - 22, 5, " ---------------------- "); + caca_putstr(ww - 22, 6, " hjkl: move view "); + caca_putstr(ww - 22, 7, " arrows: move view "); + caca_putstr(ww - 22, 8, " ---------------------- "); + caca_putstr(ww - 22, 9, " a: antialiasing method "); + caca_putstr(ww - 22, 9, " d: dithering method "); + caca_putstr(ww - 22, 10, " ---------------------- "); + caca_putstr(ww - 22, 11, " ?: help "); + caca_putstr(ww - 22, 12, " q: quit "); help = 0; } diff --git a/src/bitmap.c b/src/bitmap.c index 248097e..35a67fe 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -46,8 +46,16 @@ typedef unsigned int uint32_t; #include "caca.h" #include "caca_internals.h" -#define NEW_RENDERER 1 +/* + * Global variables + */ +enum caca_feature _caca_background; +enum caca_feature _caca_dithering; +enum caca_feature _caca_antialiasing; +/* + * Local prototypes + */ static void mask2shift(unsigned int, int *, int *); static void get_rgba_default(const struct caca_bitmap *, uint8_t *, int, int, @@ -76,54 +84,6 @@ static void init_random_dither(int); static unsigned int get_random_dither(void); static void increment_random_dither(void); -/* Current dithering method */ -static enum caca_dithering _caca_dithering = CACA_DITHERING_NONE; - -static void (*_init_dither) (int) = init_no_dither; -static unsigned int (*_get_dither) (void) = get_no_dither; -static void (*_increment_dither) (void) = increment_no_dither; - -void caca_set_dithering(enum caca_dithering dither) -{ - switch(dither) - { - case CACA_DITHERING_NONE: - _init_dither = init_no_dither; - _get_dither = get_no_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; - _increment_dither = increment_ordered4_dither; - break; - - case CACA_DITHERING_ORDERED8: - _init_dither = init_ordered8_dither; - _get_dither = get_ordered8_dither; - _increment_dither = increment_ordered8_dither; - break; - - case CACA_DITHERING_RANDOM: - _init_dither = init_random_dither; - _get_dither = get_random_dither; - _increment_dither = increment_random_dither; - break; - - default: - return; - } - - _caca_dithering = dither; -} - struct caca_bitmap { int bpp, palette; @@ -287,17 +247,17 @@ static void get_rgba_default(const struct caca_bitmap *bitmap, uint8_t *pixels, if(bitmap->palette) { - *r = bitmap->red[bits]; - *g = bitmap->green[bits]; - *b = bitmap->blue[bits]; - *a = bitmap->alpha[bits]; + *r += bitmap->red[bits]; + *g += bitmap->green[bits]; + *b += bitmap->blue[bits]; + *a += bitmap->alpha[bits]; } else { - *r = ((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft; - *g = ((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft; - *b = ((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft; - *a = ((bits & bitmap->amask) >> bitmap->aright) << bitmap->aleft; + *r += ((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft; + *g += ((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft; + *b += ((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft; + *a += ((bits & bitmap->amask) >> bitmap->aright) << bitmap->aleft; } } @@ -334,7 +294,12 @@ static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val) void caca_draw_bitmap(int x1, int y1, int x2, int y2, const struct caca_bitmap *bitmap, void *pixels) { -#if !NEW_RENDERER + /* Current dithering method */ + void (*_init_dither) (int); + unsigned int (*_get_dither) (void); + void (*_increment_dither) (void); + + /* Only used when background is black */ static const int white_colors[] = { CACA_COLOR_BLACK, @@ -342,7 +307,6 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2, CACA_COLOR_LIGHTGRAY, CACA_COLOR_WHITE }; -#endif static const int light_colors[] = { @@ -403,222 +367,276 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2, int tmp = y2; y2 = y1; y1 = tmp; } + switch(_caca_dithering) + { + case CACA_DITHERING_NONE: + _init_dither = init_no_dither; + _get_dither = get_no_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; + _increment_dither = increment_ordered4_dither; + break; + + case CACA_DITHERING_ORDERED8: + _init_dither = init_ordered8_dither; + _get_dither = get_ordered8_dither; + _increment_dither = increment_ordered8_dither; + break; + + case CACA_DITHERING_RANDOM: + _init_dither = init_random_dither; + _get_dither = get_random_dither; + _increment_dither = increment_random_dither; + break; + + default: + /* Something wicked happened! */ + return; + } + for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)_caca_height; y++) for(x = x1 > 0 ? x1 : 0, _init_dither(y); x <= x2 && x <= (int)_caca_width; x++) { int ch; - unsigned int r, g, b, a, R, G, B; + unsigned int r, g, b, a; int hue, sat, val; - int fromx = w * (x - x1) / (x2 - x1 + 1); - int fromy = h * (y - y1) / (y2 - y1 + 1); + int fromx, fromy, tox, toy, myx, myy, dots; enum caca_color outfg, outbg; char outch; -#if NEW_RENDERER + + /* Only used by coloured background */ int distbg, distfg, dist, hue1, hue2; -#endif - /* Clip values (yuck) */ - if(fromx == 0) fromx = 1; - if(fromy == 0) fromy = 1; + r = g = b = a = 0; /* First get RGB */ - R = 0, G = 0, B = 0; - get_rgba_default(bitmap, pixels, fromx, fromy, &r, &g, &b, &a); - if(a == 0) - continue; -#if 1 - R += r; G += g; B += b; -#else - R += r; G += g; B += b; - get_rgba_default(bitmap, pixels, fromx - 1, fromy, &r, &g, &b, &a); - R += r; G += g; B += b; - get_rgba_default(bitmap, pixels, fromx, fromy - 1, &r, &g, &b, &a); - R += r; G += g; B += b; - get_rgba_default(bitmap, pixels, fromx + 1, fromy, &r, &g, &b, &a); - R += r; G += g; B += b; - get_rgba_default(bitmap, pixels, fromx, fromy + 1, &r, &g, &b, &a); - R += r; G += g; B += b; - R /= 5; G /= 5; B /= 5; -#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_RENDERER -# define XRATIO 5*5 -# define YRATIO 3*3 -# define HRATIO 2*2 -# define FUZZINESS XRATIO * 0x800 - - /* distance to black */ - distbg = XRATIO * val * val; - distbg += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - distbg = distbg * 2 / 4; - outbg = CACA_COLOR_BLACK; - - /* distance to 30% */ - dist = XRATIO * (val - 0x600) * (val - 0x600) - + YRATIO * sat * sat; - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - dist = dist * 3 / 2; - if(dist <= distbg) + if(_caca_antialiasing == CACA_ANTIALIASING_PREFILTER) { - outfg = outbg; - distfg = distbg; - outbg = CACA_COLOR_DARKGRAY; - distbg = dist; + fromx = ((x - x1) * (w - 1)) / (x2 - x1 + 1); + fromy = ((y - y1) * (h - 1)) / (y2 - y1 + 1); + tox = ((x - x1 + 1) * (w - 1)) / (x2 - x1 + 1); + toy = ((y - y1 + 1) * (h - 1)) / (y2 - y1 + 1); + dots = 0; + + for(myx = fromx; myx <= tox; myx++) + for(myy = fromy; myy <= toy; myy++) + { + dots++; + get_rgba_default(bitmap, pixels, myx, myy, &r, &g, &b, &a); + } + + /* Normalize */ + r /= dots; + g /= dots; + b /= dots; + a /= dots; } else { - outfg = CACA_COLOR_DARKGRAY; - distfg = dist; - } + fromx = ((x - x1) * (w - 1)) / (x2 - x1 + 1); + fromy = ((y - y1) * (h - 1)) / (y2 - y1 + 1); + tox = ((x - x1 + 1) * (w - 1)) / (x2 - x1 + 1); + toy = ((y - y1 + 1) * (h - 1)) / (y2 - y1 + 1); - /* check dist to 70% */ - dist = XRATIO * (val - 0xa00) * (val - 0xa00) - + YRATIO * sat * sat; - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - dist = dist * 3 / 2; - if(dist <= distbg) - { - outfg = outbg; - distfg = distbg; - outbg = CACA_COLOR_LIGHTGRAY; - distbg = dist; - } - else if(dist <= distfg) - { - outfg = CACA_COLOR_LIGHTGRAY; - distfg = dist; - } + myx = (fromx + tox) / 2; + myy = (fromy + toy) / 2; - /* check dist to white */ - dist = XRATIO * (val - 0x1000) * (val - 0x1000) - + YRATIO * sat * sat; - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - if(dist <= distbg) - { - outfg = outbg; - distfg = distbg; - outbg = CACA_COLOR_WHITE; - distbg = dist; - } - else if(dist <= distfg) - { - outfg = CACA_COLOR_WHITE; - distfg = dist; + get_rgba_default(bitmap, pixels, myx, myy, &r, &g, &b, &a); } - hue1 = (hue + 0x800) & ~0xfff; - if(hue > hue1) - hue2 = (hue + 0x1800) & ~0xfff; - else - hue2 = (hue - 0x800) & ~0xfff; - - /* check dist to 2nd closest dark color */ - dist = XRATIO * (val - 0x600) * (val - 0x600) - + YRATIO * (sat - 0x1000) * (sat - 0x1000) - + HRATIO * (hue - hue2) * (hue - hue2); - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; -// dist = dist * 3 / 4; - if(dist <= distbg) - { - outfg = outbg; - distfg = distbg; - outbg = dark_colors[hue2 / 0x1000]; - distbg = dist; - } - else if(dist <= distfg) - { - outfg = dark_colors[hue2 / 0x1000]; - distfg = dist; - } + if(a < 0x100) + continue; - /* check dist to 2nd closest light color */ - dist = XRATIO * (val - 0x1000) * (val - 0x1000) - + YRATIO * (sat - 0x1000) * (sat - 0x1000) - + HRATIO * (hue - hue2) * (hue - hue2); - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - //dist = dist * 3 / 4; - //dist = dist / 2; - if(dist <= distbg) - { - outfg = outbg; - distfg = distbg; - outbg = light_colors[hue2 / 0x1000]; - distbg = dist; - } - else if(dist <= distfg) - { - outfg = light_colors[hue2 / 0x1000]; - distfg = dist; - } + /* Now get HSV from RGB */ + rgb2hsv_default(r, g, b, &hue, &sat, &val); - /* check dist to closest dark color */ - dist = XRATIO * (val - 0x600) * (val - 0x600) - + YRATIO * (sat - 0x1000) * (sat - 0x1000) - + HRATIO * (hue - hue1) * (hue - hue1); - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - dist = dist * 3 / 4; - if(dist <= distbg) + /* The hard work: calculate foreground and background colours, + * as well as the most appropriate character to output. */ + if(_caca_background == CACA_BACKGROUND_SOLID) { - outfg = outbg; - distfg = distbg; - outbg = dark_colors[hue1 / 0x1000]; - distbg = dist; +# define XRATIO 5*5 +# define YRATIO 3*3 +# define HRATIO 2*2 +# define FUZZINESS XRATIO * 0x800 + + /* distance to black */ + distbg = XRATIO * val * val; + distbg += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + distbg = distbg * 2 / 4; + outbg = CACA_COLOR_BLACK; + + /* distance to 30% */ + dist = XRATIO * (val - 0x600) * (val - 0x600) + + YRATIO * sat * sat; + dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + dist = dist * 3 / 2; + 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 += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + dist = dist * 3 / 2; + 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 += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = CACA_COLOR_WHITE; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = CACA_COLOR_WHITE; + distfg = dist; + } + + hue1 = (hue + 0x800) & ~0xfff; + if(hue > hue1) + hue2 = (hue + 0x1800) & ~0xfff; + else + hue2 = (hue - 0x800) & ~0xfff; + + /* check dist to 2nd closest dark color */ + dist = XRATIO * (val - 0x600) * (val - 0x600) + + YRATIO * (sat - 0x1000) * (sat - 0x1000) + + HRATIO * (hue - hue2) * (hue - hue2); + dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + //dist = dist * 3 / 4; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = dark_colors[hue2 / 0x1000]; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = dark_colors[hue2 / 0x1000]; + distfg = dist; + } + + /* check dist to 2nd closest light color */ + dist = XRATIO * (val - 0x1000) * (val - 0x1000) + + YRATIO * (sat - 0x1000) * (sat - 0x1000) + + HRATIO * (hue - hue2) * (hue - hue2); + dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + //dist = dist * 3 / 4; + //dist = dist / 2; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = light_colors[hue2 / 0x1000]; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = light_colors[hue2 / 0x1000]; + distfg = dist; + } + + /* check dist to closest dark color */ + dist = XRATIO * (val - 0x600) * (val - 0x600) + + YRATIO * (sat - 0x1000) * (sat - 0x1000) + + HRATIO * (hue - hue1) * (hue - hue1); + dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + dist = dist * 3 / 4; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = dark_colors[hue1 / 0x1000]; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = dark_colors[hue1 / 0x1000]; + distfg = dist; + } + + /* check dist to closest light color */ + dist = XRATIO * (val - 0x1000) * (val - 0x1000) + + YRATIO * (sat - 0x1000) * (sat - 0x1000) + + HRATIO * (hue - hue1) * (hue - hue1); + dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; + dist = dist / 2; + if(dist <= distbg) + { + outfg = outbg; + distfg = distbg; + outbg = light_colors[hue1 / 0x1000]; + distbg = dist; + } + else if(dist <= distfg) + { + outfg = light_colors[hue1 / 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 if(dist <= distfg) + else { - outfg = dark_colors[hue1 / 0x1000]; - distfg = dist; - } + outbg = CACA_COLOR_BLACK; + if((unsigned int)sat < 0x200 + _get_dither() * 0x8) + outfg = white_colors[1 + (val * 2 + _get_dither() * 0x10) + / 0x1000]; + else if((unsigned int)val > 0x800 + _get_dither() * 0x4) + outfg = light_colors[(hue + _get_dither() * 0x10) / 0x1000]; + else + outfg = dark_colors[(hue + _get_dither() * 0x10) / 0x1000]; - /* check dist to closest light color */ - dist = XRATIO * (val - 0x1000) * (val - 0x1000) - + YRATIO * (sat - 0x1000) * (sat - 0x1000) - + HRATIO * (hue - hue1) * (hue - hue1); - dist += FUZZINESS * _get_dither() - 0x80 * FUZZINESS; - dist = dist / 2; - if(dist <= distbg) - { - outfg = outbg; - distfg = distbg; - outbg = light_colors[hue1 / 0x1000]; - distbg = dist; - } - else if(dist <= distfg) - { - outfg = light_colors[hue1 / 0x1000]; - distfg = dist; + ch = (val + 0x2 * _get_dither()) * 10 / 0x1000; + ch = 4 * ch + _get_dither() / 0x40; + outch = density_chars[ch]; } - 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((unsigned int)sat < 0x200 + _get_dither() * 0x8) - outfg = white_colors[1 + (val * 2 + _get_dither() * 0x10) / 0x1000]; - else if((unsigned int)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); diff --git a/src/caca.c b/src/caca.c index 56f2630..d887d4c 100644 --- a/src/caca.c +++ b/src/caca.c @@ -48,6 +48,7 @@ #include "caca.h" #include "caca_internals.h" +static void caca_init_features(void); static void caca_init_terminal(void); #if defined(USE_NCURSES) @@ -60,6 +61,7 @@ int caca_init(void) mmask_t newmask; #endif + caca_init_features(); caca_init_terminal(); #if defined(USE_SLANG) @@ -156,21 +158,73 @@ const char *caca_get_color_name(enum caca_color color) return color_names[color]; } -const char *caca_get_dithering_name(enum caca_dithering dithering) +enum caca_feature caca_get_feature(enum caca_feature feature) { - static const char *dithering_names[] = + switch(feature) { - "no", - "2x2 ordered", - "4x4 ordered", - "8x8 ordered", - "random" - }; + case CACA_BACKGROUND: + return _caca_background; + case CACA_ANTIALIASING: + return _caca_antialiasing; + case CACA_DITHERING: + return _caca_dithering; + + default: + return CACA_UNKNOWN_FEATURE; + } +} - if(dithering < 0 || dithering > 4) - return "unknown"; +void caca_set_feature(enum caca_feature feature) +{ + switch(feature) + { + case CACA_BACKGROUND: + feature = CACA_BACKGROUND_SOLID; + case CACA_BACKGROUND_BLACK: + case CACA_BACKGROUND_SOLID: + _caca_background = feature; + break; + + case CACA_ANTIALIASING: + feature = CACA_ANTIALIASING_PREFILTER; + case CACA_ANTIALIASING_NONE: + case CACA_ANTIALIASING_PREFILTER: + _caca_antialiasing = feature; + break; + + case CACA_DITHERING: + feature = CACA_DITHERING_ORDERED4; + case CACA_DITHERING_NONE: + case CACA_DITHERING_ORDERED2: + case CACA_DITHERING_ORDERED4: + case CACA_DITHERING_ORDERED8: + case CACA_DITHERING_RANDOM: + _caca_dithering = feature; + break; + + case CACA_UNKNOWN_FEATURE: + break; + } +} - return dithering_names[dithering]; +const char *caca_get_feature_name(enum caca_feature feature) +{ + switch(feature) + { + case CACA_BACKGROUND_BLACK: return "black background"; + case CACA_BACKGROUND_SOLID: return "solid background"; + + case CACA_ANTIALIASING_NONE: return "no antialiasing"; + case CACA_ANTIALIASING_PREFILTER: return "prefilter antialiasing"; + + case CACA_DITHERING_NONE: return "no dithering"; + case CACA_DITHERING_ORDERED2: return "2x2 ordered dithering"; + case CACA_DITHERING_ORDERED4: return "4x4 ordered dithering"; + case CACA_DITHERING_ORDERED8: return "8x8 ordered dithering"; + case CACA_DITHERING_RANDOM: return "random dithering"; + + default: return "unknown"; + } } void caca_end(void) @@ -194,6 +248,13 @@ void caca_end(void) #endif } +static void caca_init_features(void) +{ + caca_set_feature(CACA_BACKGROUND); + caca_set_feature(CACA_ANTIALIASING); + caca_set_feature(CACA_DITHERING); +} + static void caca_init_terminal(void) { #if defined(HAVE_GETENV) && defined(HAVE_PUTENV) diff --git a/src/caca.h b/src/caca.h index f78dff7..a85843f 100644 --- a/src/caca.h +++ b/src/caca.h @@ -84,20 +84,44 @@ enum caca_color const char *caca_get_color_name(enum caca_color); /** - * The dithering modes to be used with caca_set_dithering(). + * The internal libcaca features. */ -enum caca_dithering +enum caca_feature { - CACA_DITHERING_NONE = 0, - CACA_DITHERING_ORDERED2 = 1, - CACA_DITHERING_ORDERED4 = 2, - CACA_DITHERING_ORDERED8 = 3, - CACA_DITHERING_RANDOM = 4 + /* Properties of background characters */ + CACA_BACKGROUND = 0x10, + CACA_BACKGROUND_BLACK = 0x11, + CACA_BACKGROUND_SOLID = 0x12, +#define CACA_BACKGROUND_MIN 0x11 +#define CACA_BACKGROUND_MAX 0x12 + + /* Antialiasing features */ + CACA_ANTIALIASING = 0x20, + CACA_ANTIALIASING_NONE = 0x21, + CACA_ANTIALIASING_PREFILTER = 0x22, +#define CACA_ANTIALIASING_MIN 0x21 +#define CACA_ANTIALIASING_MAX 0x22 + + /* Dithering methods */ + CACA_DITHERING = 0x30, + CACA_DITHERING_NONE = 0x31, + CACA_DITHERING_ORDERED2 = 0x32, + CACA_DITHERING_ORDERED4 = 0x33, + CACA_DITHERING_ORDERED8 = 0x34, + CACA_DITHERING_RANDOM = 0x35, +#define CACA_DITHERING_MIN 0x31 +#define CACA_DITHERING_MAX 0x35 + + /* Unknown feature */ + CACA_UNKNOWN_FEATURE = 0xffff }; -const char *caca_get_dithering_name(enum caca_dithering); +const char *caca_get_feature_name(enum caca_feature); /* Backwards compatibility */ +#define caca_dithering caca_feature +#define caca_set_dithering caca_set_feature +#define caca_get_dithering_name caca_get_feature_name #define CACA_DITHER_NONE CACA_DITHERING_NONE #define CACA_DITHER_ORDERED CACA_DITHERING_ORDERED8 #define CACA_DITHER_RANDOM CACA_DITHERING_RANDOM @@ -145,7 +169,8 @@ enum caca_key */ int caca_init(void); void caca_set_delay(unsigned int); -void caca_set_dithering(enum caca_dithering); +enum caca_feature caca_get_feature(enum caca_feature); +void caca_set_feature(enum caca_feature); unsigned int caca_get_rendertime(void); unsigned int caca_get_width(void); unsigned int caca_get_height(void); diff --git a/src/caca_internals.h b/src/caca_internals.h index 36113ef..189c8fa 100644 --- a/src/caca_internals.h +++ b/src/caca_internals.h @@ -32,7 +32,13 @@ extern int _caca_init_graphics(void); +/* Cached screen size */ extern unsigned int _caca_width; extern unsigned int _caca_height; +/* Internal libcaca features */ +extern enum caca_feature _caca_background; +extern enum caca_feature _caca_dithering; +extern enum caca_feature _caca_antialiasing; + #endif /* __CACA_INTERNALS_H__ */