ソースを参照

* src/bitmap.c: Support for more colour depths.

tags/v0.99.beta14
Sam Hocevar sam 21年前
コミット
dd4d9c3a81
1個のファイルの変更223行の追加44行の削除
  1. +223
    -44
      src/bitmap.c

+ 223
- 44
src/bitmap.c ファイルの表示

@@ -40,6 +40,12 @@ typedef unsigned char uint8_t;
#include "caca.h"
#include "caca_internals.h"

static void mask2shift(int, int *, int *);

static void get_rgb_default(struct caca_bitmap *, unsigned char *,
int, int, int *, int *, int *);
static void rgb2hsv_default(int, int, int, int *, int *, int *);

/* Dithering methods */
static void init_no_dither(int);
static int get_no_dither(void);
@@ -91,19 +97,45 @@ void caca_set_dithering(enum caca_dithering dither)

struct caca_bitmap
{
int bpp;
int bpp, palette;
int w, h, pitch;
int rmask, gmask, bmask;
int rright, gright, bright;
int rleft, gleft, bleft;
void (*get_hsv)(struct caca_bitmap *, char *, int, int);
int red[256], green[256], blue[256];
};

static void mask2shift(int mask, int *right, int *left)
{
int rshift = 0, lshift = 0;
*right = *left = 0;

if(!mask)
return;

while(!(mask & 1))
{
mask >>= 1;
rshift++;
}
*right = rshift;

while(mask & 1)
{
mask >>= 1;
lshift++;
}
*left = 16 - lshift;
}

struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch,
int rmask, int gmask, int bmask)
{
struct caca_bitmap *bitmap;

/* Currently only this format is supported. Will improve later. */
if(!w || !h || !pitch || bpp != 32 ||
rmask != 0x00ff0000 || gmask != 0x0000ff00 || bmask != 0x000000ff)
if(!w || !h || !pitch || bpp > 32 || bpp < 8)
return NULL;

bitmap = malloc(sizeof(struct caca_bitmap));
@@ -111,6 +143,7 @@ struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch,
return NULL;

bitmap->bpp = bpp;
bitmap->palette = 0;

bitmap->w = w;
bitmap->h = h;
@@ -120,9 +153,51 @@ struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch,
bitmap->gmask = gmask;
bitmap->bmask = bmask;

/* Load bitmasks */
if(rmask || gmask || bmask)
{
mask2shift(rmask, &bitmap->rright, &bitmap->rleft);
mask2shift(gmask, &bitmap->gright, &bitmap->gleft);
mask2shift(bmask, &bitmap->bright, &bitmap->bleft);
}

/* In 8 bpp mode, default to a grayscale palette */
if(bpp == 8)
{
int i;
bitmap->palette = 1;
for(i = 0; i < 256; i++)
{
bitmap->red[i] = i * 0x100;
bitmap->green[i] = i * 0x100;
bitmap->blue[i] = i * 0x100;
}
}

return bitmap;
}

void caca_set_bitmap_palette(struct caca_bitmap *bitmap,
int red[], int green[], int blue[])
{
int i;

if(bitmap->bpp != 8)
return;

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)
{
bitmap->red[i] = red[i];
bitmap->green[i] = green[i];
bitmap->blue[i] = blue[i];
}
}
}

void caca_free_bitmap(struct caca_bitmap *bitmap)
{
if(!bitmap)
@@ -131,14 +206,126 @@ void caca_free_bitmap(struct caca_bitmap *bitmap)
free(bitmap);
}

