Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

317 rader
9.2 KiB

  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. struct line
  29. {
  30. int x1, y1;
  31. int x2, y2;
  32. void (*draw) (pipi_image_t*, struct line*);
  33. union {
  34. uint32_t color32;
  35. float colorf[3];
  36. };
  37. union {
  38. uint32_t *buf_u32;
  39. float *buf_f;
  40. };
  41. };
  42. static void clip_line(pipi_image_t*, struct line*);
  43. static uint8_t clip_bits(pipi_image_t*, int, int);
  44. static void draw_aliased_line_u32(pipi_image_t*, struct line*);
  45. static void draw_aliased_line_gray(pipi_image_t *img, struct line* s);
  46. static void draw_aliased_line_float(pipi_image_t *img, struct line* s);
  47. static void draw_antialiased_line_float(pipi_image_t *img, struct line* s);
  48. static void draw_antialiased_line_gray(pipi_image_t *img, struct line* s);
  49. int pipi_draw_line(pipi_image_t *img , int x1, int y1, int x2, int y2, uint32_t c, int aa)
  50. {
  51. struct line s;
  52. s.x1 = x1;
  53. s.y1 = y1;
  54. s.x2 = x2;
  55. s.y2 = y2;
  56. /* No Transparency routine for u32 yet, fallback to float version */
  57. if(img->last_modified == PIPI_PIXELS_RGBA_C)
  58. {
  59. if(!aa)
  60. {
  61. uint32_t *dstdata;
  62. dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
  63. s.color32 = c;
  64. s.buf_u32 = dstdata;
  65. s.draw = draw_aliased_line_u32;
  66. }
  67. else
  68. {
  69. float *dstdata;
  70. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  71. s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
  72. s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */
  73. s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  74. s.buf_f = dstdata;
  75. s.draw = draw_antialiased_line_float;
  76. }
  77. }
  78. else if(img->last_modified == PIPI_PIXELS_Y_F)
  79. {
  80. float *dstdata;
  81. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
  82. s.colorf[0] = c/255.0f; /* XXX FIXME */
  83. s.buf_f = dstdata;
  84. s.draw = aa==0?draw_aliased_line_gray:draw_antialiased_line_gray;
  85. }
  86. else
  87. {
  88. float *dstdata;
  89. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  90. s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
  91. s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */
  92. s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  93. s.buf_f = dstdata;
  94. s.draw = aa==0?draw_aliased_line_float:draw_antialiased_line_float;
  95. }
  96. clip_line(img, &s);
  97. return 0;
  98. }
  99. int pipi_draw_polyline(pipi_image_t *img, int const x[], int const y[],
  100. int n, uint32_t c, int aa)
  101. {
  102. int i;
  103. struct line s;
  104. if(img->last_modified == PIPI_PIXELS_RGBA_C)
  105. {
  106. if(!aa)
  107. {
  108. uint32_t *dstdata;
  109. dstdata = (uint32_t *)pipi_getpixels(img, PIPI_PIXELS_RGBA_C)->pixels;
  110. s.color32 = c;
  111. s.buf_u32 = dstdata;
  112. s.draw = draw_aliased_line_u32;
  113. }
  114. else
  115. {
  116. float *dstdata;
  117. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  118. s.colorf[2] = ((c&0x00FF0000)>>16)/255.0f; /* XXX FIXME */
  119. s.colorf[1] = ((c&0x0000FF00)>>8)/255.0f; /* XXX FIXME */
  120. s.colorf[0] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  121. s.buf_f = dstdata;
  122. s.draw = draw_antialiased_line_float;
  123. }
  124. }
  125. else if(img->last_modified == PIPI_PIXELS_Y_F)
  126. {
  127. float *dstdata;
  128. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_Y_F)->pixels;
  129. s.colorf[0] = c/255.0f; /* XXX FIXME */
  130. s.buf_f = dstdata;
  131. s.draw = aa==0?draw_aliased_line_gray:draw_antialiased_line_gray;
  132. }
  133. else
  134. {
  135. float *dstdata;
  136. dstdata = (float *)pipi_getpixels(img, PIPI_PIXELS_RGBA_F)->pixels;
  137. s.colorf[0] = (c&0x00FF0000)/255.0f; /* XXX FIXME */
  138. s.colorf[1] = (c&0x0000FF00)/255.0f; /* XXX FIXME */
  139. s.colorf[2] = (c&0x000000FF)/255.0f; /* XXX FIXME */
  140. s.buf_f = dstdata;
  141. s.draw = aa==0?draw_aliased_line_float:draw_antialiased_line_float;
  142. img->last_modified = PIPI_PIXELS_RGBA_F;
  143. }
  144. for(i = 0; i < n; i++)
  145. {
  146. s.x1 = x[i];
  147. s.y1 = y[i];
  148. s.x2 = x[i+1];
  149. s.y2 = y[i+1];
  150. clip_line(img, &s);
  151. }
  152. return 0;
  153. }
  154. /*
  155. * XXX: The following functions are local.
  156. */
  157. /* Generic Cohen-Sutherland line clipping function. */
  158. static void clip_line(pipi_image_t *img, struct line* s)
  159. {
  160. uint8_t bits1, bits2;
  161. bits1 = clip_bits(img, s->x1, s->y1);
  162. bits2 = clip_bits(img, s->x2, s->y2);
  163. if(bits1 & bits2)
  164. return;
  165. if(bits1 == 0)
  166. {
  167. if(bits2 == 0)
  168. s->draw(img, s);
  169. else
  170. {
  171. int tmp;
  172. tmp = s->x1; s->x1 = s->x2; s->x2 = tmp;
  173. tmp = s->y1; s->y1 = s->y2; s->y2 = tmp;
  174. clip_line(img, s);
  175. }
  176. return;
  177. }
  178. if(bits1 & (1<<0))
  179. {
  180. s->y1 = s->y2 - (s->x2 - 0) * (s->y2 - s->y1) / (s->x2 - s->x1);
  181. s->x1 = 0;
  182. }
  183. else if(bits1 & (1<<1))
  184. {
  185. int xmax = img->w - 1;
  186. s->y1 = s->y2 - (s->x2 - xmax) * (s->y2 - s->y1) / (s->x2 - s->x1);
  187. s->x1 = xmax;
  188. }
  189. else if(bits1 & (1<<2))
  190. {
  191. s->x1 = s->x2 - (s->y2 - 0) * (s->x2 - s->x1) / (s->y2 - s->y1);
  192. s->y1 = 0;
  193. }
  194. else if(bits1 & (1<<3))
  195. {
  196. int ymax = img->h - 1;
  197. s->x1 = s->x2 - (s->y2 - ymax) * (s->x2 - s->x1) / (s->y2 - s->y1);
  198. s->y1 = ymax;
  199. }
  200. clip_line(img, s);
  201. }
  202. /* Helper function for clip_line(). */
  203. static uint8_t clip_bits(pipi_image_t *img, int x, int y)
  204. {
  205. uint8_t b = 0;
  206. if(x < 0)
  207. b |= (1<<0);
  208. else if(x >= (int)img->w)
  209. b |= (1<<1);
  210. if(y < 0)
  211. b |= (1<<2);
  212. else if(y >= (int)img->h)
  213. b |= (1<<3);
  214. return b;
  215. }
  216. /* Solid line drawing function, using Bresenham's mid-point line
  217. * scan-conversion algorithm. */
  218. static void draw_aliased_line_u32(pipi_image_t *img, struct line* s)
  219. {
  220. #undef ASSIGN
  221. #define ASSIGN(x, y, w) s->buf_u32[x+y*w] = s->color32;
  222. #include "line_template.h"
  223. }
  224. static void draw_aliased_line_float(pipi_image_t *img, struct line* s)
  225. {
  226. #undef ASSIGN
  227. #define ASSIGN(x, y, w) s->buf_f[(x*4)+y*(w*4)] = s->colorf[0]; \
  228. s->buf_f[1 + (x*4)+y*(w*4)] = s->colorf[1]; \
  229. s->buf_f[2 + (x*4)+y*(w*4)] = s->colorf[2];
  230. #include "line_template.h"
  231. }
  232. static void draw_aliased_line_gray(pipi_image_t *img, struct line* s)
  233. {
  234. #undef ASSIGN
  235. #define ASSIGN(x, y, w) s->buf_f[x+y*w] = s->colorf[0];
  236. #include "line_template.h"
  237. }
  238. /* Xiaolin Wu's line algorithm, as seen at http://portal.acm.org/citation.cfm?id=122734 */
  239. /* math.h doesn't like y1 (sucker) */
  240. float floorf(float x);
  241. float truncf(float x);
  242. float fabsf(float x);
  243. static float fractf(float d) { return (d - floorf(d)); }
  244. static float fractinvf(float d) { return (1 - (d - floorf(d))); }
  245. static void draw_antialiased_line_float(pipi_image_t *img, struct line* s)
  246. {
  247. /* Is that an horrible mess ? Yes, it is. */
  248. #undef PLOT
  249. #define PLOT(x, y, c) \
  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) s->buf_f[qwer] = 1.0f; \
  257. if(s->buf_f[qwer] < 0.0f || isnan(s->buf_f[qwer])) s->buf_f[qwer] = 0.0f; \
  258. if(s->buf_f[qweg] > 1.0f) s->buf_f[qweg] = 1.0f; \
  259. if(s->buf_f[qweg] < 0.0f || isnan(s->buf_f[qweg])) s->buf_f[qweg] = 0.0f; \
  260. if(s->buf_f[qweb] > 1.0f) s->buf_f[qweb] = 1.0f; \
  261. if(s->buf_f[qweb] < 0.0f || isnan(s->buf_f[qweb])) s->buf_f[qweb] = 0.0f; }
  262. #include "aline_template.h"
  263. }
  264. static void draw_antialiased_line_gray(pipi_image_t *img, struct line* s)
  265. {
  266. #undef PLOT
  267. #define PLOT(x, y, c) s->buf_f[((int)(x))+((int)(y))*img->w] = \
  268. (c*s->colorf[0]) + (1-c) * s->buf_f[((int)(x))+((int)(y))*img->w]; \
  269. if(s->buf_f[((int)(x))+((int)(y))*img->w] > 1.0f) s->buf_f[((int)(x))+((int)(y))*img->w] = 1.0f; \
  270. if(s->buf_f[((int)(x))+((int)(y))*img->w] < 0.0f) s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f; \
  271. if(isnan(s->buf_f[((int)(x))+((int)(y))*img->w])) s->buf_f[((int)(x))+((int)(y))*img->w] = 0.0f;
  272. #include "aline_template.h"
  273. }