You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

line.c 14 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * libpipi Proper image processing implementation library
  3. * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
  4. * 2008 Jean-Yves Lamoureux <jylam@lnxscene.org
  5. * All Rights Reserved
  6. *
  7. * $Id$
  8. *
  9. * This library is free software. It comes without any warranty, to
  10. * the extent permitted by applicable law. You can redistribute it
  11. * and/or modify it under the terms of the Do What The Fuck You Want
  12. * To Public License, Version 2, as published by Sam Hocevar. See
  13. * http://sam.zoy.org/wtfpl/COPYING for more details.
  14. */
  15. /*
  16. * line.c: line rendering functions
  17. */
  18. #include "config.h"
  19. #include "common.h"
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #undef __USE_MISC /* THAT sucks */
  24. #undef __USE_XOPEN /* THAT sucks, too (avoid declaring y1 in math.h) */
  25. #include <math.h>
  26. #include "pipi.h"
  27. #include "pipi_internals.h"
  28. /* math.h doesn't like y1 (sucker) */
  29. float floorf(float x);
  30. float truncf(float x);
  31. float fabsf(float x);
  32. #if !defined TEMPLATE_FILE /* This file uses the template system */
  33. static float fractf(float d) { return (d - floorf(d)); }
  34. static float fractinvf(float d) { return (1 - (d - floorf(d))); }
  35. struct line
  36. {
  37. int x1, y1;
  38. int x2, y2;
  39. void (*draw) (pipi_image_t*, struct line*);
  40. union {
  41. uint32_t color32;
  42. float colorf[3];
  43. };
  44. union {
  45. uint32_t *buf_u32;
  46. float *buf_f;
  47. };
  48. };
  49. #define TEMPLATE_FLAGS SET_FLAG_GRAY | SET_FLAG_8BIT
  50. #define TEMPLATE_FILE "paint/line.c"
  51. #include "pipi_template.h"
  52. static void clip_line(pipi_image_t*, struct line*);
  53. static uint8_t clip_bits(pipi_image_t*, int, int);
  54. int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c, int aa)
  55. {
  56. struct line s;
  57. s.x1 = x1;
  58. s.y1 = y1;
  59. s.x2 = x2;
  60. s.y2 = y2;
  61. /* No Transparency routine for u32 yet, fallback to float version */
  62. if(img->last_modified == PIPI_PIXELS_RGBA_C)
  63. {
  64. if(!aa)
  65. {
  66. uint32_t *dstdata;
  67. dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
  68. s.color32 = c;
  69. s.buf_u32 = dstdata;
  70. s.draw = aliased_line_8bit;
  71. }
  72. else
  73. {
  74. float *dstdata;
  75. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  76. s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
  77. s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */
  78. s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  79. s.buf_f = dstdata;
  80. s.draw = antialiased_line;
  81. }
  82. }
  83. else if(img->last_modified == PIPI_PIXELS_Y_F)
  84. {
  85. float *dstdata;
  86. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
  87. s.colorf[0] = (c & 0xff) / 255.0f; /* XXX FIXME */
  88. s.buf_f = dstdata;
  89. s.draw = aa == 0 ? aliased_line_gray : antialiased_line_gray;
  90. }
  91. else
  92. {
  93. float *dstdata;
  94. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  95. s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
  96. s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */
  97. s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  98. s.buf_f = dstdata;
  99. s.draw = aa == 0 ? aliased_line : antialiased_line;
  100. }
  101. clip_line(img, &s);
  102. return 0;
  103. }
  104. int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[],
  105. int n, uint32_t c, int aa)
  106. {
  107. int i;
  108. struct line s;
  109. if(img->last_modified == PIPI_PIXELS_RGBA_C)
  110. {
  111. if(!aa)
  112. {
  113. uint32_t *dstdata;
  114. dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
  115. s.color32 = c;
  116. s.buf_u32 = dstdata;
  117. s.draw = aliased_line_8bit;
  118. }
  119. else
  120. {
  121. float *dstdata;
  122. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  123. s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
  124. s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */
  125. s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  126. s.buf_f = dstdata;
  127. s.draw = antialiased_line;
  128. }
  129. }
  130. else if(img->last_modified == PIPI_PIXELS_Y_F)
  131. {
  132. float *dstdata;
  133. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
  134. s.colorf[0] = (c & 0xff) / 255.0f; /* XXX FIXME */
  135. s.buf_f = dstdata;
  136. s.draw = aa == 0 ? aliased_line_gray : antialiased_line_gray;
  137. }
  138. else
  139. {
  140. float *dstdata;
  141. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  142. s.colorf[0] = (c&0x00FF0000)/255.0f; /* XXX FIXME */
  143. s.colorf[1] = (c&0x0000FF00)/255.0f; /* XXX FIXME */
  144. s.colorf[2] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  145. s.buf_f = dstdata;
  146. s.draw = aa == 0 ? aliased_line : antialiased_line;
  147. img->last_modified = PIPI_PIXELS_RGBA_F;
  148. }
  149. for(i = 0; i < n; i++)
  150. {
  151. s.x1 = x[i];
  152. s.y1 = y[i];
  153. s.x2 = x[i+1];
  154. s.y2 = y[i+1];
  155. clip_line(img, &s);
  156. }
  157. return 0;
  158. }
  159. /*
  160. * XXX: The following functions are local.
  161. */
  162. /* Generic Cohen-Sutherland line clipping function. */
  163. static void clip_line(pipi_image_t *img, struct line* s)
  164. {
  165. uint8_t bits1, bits2;
  166. bits1 = clip_bits(img, s->x1, s->y1);
  167. bits2 = clip_bits(img, s->x2, s->y2);
  168. if(bits1 & bits2)
  169. return;
  170. if(bits1 == 0)
  171. {
  172. if(bits2 == 0)
  173. s->draw(img, s);
  174. else
  175. {
  176. int tmp;
  177. tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
  178. tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
  179. clip_line(img, s);
  180. }
  181. return;
  182. }
  183. if(bits1 & (1<<0))
  184. {
  185. s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
  186. s->x1 = 0;
  187. }
  188. else if(bits1 & (1<<1))
  189. {
  190. int xmax = img->w - 1;
  191. s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
  192. s->x1 = xmax;
  193. }
  194. else if(bits1 & (1<<2))
  195. {
  196. s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
  197. s->y1 = 0;
  198. }
  199. else if(bits1 & (1<<3))
  200. {
  201. int ymax = img->h - 1;
  202. s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
  203. s->y1 = ymax;
  204. }
  205. clip_line(img, s);
  206. }
  207. /* Helper function for clip_line(). */
  208. static uint8_t clip_bits(pipi_image_t *img, int x, int y)
  209. {
  210. uint8_t b = 0;
  211. if(x < 0)
  212. b |= (1<<0);
  213. else if(x >= (int)img->w)
  214. b |= (1<<1);
  215. if(y < 0)
  216. b |= (1<<2);
  217. else if(y >= (int)img->h)
  218. b |= (1<<3);
  219. return b;
  220. }
  221. #else /* XXX: the following functions use the template system */
  222. /* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */
  223. #define PLOT(x, y, c) \
  224. if(FLAG_GRAY) \
  225. { \
  226. if(FLAG_8BIT) \
  227. { \
  228. /* TODO */ \
  229. } \
  230. else \
  231. { \
  232. s->buf_f[((int)(x))+((int)(y))*img->w] = \
  233. (c*s->colorf[0]) + (1-c) * s->buf_f[((int)(x))+((int)(y))*img->w]; \
  234. if(s->buf_f[((int)(x))+((int)(y))*img->w] > 1.0f) \
  235. s->buf_f[((int)(x))+((int)(y))*img->w] = 1.0f; \
  236. if(s->buf_f[((int)(x))+((int)(y))*img->w] < 0.0f) \
  237. s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
  238. if(isnan(s->buf_f[((int)(x))+((int)(y))*img->w])) \
  239. s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
  240. } \
  241. } \
  242. else \
  243. { \
  244. if(FLAG_8BIT) \
  245. { \
  246. /* TODO */ \
  247. } \
  248. else \
  249. { \
  250. int qwer = (((int)(x)*4))+((int)(y))*(img->w*4);\
  251. int qweg = (1+((int)(x)*4))+((int)(y))*(img->w*4); \
  252. int qweb = (2+((int)(x)*4))+((int)(y))*(img->w*4); \
  253. s->buf_f[qwer] = (c*s->colorf[0]) + (1-c) * s->buf_f[qwer]; \
  254. s->buf_f[qweg] = (c*s->colorf[1]) + (1-c) * s->buf_f[qweg]; \
  255. s->buf_f[qweb] = (c*s->colorf[2]) + (1-c) * s->buf_f[qweb]; \
  256. if(s->buf_f[qwer] > 1.0f) \
  257. s->buf_f[qwer] = 1.0f; \
  258. if(s->buf_f[qwer] < 0.0f || isnan(s->buf_f[qwer])) \
  259. s->buf_f[qwer] = 0.0f; \
  260. if(s->buf_f[qweg] > 1.0f) \
  261. s->buf_f[qweg] = 1.0f; \
  262. if(s->buf_f[qweg] < 0.0f || isnan(s->buf_f[qweg])) \
  263. s->buf_f[qweg] = 0.0f; \
  264. if(s->buf_f[qweb] > 1.0f) \
  265. s->buf_f[qweb] = 1.0f; \
  266. if(s->buf_f[qweb] < 0.0f || isnan(s->buf_f[qweb])) \
  267. s->buf_f[qweb] = 0.0f; \
  268. } \
  269. }
  270. static void SUFFIX(antialiased_line)(pipi_image_t *img, struct line* s)
  271. {
  272. float x1 = s->x1, y1 = s->y1, x2 = s->x2, y2 = s->y2;
  273. float g, xd, yd, xgap, xend, yend, xf, yf, val1, val2;
  274. int x, y, ix1, ix2, iy1, iy2;
  275. xd = x2 - x1;
  276. yd = y2 - y1;
  277. /* "Horizontal" line (X greater than Y)*/
  278. if (fabsf(xd) > fabsf(yd))
  279. {
  280. if (x1 > x2)
  281. {
  282. float tmp;
  283. tmp = x1; x1 = x2; x2 = tmp;
  284. tmp = y1; y1 = y2; y2 = tmp;
  285. xd = (x2-x1);
  286. yd = (y2-y1);
  287. }
  288. g = yd/xd;
  289. xend = truncf(x1+0.5);
  290. yend = y1 + g*(xend-x1);
  291. xgap = fractinvf(x1+0.5);
  292. ix1 = (int)xend;
  293. iy1 = (int)yend;
  294. val1 = fractinvf(yend)*xgap;
  295. val2 = fractf(yend)*xgap;
  296. PLOT(ix1, iy1, val1);
  297. PLOT(ix1, (iy1+1)<y1?(iy1+1):iy1, val2);
  298. yf = yend+g;
  299. xend = truncf(x2+0.5);
  300. yend = y2 + g*(xend-x2);
  301. xgap = fractinvf(x2-0.5);
  302. ix2 = (int)xend;
  303. iy2 = (int)yend;
  304. val1 = fractinvf(yend)*xgap;
  305. val2 = fractf(yend)*xgap;
  306. PLOT(ix2, iy2, val1);
  307. PLOT(ix2, iy2+1<y2?iy2+1:iy2, val2);
  308. for (x = (ix1+1); x < ix2; x++)
  309. {
  310. float focus;
  311. val1 = fractinvf(yf);
  312. val2 = fractf(yf);
  313. focus = (1.0 - fabsf(val1-val2));
  314. val1 += 0.3*focus;
  315. val2 += 0.3*focus;
  316. PLOT(x, yf, val1);
  317. PLOT(x, (yf+1)<y1?(yf+1):yf, val2);
  318. yf = yf + g;
  319. }
  320. }
  321. /* "Vertical" line (Y greater than X)*/
  322. else
  323. {
  324. if (x1 > x2)
  325. {
  326. float tmp;
  327. tmp = x1; x1 = x2; x2 = tmp;
  328. tmp = y1; y1 = y2; y2 = tmp;
  329. xd = (x2-x1);
  330. yd = (y2-y1);
  331. }
  332. g = xd/yd;
  333. xend = truncf(x1+0.5);
  334. yend = y1 + g*(xend-x1);
  335. xgap = fractf(x1+0.5);
  336. ix1 = (int)xend;
  337. iy1 = (int)yend;
  338. val1 = fractinvf(yend)*xgap;
  339. val2 = fractf(yend)*xgap;
  340. PLOT(ix1, iy1, val1);
  341. PLOT(ix1, (iy1+1)<y1?(iy1+1):iy1, val2);
  342. xf = xend + g;
  343. xend = truncf(x2+0.5);
  344. yend = y2 + g*(xend-x2);
  345. xgap = fractinvf(x2-0.5);
  346. ix2 = (int)xend;
  347. iy2 = (int)yend;
  348. val1 = fractinvf(yend)*xgap;
  349. val2 = fractf(yend)*xgap;
  350. PLOT(ix2, iy2, val1);
  351. PLOT(ix2, (iy2+1)<y2?(iy2+1):iy2, val2);
  352. for (y = (iy1+1); y < iy2; y++)
  353. {
  354. float focus;
  355. int vx = xf;
  356. val1 = fractinvf(xf);
  357. val2 = fractf(xf);
  358. focus = (1.0 - fabsf(val1-val2));
  359. val1 += 0.3*focus;
  360. val2 += 0.3*focus;
  361. PLOT(vx, y, val1);
  362. vx++;
  363. PLOT(vx, y, val2);
  364. xf = xf + g;
  365. }
  366. }
  367. }
  368. #undef PLOT
  369. /* Solid line drawing function, using Bresenham's mid-point line
  370. * scan-conversion algorithm. */
  371. static void SUFFIX(aliased_line)(pipi_image_t *img, struct line* s)
  372. {
  373. int x1, y1, x2, y2;
  374. int dx, dy;
  375. int xinc, yinc;
  376. x1 = s->x1; y1 = s->y1; x2 = s->x2; y2 = s->y2;
  377. dx = abs(x2 - x1);
  378. dy = abs(y2 - y1);
  379. xinc = (x1 > x2) ? -1 : 1;
  380. yinc = (y1 > y2) ? -1 : 1;
  381. if(dx >= dy)
  382. {
  383. int dpr = dy << 1;
  384. int dpru = dpr - (dx << 1);
  385. int delta = dpr - dx;
  386. for(; dx >= 0; dx--)
  387. {
  388. if(FLAG_GRAY)
  389. {
  390. if(FLAG_8BIT)
  391. /* TODO */;
  392. else
  393. s->buf_f[x1 + y1 * img->w] = s->colorf[0];
  394. }
  395. else
  396. {
  397. if(FLAG_8BIT)
  398. s->buf_u32[x1 + y1 * img->w] = s->color32;
  399. else
  400. {
  401. s->buf_f[4 * (y1 * img->w + x1)] = s->colorf[0];
  402. s->buf_f[4 * (y1 * img->w + x1) + 1] = s->colorf[1];
  403. s->buf_f[4 * (y1 * img->w + x1) + 2] = s->colorf[2];
  404. }
  405. }
  406. if(delta > 0)
  407. {
  408. x1 += xinc;
  409. y1 += yinc;
  410. delta += dpru;
  411. }
  412. else
  413. {
  414. x1 += xinc;
  415. delta += dpr;
  416. }
  417. }
  418. }
  419. else
  420. {
  421. int dpr = dx << 1;
  422. int dpru = dpr - (dy << 1);
  423. int delta = dpr - dy;
  424. for(; dy >= 0; dy--)
  425. {
  426. if(FLAG_GRAY)
  427. {
  428. if(FLAG_8BIT)
  429. /* TODO */;
  430. else
  431. s->buf_f[x1 + y1 * img->w] = s->colorf[0];
  432. }
  433. else
  434. {
  435. if(FLAG_8BIT)
  436. s->buf_u32[x1 + y1 * img->w] = s->color32;
  437. else
  438. {
  439. s->buf_f[4 * (y1 * img->w + x1)] = s->colorf[0];
  440. s->buf_f[4 * (y1 * img->w + x1) + 1] = s->colorf[1];
  441. s->buf_f[4 * (y1 * img->w + x1) + 2] = s->colorf[2];
  442. }
  443. }
  444. if(delta > 0)
  445. {
  446. x1 += xinc;
  447. y1 += yinc;
  448. delta += dpru;
  449. }
  450. else
  451. {
  452. y1 += yinc;
  453. delta += dpr;
  454. }
  455. }
  456. }
  457. }
  458. #endif