選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

463 行
11 KiB

  1. /*
  2. * libcaca ASCII-Art library
  3. * Copyright (c) 2002, 2003 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  19. * 02111-1307 USA
  20. */
  21. /** \file bitmap.c
  22. * \version \$Id$
  23. * \author Sam Hocevar <sam@zoy.org>
  24. * \brief Bitmap functions
  25. *
  26. * This file contains bitmap blitting functions.
  27. */
  28. #include "config.h"
  29. #ifdef HAVE_INTTYPES_H
  30. # include <inttypes.h>
  31. #else
  32. typedef unsigned char uint8_t;
  33. typedef unsigned short uint16_t;
  34. typedef unsigned int uint32_t;
  35. #endif
  36. #include <stdlib.h>
  37. #include "caca.h"
  38. #include "caca_internals.h"
  39. static void mask2shift(int, int *, int *);
  40. static void get_rgb_default(struct caca_bitmap *, unsigned char *,
  41. int, int, int *, int *, int *);
  42. static void rgb2hsv_default(int, int, int, int *, int *, int *);
  43. /* Dithering methods */
  44. static void init_no_dither(int);
  45. static int get_no_dither(void);
  46. static void increment_no_dither(void);
  47. static void init_ordered_dither(int);
  48. static int get_ordered_dither(void);
  49. static void increment_ordered_dither(void);
  50. static void init_random_dither(int);
  51. static int get_random_dither(void);
  52. static void increment_random_dither(void);
  53. /* Current dithering method */
  54. static enum caca_dithering _caca_dithering = CACA_DITHER_NONE;
  55. static void (*_init_dither) (int) = init_no_dither;
  56. static int (*_get_dither) (void) = get_no_dither;
  57. static void (*_increment_dither) (void) = increment_no_dither;
  58. void caca_set_dithering(enum caca_dithering dither)
  59. {
  60. switch(dither)
  61. {
  62. case CACA_DITHER_NONE:
  63. _init_dither = init_no_dither;
  64. _get_dither = get_no_dither;
  65. _increment_dither = increment_no_dither;
  66. break;
  67. case CACA_DITHER_ORDERED:
  68. _init_dither = init_ordered_dither;
  69. _get_dither = get_ordered_dither;
  70. _increment_dither = increment_ordered_dither;
  71. break;
  72. case CACA_DITHER_RANDOM:
  73. _init_dither = init_random_dither;
  74. _get_dither = get_random_dither;
  75. _increment_dither = increment_random_dither;
  76. break;
  77. default:
  78. return;
  79. }
  80. _caca_dithering = dither;
  81. }
  82. struct caca_bitmap
  83. {
  84. int bpp, palette;
  85. int w, h, pitch;
  86. int rmask, gmask, bmask;
  87. int rright, gright, bright;
  88. int rleft, gleft, bleft;
  89. void (*get_hsv)(struct caca_bitmap *, char *, int, int);
  90. int red[256], green[256], blue[256];
  91. };
  92. static void mask2shift(int mask, int *right, int *left)
  93. {
  94. int rshift = 0, lshift = 0;
  95. *right = *left = 0;
  96. if(!mask)
  97. return;
  98. while(!(mask & 1))
  99. {
  100. mask >>= 1;
  101. rshift++;
  102. }
  103. *right = rshift;
  104. while(mask & 1)
  105. {
  106. mask >>= 1;
  107. lshift++;
  108. }
  109. *left = 16 - lshift;
  110. }
  111. struct caca_bitmap *caca_create_bitmap(int bpp, int w, int h, int pitch,
  112. int rmask, int gmask, int bmask)
  113. {
  114. struct caca_bitmap *bitmap;
  115. /* Currently only this format is supported. Will improve later. */
  116. if(!w || !h || !pitch || bpp > 32 || bpp < 8)
  117. return NULL;
  118. bitmap = malloc(sizeof(struct caca_bitmap));
  119. if(!bitmap)
  120. return NULL;
  121. bitmap->bpp = bpp;
  122. bitmap->palette = 0;
  123. bitmap->w = w;
  124. bitmap->h = h;
  125. bitmap->pitch = pitch;
  126. bitmap->rmask = rmask;
  127. bitmap->gmask = gmask;
  128. bitmap->bmask = bmask;
  129. /* Load bitmasks */
  130. if(rmask || gmask || bmask)
  131. {
  132. mask2shift(rmask, &bitmap->rright, &bitmap->rleft);
  133. mask2shift(gmask, &bitmap->gright, &bitmap->gleft);
  134. mask2shift(bmask, &bitmap->bright, &bitmap->bleft);
  135. }
  136. /* In 8 bpp mode, default to a grayscale palette */
  137. if(bpp == 8)
  138. {
  139. int i;
  140. bitmap->palette = 1;
  141. for(i = 0; i < 256; i++)
  142. {
  143. bitmap->red[i] = i * 0x100;
  144. bitmap->green[i] = i * 0x100;
  145. bitmap->blue[i] = i * 0x100;
  146. }
  147. }
  148. return bitmap;
  149. }
  150. void caca_set_bitmap_palette(struct caca_bitmap *bitmap,
  151. int red[], int green[], int blue[])
  152. {
  153. int i;
  154. if(bitmap->bpp != 8)
  155. return;
  156. for(i = 0; i < 256; i++)
  157. {
  158. if(red[i] >= 0 && red[i] < 65536 &&
  159. green[i] >= 0 && green[i] < 65536 &&
  160. blue[i] >= 0 && blue[i] < 65536)
  161. {
  162. bitmap->red[i] = red[i];
  163. bitmap->green[i] = green[i];
  164. bitmap->blue[i] = blue[i];
  165. }
  166. }
  167. }
  168. void caca_free_bitmap(struct caca_bitmap *bitmap)
  169. {
  170. if(!bitmap)
  171. return;
  172. free(bitmap);
  173. }
  174. static void get_rgb_default(struct caca_bitmap *bitmap, unsigned char *pixels,
  175. int x, int y, int *r, int *g, int *b)
  176. {
  177. int bits;
  178. pixels += (bitmap->bpp / 8) * x + bitmap->pitch * y;
  179. switch(bitmap->bpp / 8)
  180. {
  181. case 4:
  182. bits = *(uint32_t *)(pixels + 0);
  183. break;
  184. case 3:
  185. bits = (pixels[0] << 16)
  186. | (pixels[1] << 8)
  187. | (pixels[2]);
  188. break;
  189. case 2:
  190. bits = *(uint16_t *)(pixels + 0);
  191. break;
  192. case 1:
  193. default:
  194. bits = pixels[0];
  195. break;
  196. }
  197. if(bitmap->palette)
  198. {
  199. *r = bitmap->red[bits];
  200. *g = bitmap->green[bits];
  201. *b = bitmap->blue[bits];
  202. }
  203. else
  204. {
  205. *r = ((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft;
  206. *g = ((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft;
  207. *b = ((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft;
  208. }
  209. }
  210. static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val)
  211. {
  212. int min, max, delta;
  213. min = r; max = r;
  214. if(min > g) min = g; if(max < g) max = g;
  215. if(min > b) min = b; if(max < b) max = b;
  216. delta = max - min; /* 0 - 65535 */
  217. *val = max; /* 0 - 65535 */
  218. *sat = max ? 0x100 * delta / max * 0x100: 0; /* 0 - 65536 */
  219. if(*sat > (_get_dither() + 24) * 0x400)
  220. {
  221. /* XXX: Values should be between 1 and 6, but since we
  222. * are dithering, there may be overflows, hence our bigger
  223. * *_colors[] tables. */
  224. if( r == max )
  225. *hue = 0x10000 + 0x100 * (g - b) / delta * 0x100;
  226. else if( g == max )
  227. *hue = 0x30000 + 0x100 * (b - r) / delta * 0x100;
  228. else
  229. *hue = 0x50000 + 0x100 * (r - g) / delta * 0x100;
  230. *hue = (*hue + 0x8000 + 0x1000 * _get_dither()) / 0x10000;
  231. }
  232. else
  233. {
  234. *sat = 0;
  235. }
  236. }
  237. void caca_draw_bitmap(int x1, int y1, int x2, int y2,
  238. struct caca_bitmap *bitmap, char *pixels)
  239. {
  240. /* FIXME: this code is shite! */
  241. static int white_colors[] =
  242. {
  243. CACA_COLOR_DARKGRAY,
  244. CACA_COLOR_LIGHTGRAY,
  245. CACA_COLOR_WHITE
  246. };
  247. static int light_colors[] =
  248. {
  249. CACA_COLOR_LIGHTMAGENTA,
  250. CACA_COLOR_LIGHTRED,
  251. CACA_COLOR_YELLOW,
  252. CACA_COLOR_LIGHTGREEN,
  253. CACA_COLOR_LIGHTCYAN,
  254. CACA_COLOR_LIGHTBLUE,
  255. CACA_COLOR_LIGHTMAGENTA
  256. };
  257. static int dark_colors[] =
  258. {
  259. CACA_COLOR_MAGENTA,
  260. CACA_COLOR_RED,
  261. CACA_COLOR_BROWN,
  262. CACA_COLOR_GREEN,
  263. CACA_COLOR_CYAN,
  264. CACA_COLOR_BLUE,
  265. CACA_COLOR_MAGENTA
  266. };
  267. static char foo[] =
  268. {
  269. ' ', ' ', ' ', ' ',
  270. ',', '`', '.', '\'',
  271. 'i', '-', ':', '^',
  272. '|', '/', ';', '\\',
  273. '=', '+', 'o', 'x',
  274. '<', 'x', '%', '>',
  275. '&', 'z', '$', 'w',
  276. 'W', 'X', 'K', 'M',
  277. '#', '8', '#', '#',
  278. '8', '@', '8', '#',
  279. '@', '8', '@', '8',
  280. };
  281. int x, y, w, h, pitch;
  282. if(!bitmap || !pixels)
  283. return;
  284. w = bitmap->w;
  285. h = bitmap->h;
  286. pitch = bitmap->pitch;
  287. if(x1 > x2)
  288. {
  289. int tmp = x2; x2 = x1; x1 = tmp;
  290. }
  291. if(y1 > y2)
  292. {
  293. int tmp = y2; y2 = y1; y1 = tmp;
  294. }
  295. for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)caca_get_height(); y++)
  296. {
  297. /* Initialize dither tables for the current line */
  298. _init_dither(y);
  299. /* Dither the current line */
  300. for(x = x1 > 0 ? x1 : 0; x <= x2 && x <= (int)caca_get_width(); x++)
  301. {
  302. int ch;
  303. int hue, sat, val, r, g, b, R, G, B;
  304. int fromx = w * (x - x1) / (x2 - x1 + 1);
  305. int fromy = h * (y - y1) / (y2 - y1 + 1);
  306. /* First get RGB */
  307. R = 0, G = 0, B = 0;
  308. get_rgb_default(bitmap, pixels, fromx, fromy, &r, &g, &b);
  309. R += r; G += g; B += b;
  310. get_rgb_default(bitmap, pixels, fromx - 1, fromy, &r, &g, &b);
  311. R += r; G += g; B += b;
  312. get_rgb_default(bitmap, pixels, fromx, fromy - 1, &r, &g, &b);
  313. R += r; G += g; B += b;
  314. get_rgb_default(bitmap, pixels, fromx + 1, fromy, &r, &g, &b);
  315. R += r; G += g; B += b;
  316. get_rgb_default(bitmap, pixels, fromx, fromy + 1, &r, &g, &b);
  317. R += r; G += g; B += b;
  318. R /= 5; G /= 5; B /= 5;
  319. /* Now get HSV from RGB */
  320. rgb2hsv_default(R, G, B, &hue, &sat, &val);
  321. if(!sat)
  322. caca_set_color(white_colors[val * 3 / 0x10000], CACA_COLOR_BLACK);
  323. else if(val > (_get_dither() + 40) * 0x400)
  324. caca_set_color(light_colors[hue], CACA_COLOR_BLACK);
  325. else
  326. caca_set_color(dark_colors[hue], CACA_COLOR_BLACK);
  327. /* FIXME: choose better characters! */
  328. ch = (val + 0x200 * _get_dither()) * 10 / 0x10000;
  329. ch = 4 * ch + (_get_dither() + 8) / 4;
  330. caca_putchar(x, y, foo[ch]);
  331. _increment_dither();
  332. }
  333. }
  334. }
  335. /*
  336. * XXX: The following functions are local.
  337. */
  338. /*
  339. * No dithering
  340. */
  341. static void init_no_dither(int line)
  342. {
  343. ;
  344. }
  345. static int get_no_dither(void)
  346. {
  347. return 0;
  348. }
  349. static void increment_no_dither(void)
  350. {
  351. return;
  352. }
  353. /*
  354. * Ordered dithering
  355. */
  356. static int dither4x4[] = {-8, 0, -6, 2,
  357. 4, -4, 6, -2,
  358. -5, 3, -7, 1,
  359. 7, -1, 5, -3};
  360. static int *dither_table;
  361. static int dither_index;
  362. static void init_ordered_dither(int line)
  363. {
  364. dither_table = dither4x4 + (line % 4) * 4;
  365. dither_index = 0;
  366. }
  367. static int get_ordered_dither(void)
  368. {
  369. return dither_table[dither_index];
  370. }
  371. static void increment_ordered_dither(void)
  372. {
  373. dither_index = (dither_index + 1) % 4;
  374. }
  375. /*
  376. * Random dithering
  377. */
  378. static void init_random_dither(int line)
  379. {
  380. ;
  381. }
  382. static int get_random_dither(void)
  383. {
  384. return caca_rand(-8, 7);
  385. }
  386. static void increment_random_dither(void)
  387. {
  388. return;
  389. }