Вы не можете выбрать более 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) | (pixels[1] << 8) | (pixels[2]);
  186. break;
  187. case 2:
  188. bits = *(uint16_t *)(pixels + 0);
  189. break;
  190. case 1:
  191. default:
  192. bits = pixels[0];
  193. break;
  194. }
  195. if(bitmap->palette)
  196. {
  197. *r = bitmap->red[bits];
  198. *g = bitmap->green[bits];
  199. *b = bitmap->blue[bits];
  200. }
  201. else
  202. {
  203. *r = ((bits & bitmap->rmask) >> bitmap->rright) << bitmap->rleft;
  204. *g = ((bits & bitmap->gmask) >> bitmap->gright) << bitmap->gleft;
  205. *b = ((bits & bitmap->bmask) >> bitmap->bright) << bitmap->bleft;
  206. }
  207. }
  208. static void rgb2hsv_default(int r, int g, int b, int *hue, int *sat, int *val)
  209. {
  210. int min, max, delta;
  211. min = r; max = r;
  212. if(min > g) min = g; if(max < g) max = g;
  213. if(min > b) min = b; if(max < b) max = b;
  214. delta = max - min; /* 0 - 0xffff */
  215. *val = max; /* 0 - 0xffff */
  216. if(delta)
  217. {
  218. *sat = 0x1000 * delta / max * 0x10; /* 0 - 0xffff */
  219. /* Generate *hue between 0 and 0x5ffff */
  220. if( r == max )
  221. *hue = 0x10000 + 0x100 * (g - b) / delta * 0x100;
  222. else if( g == max )
  223. *hue = 0x30000 + 0x100 * (b - r) / delta * 0x100;
  224. else
  225. *hue = 0x50000 + 0x100 * (r - g) / delta * 0x100;
  226. }
  227. else
  228. {
  229. *sat = 0;
  230. *hue = 0;
  231. }
  232. }
  233. void caca_draw_bitmap(int x1, int y1, int x2, int y2,
  234. struct caca_bitmap *bitmap, char *pixels)
  235. {
  236. /* FIXME: this code is shite! */
  237. static int white_colors[] =
  238. {
  239. CACA_COLOR_DARKGRAY,
  240. CACA_COLOR_LIGHTGRAY,
  241. CACA_COLOR_WHITE
  242. };
  243. static int light_colors[] =
  244. {
  245. CACA_COLOR_LIGHTMAGENTA,
  246. CACA_COLOR_LIGHTRED,
  247. CACA_COLOR_YELLOW,
  248. CACA_COLOR_LIGHTGREEN,
  249. CACA_COLOR_LIGHTCYAN,
  250. CACA_COLOR_LIGHTBLUE,
  251. CACA_COLOR_LIGHTMAGENTA
  252. };
  253. static int dark_colors[] =
  254. {
  255. CACA_COLOR_MAGENTA,
  256. CACA_COLOR_RED,
  257. CACA_COLOR_BROWN,
  258. CACA_COLOR_GREEN,
  259. CACA_COLOR_CYAN,
  260. CACA_COLOR_BLUE,
  261. CACA_COLOR_MAGENTA
  262. };
  263. static char foo[] =
  264. {
  265. ' ', ' ', ' ', ' ',
  266. ',', '`', '.', '\'',
  267. 'i', '-', ':', '^',
  268. '|', '/', ';', '\\',
  269. '=', '+', 'o', 'x',
  270. '<', 'x', '%', '>',
  271. '&', 'z', '$', 'w',
  272. 'W', 'X', 'K', 'M',
  273. '#', '8', '#', '#',
  274. '8', '@', '8', '#',
  275. '@', '8', '@', '8',
  276. };
  277. int x, y, w, h, pitch;
  278. if(!bitmap || !pixels)
  279. return;
  280. w = bitmap->w;
  281. h = bitmap->h;
  282. pitch = bitmap->pitch;
  283. if(x1 > x2)
  284. {
  285. int tmp = x2; x2 = x1; x1 = tmp;
  286. }
  287. if(y1 > y2)
  288. {
  289. int tmp = y2; y2 = y1; y1 = tmp;
  290. }
  291. for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)caca_get_height(); y++)
  292. {
  293. /* Initialize dither tables for the current line */
  294. _init_dither(y);
  295. /* Dither the current line */
  296. for(x = x1 > 0 ? x1 : 0; x <= x2 && x <= (int)caca_get_width(); x++)
  297. {
  298. int ch;
  299. int hue, sat, val, r, g, b, R, G, B;
  300. int fromx = w * (x - x1) / (x2 - x1 + 1);
  301. int fromy = h * (y - y1) / (y2 - y1 + 1);
  302. /* Clip values (yuck) */
  303. if(fromx == 0) fromx = 1;
  304. if(fromy == 0) fromy = 1;
  305. /* First get RGB */
  306. R = 0, G = 0, B = 0;
  307. get_rgb_default(bitmap, pixels, fromx, fromy, &r, &g, &b);
  308. R += r; G += g; B += b;
  309. get_rgb_default(bitmap, pixels, fromx - 1, fromy, &r, &g, &b);
  310. R += r; G += g; B += b;
  311. get_rgb_default(bitmap, pixels, fromx, fromy - 1, &r, &g, &b);
  312. R += r; G += g; B += b;
  313. get_rgb_default(bitmap, pixels, fromx + 1, fromy, &r, &g, &b);
  314. R += r; G += g; B += b;
  315. get_rgb_default(bitmap, pixels, fromx, fromy + 1, &r, &g, &b);
  316. R += r; G += g; B += b;
  317. R /= 5; G /= 5; B /= 5;
  318. /* Now get HSV from RGB */
  319. rgb2hsv_default(R, G, B, &hue, &sat, &val);
  320. if(sat < 0x6000 + _get_dither() * 0x800)
  321. caca_set_color(white_colors[val * 3 / 0x10000], CACA_COLOR_BLACK);
  322. else if(val > (_get_dither() + 40) * 0x400)
  323. caca_set_color(light_colors[(hue + 0x8000 + _get_dither() * 0x1000) / 0x10000], CACA_COLOR_BLACK);
  324. else
  325. caca_set_color(dark_colors[(hue + 0x8000 + _get_dither() * 0x1000) / 0x10000], CACA_COLOR_BLACK);
  326. /* FIXME: choose better characters! */
  327. ch = (val + 0x200 * _get_dither()) * 10 / 0x10000;
  328. ch = 4 * ch + (_get_dither() + 8) / 4;
  329. caca_putchar(x, y, foo[ch]);
  330. _increment_dither();
  331. }
  332. }
  333. }
  334. /*
  335. * XXX: The following functions are local.
  336. */
  337. /*
  338. * No dithering
  339. */
  340. static void init_no_dither(int line)
  341. {
  342. ;
  343. }
  344. static int get_no_dither(void)
  345. {
  346. return 0;
  347. }
  348. static void increment_no_dither(void)
  349. {
  350. return;
  351. }
  352. /*
  353. * Ordered dithering
  354. */
  355. static int dither4x4[] = {-8, 0, -6, 2,
  356. 4, -4, 6, -2,
  357. -5, 3, -7, 1,
  358. 7, -1, 5, -3};
  359. static int *dither_table;
  360. static int dither_index;
  361. static void init_ordered_dither(int line)
  362. {
  363. dither_table = dither4x4 + (line % 4) * 4;
  364. dither_index = 0;
  365. }
  366. static int get_ordered_dither(void)
  367. {
  368. return dither_table[dither_index];
  369. }
  370. static void increment_ordered_dither(void)
  371. {
  372. dither_index = (dither_index + 1) % 4;
  373. }
  374. /*
  375. * Random dithering
  376. */
  377. static void init_random_dither(int line)
  378. {
  379. ;
  380. }
  381. static int get_random_dither(void)
  382. {
  383. return caca_rand(-8, 7);
  384. }
  385. static void increment_random_dither(void)
  386. {
  387. return;
  388. }