static void get_rgb_default(struct caca_bitmap *bitmap, unsigned char *pixels,
int x, int y, int *r, int *g, int *b)
{
int bits;

pixels += (bitmap->bpp / 8) * x + bitmap->pitch * y;

switch(bitmap->bpp / 8)
{
case 4:
bits = *(uint32_t *)(pixels + 0);
break;
case 3:
bits = (pixels[0] << 16)
| (pixels[1] << 8)
| (pixels[2]);
break;
case 2:
bits = *(uint16_t *)(pixels + 0);
break;
case 1:
default:
bits = pixels[0];
break;
}

if(bitmap->palette)
{
*r = bitmap->red[bits];
*g = bitmap->green[bits];
*b = bitmap->blue[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;
}
}

static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val)
{
int min, max, delta;

min = r; max = r;
if(min > g) min = g; if(max < g) max = g;
if(min > b) min = b; if(max < b) max = b;

delta = max - min; /* 0 - 65535 */
*val = max; /* 0 - 65535 */
*sat = max ? 0x100 * delta / max * 0x100: 0; /* 0 - 65536 */

if(*sat > (_get_dither() + 24) * 0x400)
{
/* 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 = 0x10000 + 0x100 * (g - b) / delta * 0x100;
else if( g == max )
*hue = 0x30000 + 0x100 * (b - r) / delta * 0x100;
else
*hue = 0x50000 + 0x100 * (r - g) / delta * 0x100;

*hue = (*hue + 0x8000 + 0x1000 * _get_dither()) / 0x10000;
}
else
{
*sat = 0;
}
}

void caca_draw_bitmap(int x1, int y1, int x2, int y2,
struct caca_bitmap *bitmap, char *pixels)
{
/* FIXME: this code is shite! */
static int white_colors[] = {CACA_COLOR_DARKGRAY, CACA_COLOR_LIGHTGRAY, CACA_COLOR_WHITE};
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', '@' };
static int white_colors[] =
{
CACA_COLOR_DARKGRAY,
CACA_COLOR_LIGHTGRAY,
CACA_COLOR_WHITE
};

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[] =
{
' ', ' ', ' ', ' ',
',', '`', '.', '\'',
'i', '-', ':', '^',
'|', '/', ';', '\\',
'=', '+', 'o', 'x',
'<', 'x', '%', '>',
'&', 'z', '$', '§',
'W', 'X', 'K', 'M',
'#', '8', '#', '#',
'8', '@', '8', '#',
'@', '8', '@', '8',
};

int x, y, w, h, pitch;

if(!bitmap || !pixels)
@@ -166,47 +353,39 @@ void caca_draw_bitmap(int x1, int y1, int x2, int y2,
/* Dither the current line */
for(x = x1 > 0 ? x1 : 0; x <= x2 && x <= (int)caca_get_width(); x++)
{
int ch;
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);
/* FIXME: bwahaaa, we don't even respect masks */
int b = ((unsigned char *)pixels)[4 * fromx + pitch * fromy];
int g = ((unsigned char *)pixels)[4 * fromx + 1 + pitch * fromy];
int r = ((unsigned char *)pixels)[4 * fromx + 2 + pitch * fromy];
int hue, sat, val;

int min = r, max = r, delta;
if(min > g) min = g; if(max < g) max = g;
if(min > b) min = b; if(max < b) max = b;

delta = max - min;
val = max; /* 0 - 255 */
sat = max ? 256 * delta / max : 0; /* 0 - 255 */

if(sat > (_get_dither() + 24) * 4)
{
/* 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 = 256 + 256 * (g - b) / delta;
else if( g == max )
hue = 768 + 256 * (b - r) / delta;
else
hue = 1280 + 256 * (r - g) / delta;

hue = (hue + 128 + 16 * _get_dither()) / 256;

if(val > (_get_dither() + 40) * 4)
caca_set_color(light_colors[hue]);
else
caca_set_color(dark_colors[hue]);
}

/* 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)
caca_set_color(white_colors[val * 3 / 0x10000], CACA_COLOR_BLACK);
else if(val > (_get_dither() + 40) * 0x400)
caca_set_color(light_colors[hue], CACA_COLOR_BLACK);
else
{
caca_set_color(white_colors[max * 3 / 256]);
}
caca_set_color(dark_colors[hue], CACA_COLOR_BLACK);

caca_putchar(x, y, foo[(r + g + b + 2 * _get_dither()) / 3 / 25]);
/* FIXME: choose better characters! */
ch = (val + 0x200 * _get_dither()) * 10 / 0x10000;
ch = 4 * ch + (_get_dither() + 8) / 4;
caca_putchar(x, y, foo[ch]);

_increment_dither();
}


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