您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

1568 行
41 KiB

  1. /*
  2. * libcucul Canvas for ultrafast compositing of Unicode letters
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * This file contains bitmap dithering functions.
  16. */
  17. #include "config.h"
  18. #if !defined(__KERNEL__)
  19. # if defined(HAVE_ENDIAN_H)
  20. # include <endian.h>
  21. # endif
  22. # include <stdio.h>
  23. # include <stdlib.h>
  24. # include <limits.h>
  25. # include <string.h>
  26. #endif
  27. #include "cucul.h"
  28. #include "cucul_internals.h"
  29. #define CP437 0
  30. /*
  31. * Local variables
  32. */
  33. #if !defined(_DOXYGEN_SKIP_ME)
  34. # define LOOKUP_VAL 32
  35. # define LOOKUP_SAT 32
  36. # define LOOKUP_HUE 16
  37. #endif
  38. static uint8_t hsv_distances[LOOKUP_VAL][LOOKUP_SAT][LOOKUP_HUE];
  39. static uint16_t lookup_colors[8];
  40. static int lookup_initialised = 0;
  41. static int const hsv_palette[] =
  42. {
  43. /* weight, hue, saturation, value */
  44. 4, 0x0, 0x0, 0x0, /* black */
  45. 5, 0x0, 0x0, 0x5ff, /* 30% */
  46. 5, 0x0, 0x0, 0x9ff, /* 70% */
  47. 4, 0x0, 0x0, 0xfff, /* white */
  48. 3, 0x1000, 0xfff, 0x5ff, /* dark yellow */
  49. 2, 0x1000, 0xfff, 0xfff, /* light yellow */
  50. 3, 0x0, 0xfff, 0x5ff, /* dark red */
  51. 2, 0x0, 0xfff, 0xfff /* light red */
  52. };
  53. /* RGB palette for the new colour picker */
  54. static int const rgb_palette[] =
  55. {
  56. 0x0, 0x0, 0x0,
  57. 0x0, 0x0, 0x7ff,
  58. 0x0, 0x7ff, 0x0,
  59. 0x0, 0x7ff, 0x7ff,
  60. 0x7ff, 0x0, 0x0,
  61. 0x7ff, 0x0, 0x7ff,
  62. 0x7ff, 0x7ff, 0x0,
  63. 0xaaa, 0xaaa, 0xaaa,
  64. 0x555, 0x555, 0x555,
  65. 0x000, 0x000, 0xfff,
  66. 0x000, 0xfff, 0x000,
  67. 0x000, 0xfff, 0xfff,
  68. 0xfff, 0x000, 0x000,
  69. 0xfff, 0x000, 0xfff,
  70. 0xfff, 0xfff, 0x000,
  71. 0xfff, 0xfff, 0xfff,
  72. };
  73. static int const rgb_weight[] =
  74. {
  75. /* 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2 */
  76. 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  77. };
  78. /* List of glyphs */
  79. static uint32_t ascii_glyphs[] =
  80. {
  81. ' ', '.', ':', ';', 't', '%', 'S', 'X', '@', '8', '?'
  82. };
  83. static uint32_t shades_glyphs[] =
  84. {
  85. /* ' '. '·', '░', '▒', '?' */
  86. ' ', 0xb7, 0x2591, 0x2592, '?'
  87. };
  88. static uint32_t blocks_glyphs[] =
  89. {
  90. /* ' ', '▘', '▚', '?' */
  91. ' ', 0x2598, 0x259a, '?'
  92. };
  93. #if !defined(_DOXYGEN_SKIP_ME)
  94. enum color_mode
  95. {
  96. COLOR_MODE_MONO,
  97. COLOR_MODE_GRAY,
  98. COLOR_MODE_8,
  99. COLOR_MODE_16,
  100. COLOR_MODE_FULLGRAY,
  101. COLOR_MODE_FULL8,
  102. COLOR_MODE_FULL16
  103. };
  104. struct cucul_dither
  105. {
  106. int bpp, has_palette, has_alpha;
  107. int w, h, pitch;
  108. int rmask, gmask, bmask, amask;
  109. int rright, gright, bright, aright;
  110. int rleft, gleft, bleft, aleft;
  111. void (*get_hsv)(cucul_dither_t *, char *, int, int);
  112. int red[256], green[256], blue[256], alpha[256];
  113. /* Colour features */
  114. float gamma, brightness, contrast;
  115. int gammatab[4097];
  116. /* Dithering features */
  117. char const *antialias_name;
  118. int antialias;
  119. char const *color_name;
  120. enum color_mode color;
  121. char const *algo_name;
  122. void (*init_dither) (int);
  123. unsigned int (*get_dither) (void);
  124. void (*increment_dither) (void);
  125. char const *glyph_name;
  126. uint32_t const * glyphs;
  127. unsigned glyph_count;
  128. int invert;
  129. };
  130. #define HSV_XRATIO 6
  131. #define HSV_YRATIO 3
  132. #define HSV_HRATIO 3
  133. #define HSV_DISTANCE(h, s, v, index) \
  134. (hsv_palette[index * 4] \
  135. * ((HSV_XRATIO * ((v) - hsv_palette[index * 4 + 3]) \
  136. * ((v) - hsv_palette[index * 4 + 3])) \
  137. + (hsv_palette[index * 4 + 3] \
  138. ? (HSV_YRATIO * ((s) - hsv_palette[index * 4 + 2]) \
  139. * ((s) - hsv_palette[index * 4 + 2])) \
  140. : 0) \
  141. + (hsv_palette[index * 4 + 2] \
  142. ? (HSV_HRATIO * ((h) - hsv_palette[index * 4 + 1]) \
  143. * ((h) - hsv_palette[index * 4 + 1])) \
  144. : 0)))
  145. #endif
  146. /*
  147. * Local prototypes
  148. */
  149. static void mask2shift(uint32_t, int *, int *);
  150. static float gammapow(float x, float y);
  151. static void get_rgba_default(cucul_dither_t const *, uint8_t *, int, int,
  152. unsigned int *);
  153. static int init_lookup(void);
  154. /* Dithering algorithms */
  155. static void init_no_dither(int);
  156. static unsigned int get_no_dither(void);
  157. static void increment_no_dither(void);
  158. static void init_fstein_dither(int);
  159. static unsigned int get_fstein_dither(void);
  160. static void increment_fstein_dither(void);
  161. static void init_ordered2_dither(int);
  162. static unsigned int get_ordered2_dither(void);
  163. static void increment_ordered2_dither(void);
  164. static void init_ordered4_dither(int);
  165. static unsigned int get_ordered4_dither(void);
  166. static void increment_ordered4_dither(void);
  167. static void init_ordered8_dither(int);
  168. static unsigned int get_ordered8_dither(void);
  169. static void increment_ordered8_dither(void);
  170. static void init_random_dither(int);
  171. static unsigned int get_random_dither(void);
  172. static void increment_random_dither(void);
  173. static inline int sq(int x)
  174. {
  175. return x * x;
  176. }
  177. static inline void rgb2hsv_default(int r, int g, int b,
  178. int *hue, int *sat, int *val)
  179. {
  180. int min, max, delta;
  181. min = r; max = r;
  182. if(min > g) min = g; if(max < g) max = g;
  183. if(min > b) min = b; if(max < b) max = b;
  184. delta = max - min; /* 0 - 0xfff */
  185. *val = max; /* 0 - 0xfff */
  186. if(delta)
  187. {
  188. *sat = 0xfff * delta / max; /* 0 - 0xfff */
  189. /* Generate *hue between 0 and 0x5fff */
  190. if( r == max )
  191. *hue = 0x1000 + 0x1000 * (g - b) / delta;
  192. else if( g == max )
  193. *hue = 0x3000 + 0x1000 * (b - r) / delta;
  194. else
  195. *hue = 0x5000 + 0x1000 * (r - g) / delta;
  196. }
  197. else
  198. {
  199. *sat = 0;
  200. *hue = 0;
  201. }
  202. }
  203. /** \brief Create an internal dither object.
  204. *
  205. * Create a dither structure from its coordinates (depth, width, height and
  206. * pitch) and pixel mask values. If the depth is 8 bits per pixel, the mask
  207. * values are ignored and the colour palette should be set using the
  208. * cucul_set_dither_palette() function. For depths greater than 8 bits per
  209. * pixel, a zero alpha mask causes the alpha values to be ignored.
  210. *
  211. * If an error occurs, NULL is returned and \b errno is set accordingly:
  212. * - \c EINVAL Requested width, height, pitch or bits per pixel value was
  213. * invalid.
  214. * - \c ENOMEM Not enough memory to allocate dither structure.
  215. *
  216. * \param bpp Bitmap depth in bits per pixel.
  217. * \param w Bitmap width in pixels.
  218. * \param h Bitmap height in pixels.
  219. * \param pitch Bitmap pitch in bytes.
  220. * \param rmask Bitmask for red values.
  221. * \param gmask Bitmask for green values.
  222. * \param bmask Bitmask for blue values.
  223. * \param amask Bitmask for alpha values.
  224. * \return Dither object upon success, NULL if an error occurred.
  225. */
  226. cucul_dither_t *cucul_create_dither(unsigned int bpp, unsigned int w,
  227. unsigned int h, unsigned int pitch,
  228. uint32_t rmask, uint32_t gmask,
  229. uint32_t bmask, uint32_t amask)
  230. {
  231. cucul_dither_t *d;
  232. int i;
  233. /* Minor sanity test */
  234. if(!w || !h || !pitch || bpp > 32 || bpp < 8)
  235. {
  236. seterrno(EINVAL);
  237. return NULL;
  238. }
  239. d = malloc(sizeof(cucul_dither_t));
  240. if(!d)
  241. {
  242. seterrno(ENOMEM);
  243. return NULL;
  244. }
  245. if(!lookup_initialised)
  246. {
  247. /* XXX: because we do not wish to be thread-safe, there is a slight
  248. * chance that the following code will be executed twice. It is
  249. * totally harmless. */
  250. init_lookup();
  251. lookup_initialised = 1;
  252. }
  253. d->bpp = bpp;
  254. d->has_palette = 0;
  255. d->has_alpha = amask ? 1 : 0;
  256. d->w = w;
  257. d->h = h;
  258. d->pitch = pitch;
  259. d->rmask = rmask;
  260. d->gmask = gmask;
  261. d->bmask = bmask;
  262. d->amask = amask;
  263. /* Load bitmasks */
  264. if(rmask || gmask || bmask || amask)
  265. {
  266. mask2shift(rmask, &d->rright, &d->rleft);
  267. mask2shift(gmask, &d->gright, &d->gleft);
  268. mask2shift(bmask, &d->bright, &d->bleft);
  269. mask2shift(amask, &d->aright, &d->aleft);
  270. }
  271. /* In 8 bpp mode, default to a grayscale palette */
  272. if(bpp == 8)
  273. {
  274. d->has_palette = 1;
  275. d->has_alpha = 0;
  276. for(i = 0; i < 256; i++)
  277. {
  278. d->red[i] = i * 0xfff / 256;
  279. d->green[i] = i * 0xfff / 256;
  280. d->blue[i] = i * 0xfff / 256;
  281. }
  282. }
  283. /* Default gamma value */
  284. d->gamma = 1.0;
  285. for(i = 0; i < 4096; i++)
  286. d->gammatab[i] = i;
  287. /* Default colour properties */
  288. d->brightness = 1.0;
  289. d->contrast = 1.0;
  290. /* Default features */
  291. d->antialias_name = "prefilter";
  292. d->antialias = 1;
  293. d->color_name = "full16";
  294. d->color = COLOR_MODE_FULL16;
  295. d->glyph_name = "ascii";
  296. d->glyphs = ascii_glyphs;
  297. d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
  298. d->algo_name = "fstein";
  299. d->init_dither = init_fstein_dither;
  300. d->get_dither = get_fstein_dither;
  301. d->increment_dither = increment_fstein_dither;
  302. d->invert = 0;
  303. return d;
  304. }
  305. /** \brief Set the palette of an 8bpp dither object.
  306. *
  307. * Set the palette of an 8 bits per pixel bitmap. Values should be between
  308. * 0 and 4095 (0xfff).
  309. *
  310. * If an error occurs, -1 is returned and \b errno is set accordingly:
  311. * - \c EINVAL Dither bits per pixel value is not 8, or one of the pixel
  312. * values was outside the range 0 - 4095.
  313. *
  314. * \param d Dither object.
  315. * \param red Array of 256 red values.
  316. * \param green Array of 256 green values.
  317. * \param blue Array of 256 blue values.
  318. * \param alpha Array of 256 alpha values.
  319. * \return 0 in case of success, -1 if an error occurred.
  320. */
  321. int cucul_set_dither_palette(cucul_dither_t *d,
  322. unsigned int red[], unsigned int green[],
  323. unsigned int blue[], unsigned int alpha[])
  324. {
  325. int i, has_alpha = 0;
  326. if(d->bpp != 8)
  327. {
  328. seterrno(EINVAL);
  329. return -1;
  330. }
  331. for(i = 0; i < 256; i++)
  332. {
  333. if((red[i] | green[i] | blue[i] | alpha[i]) >= 0x1000)
  334. {
  335. seterrno(EINVAL);
  336. return -1;
  337. }
  338. }
  339. for(i = 0; i < 256; i++)
  340. {
  341. d->red[i] = red[i];
  342. d->green[i] = green[i];
  343. d->blue[i] = blue[i];
  344. if(alpha[i])
  345. {
  346. d->alpha[i] = alpha[i];
  347. has_alpha = 1;
  348. }
  349. }
  350. d->has_alpha = has_alpha;
  351. return 0;
  352. }
  353. /** \brief Set the brightness of a dither object.
  354. *
  355. * Set the brightness of dither.
  356. *
  357. * If an error occurs, -1 is returned and \b errno is set accordingly:
  358. * - \c EINVAL Brightness value was out of range.
  359. *
  360. * \param d Dither object.
  361. * \param brightness brightness value.
  362. * \return 0 in case of success, -1 if an error occurred.
  363. */
  364. int cucul_set_dither_brightness(cucul_dither_t *d, float brightness)
  365. {
  366. /* FIXME */
  367. d->brightness = brightness;
  368. return 0;
  369. }
  370. /** \brief Get the brightness of a dither object.
  371. *
  372. * Get the brightness of the given dither object.
  373. *
  374. * This function never fails.
  375. *
  376. * \param d Dither object.
  377. * \return Brightness value.
  378. */
  379. float cucul_get_dither_brightness(cucul_dither_t const *d)
  380. {
  381. return d->brightness;
  382. }
  383. /** \brief Set the gamma of a dither object.
  384. *
  385. * Set the gamma of the given dither object. A negative value causes
  386. * colour inversion.
  387. *
  388. * If an error occurs, -1 is returned and \b errno is set accordingly:
  389. * - \c EINVAL Gamma value was out of range.
  390. *
  391. * \param d Dither object.
  392. * \param gamma Gamma value.
  393. * \return 0 in case of success, -1 if an error occurred.
  394. */
  395. int cucul_set_dither_gamma(cucul_dither_t *d, float gamma)
  396. {
  397. /* FIXME: we don't need 4096 calls to gammapow(), we could just compute
  398. * a few of them and do linear interpolation for the rest. This will
  399. * probably speed up things a lot. */
  400. int i;
  401. if(gamma < 0.0)
  402. {
  403. d->invert = 1;
  404. gamma = -gamma;
  405. }
  406. else if(gamma == 0.0)
  407. {
  408. seterrno(EINVAL);
  409. return -1;
  410. }
  411. d->gamma = gamma;
  412. for(i = 0; i < 4096; i++)
  413. d->gammatab[i] = 4096.0 * gammapow((float)i / 4096.0, 1.0 / gamma);
  414. return 0;
  415. }
  416. /** \brief Get the gamma of a dither object.
  417. *
  418. * Get the gamma of the given dither object.
  419. *
  420. * This function never fails.
  421. *
  422. * \param d Dither object.
  423. * \return Gamma value.
  424. */
  425. float cucul_get_dither_gamma(cucul_dither_t const *d)
  426. {
  427. return d->gamma;
  428. }
  429. /** \brief Set the contrast of a dither object.
  430. *
  431. * Set the contrast of dither.
  432. *
  433. * If an error occurs, -1 is returned and \b errno is set accordingly:
  434. * - \c EINVAL Contrast value was out of range.
  435. *
  436. * \param d Dither object.
  437. * \param contrast contrast value.
  438. * \return 0 in case of success, -1 if an error occurred.
  439. */
  440. int cucul_set_dither_contrast(cucul_dither_t *d, float contrast)
  441. {
  442. /* FIXME */
  443. d->contrast = contrast;
  444. return 0;
  445. }
  446. /** \brief Get the contrast of a dither object.
  447. *
  448. * Get the contrast of the given dither object.
  449. *
  450. * This function never fails.
  451. *
  452. * \param d Dither object.
  453. * \return Contrast value.
  454. */
  455. float cucul_get_dither_contrast(cucul_dither_t const *d)
  456. {
  457. return d->contrast;
  458. }
  459. /** \brief Set dither antialiasing
  460. *
  461. * Tell the renderer whether to antialias the dither. Antialiasing smoothens
  462. * the rendered image and avoids the commonly seen staircase effect.
  463. * - \c "none": no antialiasing.
  464. * - \c "prefilter" or \c "default": simple prefilter antialiasing. This
  465. * is the default value.
  466. *
  467. * If an error occurs, -1 is returned and \b errno is set accordingly:
  468. * - \c EINVAL Invalid antialiasing mode.
  469. *
  470. * \param d Dither object.
  471. * \param str A string describing the antialiasing method that will be used
  472. * for the dithering.
  473. * \return 0 in case of success, -1 if an error occurred.
  474. */
  475. int cucul_set_dither_antialias(cucul_dither_t *d, char const *str)
  476. {
  477. if(!strcasecmp(str, "none"))
  478. {
  479. d->antialias_name = "none";
  480. d->antialias = 0;
  481. }
  482. else if(!strcasecmp(str, "prefilter") || !strcasecmp(str, "default"))
  483. {
  484. d->antialias_name = "prefilter";
  485. d->antialias = 1;
  486. }
  487. else
  488. {
  489. seterrno(EINVAL);
  490. return -1;
  491. }
  492. return 0;
  493. }
  494. /** \brief Get available antialiasing methods
  495. *
  496. * Return a list of available antialiasing methods for a given dither. The
  497. * list is a NULL-terminated array of strings, interleaving a string
  498. * containing the internal value for the antialiasing method to be used with
  499. * cucul_set_dither_antialias(), and a string containing the natural
  500. * language description for that antialiasing method.
  501. *
  502. * This function never fails.
  503. *
  504. * \param d Dither object.
  505. * \return An array of strings.
  506. */
  507. char const * const *
  508. cucul_get_dither_antialias_list(cucul_dither_t const *d)
  509. {
  510. static char const * const list[] =
  511. {
  512. "none", "No antialiasing",
  513. "prefilter", "Prefilter antialiasing",
  514. NULL, NULL
  515. };
  516. return list;
  517. }
  518. /** \brief Get current antialiasing method
  519. *
  520. * Return the given dither's current antialiasing method.
  521. *
  522. * This function never fails.
  523. *
  524. * \param d Dither object.
  525. * \return A static string.
  526. */
  527. char const * cucul_get_dither_antialias(cucul_dither_t const *d)
  528. {
  529. return d->antialias_name;
  530. }
  531. /** \brief Choose colours used for dithering
  532. *
  533. * Tell the renderer which colours should be used to render the
  534. * bitmap. Valid values for \c str are:
  535. * - \c "mono": use light gray on a black background.
  536. * - \c "gray": use white and two shades of gray on a black background.
  537. * - \c "8": use the 8 ANSI colours on a black background.
  538. * - \c "16": use the 16 ANSI colours on a black background.
  539. * - \c "fullgray": use black, white and two shades of gray for both the
  540. * characters and the background.
  541. * - \c "full8": use the 8 ANSI colours for both the characters and the
  542. * background.
  543. * - \c "full16" or \c "default": use the 16 ANSI colours for both the
  544. * characters and the background. This is the default value.
  545. *
  546. * If an error occurs, -1 is returned and \b errno is set accordingly:
  547. * - \c EINVAL Invalid colour set.
  548. *
  549. * \param d Dither object.
  550. * \param str A string describing the colour set that will be used
  551. * for the dithering.
  552. * \return 0 in case of success, -1 if an error occurred.
  553. */
  554. int cucul_set_dither_color(cucul_dither_t *d, char const *str)
  555. {
  556. if(!strcasecmp(str, "mono"))
  557. {
  558. d->color_name = "mono";
  559. d->color = COLOR_MODE_MONO;
  560. }
  561. else if(!strcasecmp(str, "gray"))
  562. {
  563. d->color_name = "gray";
  564. d->color = COLOR_MODE_GRAY;
  565. }
  566. else if(!strcasecmp(str, "8"))
  567. {
  568. d->color_name = "8";
  569. d->color = COLOR_MODE_8;
  570. }
  571. else if(!strcasecmp(str, "16"))
  572. {
  573. d->color_name = "16";
  574. d->color = COLOR_MODE_16;
  575. }
  576. else if(!strcasecmp(str, "fullgray"))
  577. {
  578. d->color_name = "fullgray";
  579. d->color = COLOR_MODE_FULLGRAY;
  580. }
  581. else if(!strcasecmp(str, "full8"))
  582. {
  583. d->color_name = "full8";
  584. d->color = COLOR_MODE_FULL8;
  585. }
  586. else if(!strcasecmp(str, "full16") || !strcasecmp(str, "default"))
  587. {
  588. d->color_name = "full16";
  589. d->color = COLOR_MODE_FULL16;
  590. }
  591. else
  592. {
  593. seterrno(EINVAL);
  594. return -1;
  595. }
  596. return 0;
  597. }
  598. /** \brief Get available colour modes
  599. *
  600. * Return a list of available colour modes for a given dither. The list
  601. * is a NULL-terminated array of strings, interleaving a string containing
  602. * the internal value for the colour mode, to be used with
  603. * cucul_set_dither_color(), and a string containing the natural
  604. * language description for that colour mode.
  605. *
  606. * This function never fails.
  607. *
  608. * \param d Dither object.
  609. * \return An array of strings.
  610. */
  611. char const * const *
  612. cucul_get_dither_color_list(cucul_dither_t const *d)
  613. {
  614. static char const * const list[] =
  615. {
  616. "mono", "white on black",
  617. "gray", "grayscale on black",
  618. "8", "8 colours on black",
  619. "16", "16 colours on black",
  620. "fullgray", "full grayscale",
  621. "full8", "full 8 colours",
  622. "full16", "full 16 colours",
  623. NULL, NULL
  624. };
  625. return list;
  626. }
  627. /** \brief Get current colour mode
  628. *
  629. * Return the given dither's current colour mode.
  630. *
  631. * This function never fails.
  632. *
  633. * \param d Dither object.
  634. * \return A static string.
  635. */
  636. char const * cucul_get_dither_color(cucul_dither_t const *d)
  637. {
  638. return d->color_name;
  639. }
  640. /** \brief Choose characters used for dithering
  641. *
  642. * Tell the renderer which characters should be used to render the
  643. * dither. Valid values for \c str are:
  644. * - \c "ascii" or \c "default": use only ASCII characters. This is the
  645. * default value.
  646. * - \c "shades": use Unicode characters "U+2591 LIGHT SHADE", "U+2592
  647. * MEDIUM SHADE" and "U+2593 DARK SHADE". These characters are also
  648. * present in the CP437 codepage available on DOS and VGA.
  649. * - \c "blocks": use Unicode quarter-cell block combinations. These
  650. * characters are only found in the Unicode set.
  651. *
  652. * If an error occurs, -1 is returned and \b errno is set accordingly:
  653. * - \c EINVAL Invalid character set.
  654. *
  655. * \param d Dither object.
  656. * \param str A string describing the characters that need to be used
  657. * for the dithering.
  658. * \return 0 in case of success, -1 if an error occurred.
  659. */
  660. int cucul_set_dither_charset(cucul_dither_t *d, char const *str)
  661. {
  662. if(!strcasecmp(str, "shades"))
  663. {
  664. d->glyph_name = "shades";
  665. d->glyphs = shades_glyphs;
  666. d->glyph_count = sizeof(shades_glyphs) / sizeof(*shades_glyphs);
  667. }
  668. else if(!strcasecmp(str, "blocks"))
  669. {
  670. d->glyph_name = "blocks";
  671. d->glyphs = blocks_glyphs;
  672. d->glyph_count = sizeof(blocks_glyphs) / sizeof(*blocks_glyphs);
  673. }
  674. else if(!strcasecmp(str, "ascii") || !strcasecmp(str, "default"))
  675. {
  676. d->glyph_name = "ascii";
  677. d->glyphs = ascii_glyphs;
  678. d->glyph_count = sizeof(ascii_glyphs) / sizeof(*ascii_glyphs);
  679. }
  680. else
  681. {
  682. seterrno(EINVAL);
  683. return -1;
  684. }
  685. return 0;
  686. }
  687. /** \brief Get available dither character sets
  688. *
  689. * Return a list of available character sets for a given dither. The list
  690. * is a NULL-terminated array of strings, interleaving a string containing
  691. * the internal value for the character set, to be used with
  692. * cucul_set_dither_charset(), and a string containing the natural
  693. * language description for that character set.
  694. *
  695. * This function never fails.
  696. *
  697. * \param d Dither object.
  698. * \return An array of strings.
  699. */
  700. char const * const * cucul_get_dither_charset_list(cucul_dither_t const *d)
  701. {
  702. static char const * const list[] =
  703. {
  704. "ascii", "plain ASCII",
  705. "shades", "CP437 shades",
  706. "blocks", "Unicode blocks",
  707. NULL, NULL
  708. };
  709. return list;
  710. }
  711. /** \brief Get current character set
  712. *
  713. * Return the given dither's current character set.
  714. *
  715. * This function never fails.
  716. *
  717. * \param d Dither object.
  718. * \return A static string.
  719. */
  720. char const * cucul_get_dither_charset(cucul_dither_t const *d)
  721. {
  722. return d->glyph_name;
  723. }
  724. /** \brief Set dithering algorithm
  725. *
  726. * Tell the renderer which dithering algorithm should be used. Dithering is
  727. * necessary because the picture being rendered has usually far more colours
  728. * than the available palette. Valid values for \c str are:
  729. * - \c "none": no dithering is used, the nearest matching colour is used.
  730. * - \c "ordered2": use a 2x2 Bayer matrix for dithering.
  731. * - \c "ordered4": use a 4x4 Bayer matrix for dithering.
  732. * - \c "ordered8": use a 8x8 Bayer matrix for dithering.
  733. * - \c "random": use random dithering.
  734. * - \c "fstein": use Floyd-Steinberg dithering. This is the default value.
  735. *
  736. * If an error occurs, -1 is returned and \b errno is set accordingly:
  737. * - \c EINVAL Unknown dithering mode.
  738. *
  739. * \param d Dither object.
  740. * \param str A string describing the algorithm that needs to be used
  741. * for the dithering.
  742. * \return 0 in case of success, -1 if an error occurred.
  743. */
  744. int cucul_set_dither_algorithm(cucul_dither_t *d, char const *str)
  745. {
  746. if(!strcasecmp(str, "none"))
  747. {
  748. d->algo_name = "none";
  749. d->init_dither = init_no_dither;
  750. d->get_dither = get_no_dither;
  751. d->increment_dither = increment_no_dither;
  752. }
  753. else if(!strcasecmp(str, "ordered2"))
  754. {
  755. d->algo_name = "ordered2";
  756. d->init_dither = init_ordered2_dither;
  757. d->get_dither = get_ordered2_dither;
  758. d->increment_dither = increment_ordered2_dither;
  759. }
  760. else if(!strcasecmp(str, "ordered4"))
  761. {
  762. d->algo_name = "ordered4";
  763. d->init_dither = init_ordered4_dither;
  764. d->get_dither = get_ordered4_dither;
  765. d->increment_dither = increment_ordered4_dither;
  766. }
  767. else if(!strcasecmp(str, "ordered8"))
  768. {
  769. d->algo_name = "ordered8";
  770. d->init_dither = init_ordered8_dither;
  771. d->get_dither = get_ordered8_dither;
  772. d->increment_dither = increment_ordered8_dither;
  773. }
  774. else if(!strcasecmp(str, "random"))
  775. {
  776. d->algo_name = "random";
  777. d->init_dither = init_random_dither;
  778. d->get_dither = get_random_dither;
  779. d->increment_dither = increment_random_dither;
  780. }
  781. else if(!strcasecmp(str, "fstein") || !strcasecmp(str, "default"))
  782. {
  783. d->algo_name = "fstein";
  784. d->init_dither = init_fstein_dither;
  785. d->get_dither = get_fstein_dither;
  786. d->increment_dither = increment_fstein_dither;
  787. }
  788. else
  789. {
  790. seterrno(EINVAL);
  791. return -1;
  792. }
  793. return 0;
  794. }
  795. /** \brief Get dithering algorithms
  796. *
  797. * Return a list of available dithering algorithms for a given dither. The
  798. * list is a NULL-terminated array of strings, interleaving a string
  799. * containing the internal value for the dithering algorithm, to be used
  800. * with cucul_set_dither_dithering(), and a string containing the natural
  801. * language description for that algorithm.
  802. *
  803. * This function never fails.
  804. *
  805. * \param d Dither object.
  806. * \return An array of strings.
  807. */
  808. char const * const * cucul_get_dither_algorithm_list(cucul_dither_t const *d)
  809. {
  810. static char const * const list[] =
  811. {
  812. "none", "no dithering",
  813. "ordered2", "2x2 ordered dithering",
  814. "ordered4", "4x4 ordered dithering",
  815. "ordered8", "8x8 ordered dithering",
  816. "random", "random dithering",
  817. "fstein", "Floyd-Steinberg dithering",
  818. NULL, NULL
  819. };
  820. return list;
  821. }
  822. /** \brief Get current dithering algorithm
  823. *
  824. * Return the given dither's current dithering algorithm.
  825. *
  826. * This function never fails.
  827. *
  828. * \param d Dither object.
  829. * \return A static string.
  830. */
  831. char const * cucul_get_dither_algorithm(cucul_dither_t const *d)
  832. {
  833. return d->algo_name;
  834. }
  835. /** \brief Dither a bitmap on the canvas.
  836. *
  837. * Dither a bitmap at the given coordinates. The dither can be of any size
  838. * and will be stretched to the text area.
  839. *
  840. * This function never fails.
  841. *
  842. * \param cv A handle to the libcucul canvas.
  843. * \param x X coordinate of the upper-left corner of the drawing area.
  844. * \param y Y coordinate of the upper-left corner of the drawing area.
  845. * \param w Width of the drawing area.
  846. * \param h Height of the drawing area.
  847. * \param d Dither object to be drawn.
  848. * \param pixels Bitmap's pixels.
  849. * \return This function always returns 0.
  850. */
  851. int cucul_dither_bitmap(cucul_canvas_t *cv, int x, int y, int w, int h,
  852. cucul_dither_t const *d, void *pixels)
  853. {
  854. int *floyd_steinberg, *fs_r, *fs_g, *fs_b;
  855. uint32_t savedattr;
  856. int fs_length;
  857. int x1, y1, x2, y2, pitch, deltax, deltay;
  858. unsigned int dchmax;
  859. if(!d || !pixels)
  860. return 0;
  861. savedattr = cucul_get_attr(cv, -1, -1);
  862. x1 = x; x2 = x + w - 1;
  863. y1 = y; y2 = y + h - 1;
  864. /* FIXME: do not overwrite arguments */
  865. w = d->w;
  866. h = d->h;
  867. pitch = d->pitch;
  868. deltax = x2 - x1 + 1;
  869. deltay = y2 - y1 + 1;
  870. dchmax = d->glyph_count;
  871. fs_length = ((int)cv->width <= x2 ? (int)cv->width : x2) + 1;
  872. floyd_steinberg = malloc(3 * (fs_length + 2) * sizeof(int));
  873. memset(floyd_steinberg, 0, 3 * (fs_length + 2) * sizeof(int));
  874. fs_r = floyd_steinberg + 1;
  875. fs_g = fs_r + fs_length + 2;
  876. fs_b = fs_g + fs_length + 2;
  877. for(y = y1 > 0 ? y1 : 0; y <= y2 && y <= (int)cv->height; y++)
  878. {
  879. int remain_r = 0, remain_g = 0, remain_b = 0;
  880. for(x = x1 > 0 ? x1 : 0, d->init_dither(y);
  881. x <= x2 && x <= (int)cv->width;
  882. x++)
  883. {
  884. unsigned int i;
  885. int ch = 0, distmin;
  886. unsigned int rgba[4];
  887. int fg_r = 0, fg_g = 0, fg_b = 0, bg_r, bg_g, bg_b;
  888. int fromx, fromy, tox, toy, myx, myy, dots, dist;
  889. int error[3];
  890. unsigned int outfg = 0, outbg = 0;
  891. uint32_t outch;
  892. rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
  893. /* First get RGB */
  894. if(d->antialias)
  895. {
  896. fromx = (x - x1) * w / deltax;
  897. fromy = (y - y1) * h / deltay;
  898. tox = (x - x1 + 1) * w / deltax;
  899. toy = (y - y1 + 1) * h / deltay;
  900. /* We want at least one pixel */
  901. if(tox == fromx) tox++;
  902. if(toy == fromy) toy++;
  903. dots = 0;
  904. for(myx = fromx; myx < tox; myx++)
  905. for(myy = fromy; myy < toy; myy++)
  906. {
  907. dots++;
  908. get_rgba_default(d, pixels, myx, myy, rgba);
  909. }
  910. /* Normalize */
  911. rgba[0] /= dots;
  912. rgba[1] /= dots;
  913. rgba[2] /= dots;
  914. rgba[3] /= dots;
  915. }
  916. else
  917. {
  918. fromx = (x - x1) * w / deltax;
  919. fromy = (y - y1) * h / deltay;
  920. tox = (x - x1 + 1) * w / deltax;
  921. toy = (y - y1 + 1) * h / deltay;
  922. /* tox and toy can overflow the canvas, but they cannot overflow
  923. * when averaged with fromx and fromy because these are guaranteed
  924. * to be within the pixel boundaries. */
  925. myx = (fromx + tox) / 2;
  926. myy = (fromy + toy) / 2;
  927. get_rgba_default(d, pixels, myx, myy, rgba);
  928. }
  929. if(d->has_alpha && rgba[3] < 0x800)
  930. {
  931. remain_r = remain_g = remain_b = 0;
  932. fs_r[x] = 0;
  933. fs_g[x] = 0;
  934. fs_b[x] = 0;
  935. continue;
  936. }
  937. /* XXX: OMG HAX */
  938. if(d->init_dither == init_fstein_dither)
  939. {
  940. rgba[0] += remain_r;
  941. rgba[1] += remain_g;
  942. rgba[2] += remain_b;
  943. }
  944. else
  945. {
  946. rgba[0] += (d->get_dither() - 0x80) * 4;
  947. rgba[1] += (d->get_dither() - 0x80) * 4;
  948. rgba[2] += (d->get_dither() - 0x80) * 4;
  949. }
  950. distmin = INT_MAX;
  951. for(i = 0; i < 16; i++)
  952. {
  953. dist = sq(rgba[0] - rgb_palette[i * 3])
  954. + sq(rgba[1] - rgb_palette[i * 3 + 1])
  955. + sq(rgba[2] - rgb_palette[i * 3 + 2]);
  956. dist *= rgb_weight[i];
  957. if(dist < distmin)
  958. {
  959. outbg = i;
  960. distmin = dist;
  961. }
  962. }
  963. bg_r = rgb_palette[outbg * 3];
  964. bg_g = rgb_palette[outbg * 3 + 1];
  965. bg_b = rgb_palette[outbg * 3 + 2];
  966. /* FIXME: we currently only honour "full16" */
  967. if(d->color == COLOR_MODE_FULL16)
  968. {
  969. distmin = INT_MAX;
  970. for(i = 0; i < 16; i++)
  971. {
  972. if(i == outbg)
  973. continue;
  974. dist = sq(rgba[0] - rgb_palette[i * 3])
  975. + sq(rgba[1] - rgb_palette[i * 3 + 1])
  976. + sq(rgba[2] - rgb_palette[i * 3 + 2]);
  977. dist *= rgb_weight[i];
  978. if(dist < distmin)
  979. {
  980. outfg = i;
  981. distmin = dist;
  982. }
  983. }
  984. fg_r = rgb_palette[outfg * 3];
  985. fg_g = rgb_palette[outfg * 3 + 1];
  986. fg_b = rgb_palette[outfg * 3 + 2];
  987. distmin = INT_MAX;
  988. for(i = 0; i < dchmax - 1; i++)
  989. {
  990. int newr = i * fg_r + ((2*dchmax-1) - i) * bg_r;
  991. int newg = i * fg_g + ((2*dchmax-1) - i) * bg_g;
  992. int newb = i * fg_b + ((2*dchmax-1) - i) * bg_b;
  993. dist = abs(rgba[0] * (2*dchmax-1) - newr)
  994. + abs(rgba[1] * (2*dchmax-1) - newg)
  995. + abs(rgba[2] * (2*dchmax-1) - newb);
  996. if(dist < distmin)
  997. {
  998. ch = i;
  999. distmin = dist;
  1000. }
  1001. }
  1002. outch = d->glyphs[ch];
  1003. /* XXX: OMG HAX */
  1004. if(d->init_dither == init_fstein_dither)
  1005. {
  1006. error[0] = rgba[0] - (fg_r * ch + bg_r * ((2*dchmax-1) - ch)) / (2*dchmax-1);
  1007. error[1] = rgba[1] - (fg_g * ch + bg_g * ((2*dchmax-1) - ch)) / (2*dchmax-1);
  1008. error[2] = rgba[2] - (fg_b * ch + bg_b * ((2*dchmax-1) - ch)) / (2*dchmax-1);
  1009. }
  1010. }
  1011. else
  1012. {
  1013. unsigned int lum = rgba[0];
  1014. if(rgba[1] > lum) lum = rgba[1];
  1015. if(rgba[2] > lum) lum = rgba[2];
  1016. outfg = outbg;
  1017. outbg = CUCUL_BLACK;
  1018. ch = lum * dchmax / 0x1000;
  1019. if(ch < 0)
  1020. ch = 0;
  1021. else if(ch > (int)(dchmax - 1))
  1022. ch = dchmax - 1;
  1023. outch = d->glyphs[ch];
  1024. /* XXX: OMG HAX */
  1025. if(d->init_dither == init_fstein_dither)
  1026. {
  1027. error[0] = rgba[0] - bg_r * ch / (dchmax-1);
  1028. error[1] = rgba[1] - bg_g * ch / (dchmax-1);
  1029. error[2] = rgba[2] - bg_b * ch / (dchmax-1);
  1030. }
  1031. }
  1032. /* XXX: OMG HAX */
  1033. if(d->init_dither == init_fstein_dither)
  1034. {
  1035. remain_r = fs_r[x+1] + 7 * error[0] / 16;
  1036. remain_g = fs_g[x+1] + 7 * error[1] / 16;
  1037. remain_b = fs_b[x+1] + 7 * error[2] / 16;
  1038. fs_r[x-1] += 3 * error[0] / 16;
  1039. fs_g[x-1] += 3 * error[1] / 16;
  1040. fs_b[x-1] += 3 * error[2] / 16;
  1041. fs_r[x] = 5 * error[0] / 16;
  1042. fs_g[x] = 5 * error[1] / 16;
  1043. fs_b[x] = 5 * error[2] / 16;
  1044. fs_r[x+1] = 1 * error[0] / 16;
  1045. fs_g[x+1] = 1 * error[1] / 16;
  1046. fs_b[x+1] = 1 * error[2] / 16;
  1047. }
  1048. if(d->invert)
  1049. {
  1050. outfg = 15 - outfg;
  1051. outbg = 15 - outbg;
  1052. }
  1053. /* Now output the character */
  1054. cucul_set_color_ansi(cv, outfg, outbg);
  1055. cucul_put_char(cv, x, y, outch);
  1056. d->increment_dither();
  1057. }
  1058. /* end loop */
  1059. }
  1060. free(floyd_steinberg);
  1061. cucul_set_attr(cv, savedattr);
  1062. return 0;
  1063. }
  1064. /** \brief Free the memory associated with a dither.
  1065. *
  1066. * Free the memory allocated by cucul_create_dither().
  1067. *
  1068. * This function never fails.
  1069. *
  1070. * \param d Dither object.
  1071. * \return This function always returns 0.
  1072. */
  1073. int cucul_free_dither(cucul_dither_t *d)
  1074. {
  1075. if(!d)
  1076. return 0;
  1077. free(d);
  1078. return 0;
  1079. }
  1080. /*
  1081. * XXX: The following functions are local.
  1082. */
  1083. /* Convert a mask, eg. 0x0000ff00, to shift values, eg. 8 and -4. */
  1084. static void mask2shift(uint32_t mask, int *right, int *left)
  1085. {
  1086. int rshift = 0, lshift = 0;
  1087. if(!mask)
  1088. {
  1089. *right = *left = 0;
  1090. return;
  1091. }
  1092. while(!(mask & 1))
  1093. {
  1094. mask >>= 1;
  1095. rshift++;
  1096. }
  1097. *right = rshift;
  1098. while(mask & 1)
  1099. {
  1100. mask >>= 1;
  1101. lshift++;
  1102. }
  1103. *left = 12 - lshift;
  1104. }
  1105. /* Compute x^y without relying on the math library */
  1106. static float gammapow(float x, float y)
  1107. {
  1108. #ifdef HAVE_FLDLN2
  1109. register double logx;
  1110. register long double v, e;
  1111. #else
  1112. register float tmp, t, t2, r;
  1113. int i;
  1114. #endif
  1115. if(x == 0.0)
  1116. return y == 0.0 ? 1.0 : 0.0;
  1117. #ifdef HAVE_FLDLN2
  1118. /* FIXME: this can be optimised by directly calling fyl2x for x and y */
  1119. asm volatile("fldln2; fxch; fyl2x"
  1120. : "=t" (logx) : "0" (x) : "st(1)");
  1121. asm volatile("fldl2e\n\t"
  1122. "fmul %%st(1)\n\t"
  1123. "fst %%st(1)\n\t"
  1124. "frndint\n\t"
  1125. "fxch\n\t"
  1126. "fsub %%st(1)\n\t"
  1127. "f2xm1\n\t"
  1128. : "=t" (v), "=u" (e) : "0" (y * logx));
  1129. v += 1.0;
  1130. asm volatile("fscale"
  1131. : "=t" (v) : "0" (v), "u" (e));
  1132. return v;
  1133. #else
  1134. /* Compute ln(x) for x ∈ ]0,1]
  1135. * ln(x) = 2 * (t + t^3/3 + t^5/5 + ...) with t = (x-1)/(x+1)
  1136. * The convergence is a bit slow, especially when x is near 0. */
  1137. t = (x - 1.0) / (x + 1.0);
  1138. t2 = t * t;
  1139. tmp = r = t;
  1140. for(i = 3; i < 20; i += 2)
  1141. {
  1142. r *= t2;
  1143. tmp += r / i;
  1144. }
  1145. /* Compute -y*ln(x) */
  1146. tmp = - y * 2.0 * tmp;
  1147. /* Compute x^-y as e^t where t = -y*ln(x):
  1148. * e^t = 1 + t/1! + t^2/2! + t^3/3! + t^4/4! + t^5/5! ...
  1149. * The convergence is quite faster here, thanks to the factorial. */
  1150. r = t = tmp;
  1151. tmp = 1.0 + t;
  1152. for(i = 2; i < 16; i++)
  1153. {
  1154. r = r * t / i;
  1155. tmp += r;
  1156. }
  1157. /* Return x^y as 1/(x^-y) */
  1158. return 1.0 / tmp;
  1159. #endif
  1160. }
  1161. static void get_rgba_default(cucul_dither_t const *d, uint8_t *pixels,
  1162. int x, int y, unsigned int *rgba)
  1163. {
  1164. uint32_t bits;
  1165. pixels += (d->bpp / 8) * x + d->pitch * y;
  1166. switch(d->bpp / 8)
  1167. {
  1168. case 4:
  1169. bits = *(uint32_t *)pixels;
  1170. break;
  1171. case 3:
  1172. {
  1173. #if defined(HAVE_ENDIAN_H)
  1174. if(__BYTE_ORDER == __BIG_ENDIAN)
  1175. #else
  1176. /* This is compile-time optimised with at least -O1 or -Os */
  1177. uint32_t const tmp = 0x12345678;
  1178. if(*(uint8_t const *)&tmp == 0x12)
  1179. #endif
  1180. bits = ((uint32_t)pixels[0] << 16) |
  1181. ((uint32_t)pixels[1] << 8) |
  1182. ((uint32_t)pixels[2]);
  1183. else
  1184. bits = ((uint32_t)pixels[2] << 16) |
  1185. ((uint32_t)pixels[1] << 8) |
  1186. ((uint32_t)pixels[0]);
  1187. break;
  1188. }
  1189. case 2:
  1190. bits = *(uint16_t *)pixels;
  1191. break;
  1192. case 1:
  1193. default:
  1194. bits = pixels[0];
  1195. break;
  1196. }
  1197. if(d->has_palette)
  1198. {
  1199. rgba[0] += d->gammatab[d->red[bits]];
  1200. rgba[1] += d->gammatab[d->green[bits]];
  1201. rgba[2] += d->gammatab[d->blue[bits]];
  1202. rgba[3] += d->alpha[bits];
  1203. }
  1204. else
  1205. {
  1206. rgba[0] += d->gammatab[((bits & d->rmask) >> d->rright) << d->rleft];
  1207. rgba[1] += d->gammatab[((bits & d->gmask) >> d->gright) << d->gleft];
  1208. rgba[2] += d->gammatab[((bits & d->bmask) >> d->bright) << d->bleft];
  1209. rgba[3] += ((bits & d->amask) >> d->aright) << d->aleft;
  1210. }
  1211. }
  1212. /*
  1213. * No dithering
  1214. */
  1215. static void init_no_dither(int line)
  1216. {
  1217. ;
  1218. }
  1219. static unsigned int get_no_dither(void)
  1220. {
  1221. return 0x80;
  1222. }
  1223. static void increment_no_dither(void)
  1224. {
  1225. return;
  1226. }
  1227. /*
  1228. * Floyd-Steinberg dithering
  1229. */
  1230. static void init_fstein_dither(int line)
  1231. {
  1232. ;
  1233. }
  1234. static unsigned int get_fstein_dither(void)
  1235. {
  1236. return 0x80;
  1237. }
  1238. static void increment_fstein_dither(void)
  1239. {
  1240. return;
  1241. }
  1242. /*
  1243. * Ordered 2 dithering
  1244. */
  1245. static unsigned int const *ordered2_table;
  1246. static unsigned int ordered2_index;
  1247. static void init_ordered2_dither(int line)
  1248. {
  1249. static unsigned int const dither2x2[] =
  1250. {
  1251. 0x00, 0x80,
  1252. 0xc0, 0x40,
  1253. };
  1254. ordered2_table = dither2x2 + (line % 2) * 2;
  1255. ordered2_index = 0;
  1256. }
  1257. static unsigned int get_ordered2_dither(void)
  1258. {
  1259. return ordered2_table[ordered2_index];
  1260. }
  1261. static void increment_ordered2_dither(void)
  1262. {
  1263. ordered2_index = (ordered2_index + 1) % 2;
  1264. }
  1265. /*
  1266. * Ordered 4 dithering
  1267. */
  1268. /*static int dither4x4[] = { 5, 0, 1, 6,
  1269. -1, -6, -5, 2,
  1270. -2, -7, -8, 3,
  1271. 4, -3, -4, -7};*/
  1272. static unsigned int const *ordered4_table;
  1273. static unsigned int ordered4_index;
  1274. static void init_ordered4_dither(int line)
  1275. {
  1276. static unsigned int const dither4x4[] =
  1277. {
  1278. 0x00, 0x80, 0x20, 0xa0,
  1279. 0xc0, 0x40, 0xe0, 0x60,
  1280. 0x30, 0xb0, 0x10, 0x90,
  1281. 0xf0, 0x70, 0xd0, 0x50
  1282. };
  1283. ordered4_table = dither4x4 + (line % 4) * 4;
  1284. ordered4_index = 0;
  1285. }
  1286. static unsigned int get_ordered4_dither(void)
  1287. {
  1288. return ordered4_table[ordered4_index];
  1289. }
  1290. static void increment_ordered4_dither(void)
  1291. {
  1292. ordered4_index = (ordered4_index + 1) % 4;
  1293. }
  1294. /*
  1295. * Ordered 8 dithering
  1296. */
  1297. static unsigned int const *ordered8_table;
  1298. static unsigned int ordered8_index;
  1299. static void init_ordered8_dither(int line)
  1300. {
  1301. static unsigned int const dither8x8[] =
  1302. {
  1303. 0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
  1304. 0xc0, 0x40, 0xe0, 0x60, 0xc8, 0x48, 0xe8, 0x68,
  1305. 0x30, 0xb0, 0x10, 0x90, 0x38, 0xb8, 0x18, 0x98,
  1306. 0xf0, 0x70, 0xd0, 0x50, 0xf8, 0x78, 0xd8, 0x58,
  1307. 0x0c, 0x8c, 0x2c, 0xac, 0x04, 0x84, 0x24, 0xa4,
  1308. 0xcc, 0x4c, 0xec, 0x6c, 0xc4, 0x44, 0xe4, 0x64,
  1309. 0x3c, 0xbc, 0x1c, 0x9c, 0x34, 0xb4, 0x14, 0x94,
  1310. 0xfc, 0x7c, 0xdc, 0x5c, 0xf4, 0x74, 0xd4, 0x54,
  1311. };
  1312. ordered8_table = dither8x8 + (line % 8) * 8;
  1313. ordered8_index = 0;
  1314. }
  1315. static unsigned int get_ordered8_dither(void)
  1316. {
  1317. return ordered8_table[ordered8_index];
  1318. }
  1319. static void increment_ordered8_dither(void)
  1320. {
  1321. ordered8_index = (ordered8_index + 1) % 8;
  1322. }
  1323. /*
  1324. * Random dithering
  1325. */
  1326. static void init_random_dither(int line)
  1327. {
  1328. ;
  1329. }
  1330. static unsigned int get_random_dither(void)
  1331. {
  1332. return cucul_rand(0x00, 0x100);
  1333. }
  1334. static void increment_random_dither(void)
  1335. {
  1336. return;
  1337. }
  1338. /*
  1339. * Lookup tables
  1340. */
  1341. static int init_lookup(void)
  1342. {
  1343. unsigned int v, s, h;
  1344. /* These ones are constant */
  1345. lookup_colors[0] = CUCUL_BLACK;
  1346. lookup_colors[1] = CUCUL_DARKGRAY;
  1347. lookup_colors[2] = CUCUL_LIGHTGRAY;
  1348. lookup_colors[3] = CUCUL_WHITE;
  1349. /* These ones will be overwritten */
  1350. lookup_colors[4] = CUCUL_MAGENTA;
  1351. lookup_colors[5] = CUCUL_LIGHTMAGENTA;
  1352. lookup_colors[6] = CUCUL_RED;
  1353. lookup_colors[7] = CUCUL_LIGHTRED;
  1354. for(v = 0; v < LOOKUP_VAL; v++)
  1355. for(s = 0; s < LOOKUP_SAT; s++)
  1356. for(h = 0; h < LOOKUP_HUE; h++)
  1357. {
  1358. int i, distbg, distfg, dist;
  1359. int val, sat, hue;
  1360. uint8_t outbg, outfg;
  1361. val = 0xfff * v / (LOOKUP_VAL - 1);
  1362. sat = 0xfff * s / (LOOKUP_SAT - 1);
  1363. hue = 0xfff * h / (LOOKUP_HUE - 1);
  1364. /* Initialise distances to the distance between pure black HSV
  1365. * coordinates and our white colour (3) */
  1366. outbg = outfg = 3;
  1367. distbg = distfg = HSV_DISTANCE(0, 0, 0, 3);
  1368. /* Calculate distances to eight major colour values and store the
  1369. * two nearest points in our lookup table. */
  1370. for(i = 0; i < 8; i++)
  1371. {
  1372. dist = HSV_DISTANCE(hue, sat, val, i);
  1373. if(dist <= distbg)
  1374. {
  1375. outfg = outbg;
  1376. distfg = distbg;
  1377. outbg = i;
  1378. distbg = dist;
  1379. }
  1380. else if(dist <= distfg)
  1381. {
  1382. outfg = i;
  1383. distfg = dist;
  1384. }
  1385. }
  1386. hsv_distances[v][s][h] = (outfg << 4) | outbg;
  1387. }
  1388. return 0;
  1389. }