ソースを参照

* 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 <endian.h>.
  * examples/demo.c examples/view.c:
    + Fixed an endianness issue in cacaview.
    + Adapted code to the additional dithering method.
tags/v0.99.beta14
Sam Hocevar sam 21年前
コミット
cda43d3563
6個のファイルの変更257行の追加77行の削除
  1. +2
    -2
      configure.ac
  2. +1
    -1
      examples/demo.c
  3. +23
    -5
      examples/view.c
  4. +225
    -65
      src/bitmap.c
  5. +2
    -1
      src/caca.c
  6. +4
    -3
      src/caca.h

+ 2
- 2
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


+ 1
- 1
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;


+ 23
- 5
examples/view.c ファイルの表示

@@ -28,6 +28,10 @@
#include <malloc.h>
#include <unistd.h>

#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif

#include <Imlib2.h>

#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();


+ 225
- 65
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 <stdio.h>
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"
"<x%>"
"&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
*/


+ 2
- 1
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];


+ 4
- 3
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);


読み込み中…
キャンセル
保存