/src/gfxlib2/gfx_line.c

https://github.com/freebasic/fbc · C · 240 lines · 187 code · 30 blank · 23 comment · 70 complexity · e43084e2dc3129841f14e6ee057211d0 MD5 · raw file

  1. /* LINE statement */
  2. #include "fb_gfx.h"
  3. static int reverse_mask(int mask)
  4. {
  5. mask = ((mask >> 1) & 0x5555) | ((mask & 0x5555) << 1);
  6. mask = ((mask >> 2) & 0x3333) | ((mask & 0x3333) << 2);
  7. mask = ((mask >> 4) & 0x0F0F) | ((mask & 0x0F0F) << 4);
  8. mask = ((mask >> 8) & 0x00FF) | ((mask & 0x00FF) << 8);
  9. return mask;
  10. }
  11. /* Assumes coordinates to be physical ones.
  12. * Also assumes color is already masked. */
  13. /* Caller is expected to hold FB_GRAPHICS_LOCK() */
  14. void fb_GfxDrawLine(FB_GFXCTX *context, int x1, int y1, int x2, int y2, unsigned int color, unsigned int style)
  15. {
  16. int x, y, d, dx, dy, ax, ay, skip, rot, bit;
  17. int xmin = context->view_x, xmax = context->view_x + context->view_w - 1;
  18. int ymin = context->view_y, ymax = context->view_y + context->view_h - 1;
  19. /* line entirely out of bounds? */
  20. if ((x1 < xmin) && (x2 < xmin))
  21. return;
  22. else if ((x1 > xmax) && (x2 > xmax))
  23. return;
  24. else if ((y1 < ymin) && (y2 < ymin))
  25. return;
  26. else if ((y1 > ymax) && (y2 > ymax))
  27. return;
  28. /* store dy/dx before line is clipped */
  29. dx = x2 - x1;
  30. dy = y2 - y1;
  31. /* clip x2, y2 */
  32. x2 = MID(xmin, x2, xmax);
  33. y2 = MID(ymin, y2, ymax);
  34. rot = 0;
  35. DRIVER_LOCK();
  36. /* vertical line */
  37. if (dx == 0) {
  38. /* clip y1 */
  39. if (y1 < ymin) {
  40. rot += ymin - y1;
  41. y1 = ymin;
  42. } else if (y1 > ymax) {
  43. rot += y1 - ymax;
  44. y1 = ymax;
  45. }
  46. /* go from top down */
  47. if (y1 > y2) {
  48. style = reverse_mask(style);
  49. rot = (~rot) + y2 - y1;
  50. SWAP(y1, y2);
  51. }
  52. bit = 0x8000 >> (rot & 0xF);
  53. for (y = y1; y <= y2; y++) {
  54. if (style & bit)
  55. context->put_pixel(context, x1, y, color);
  56. RORW1(bit);
  57. }
  58. }
  59. /* horizontal line */
  60. else if (dy == 0) {
  61. /* clip x1 */
  62. if (x1 < xmin) {
  63. rot += (xmin - x1);
  64. x1 = xmin;
  65. } else if (x1 > xmax) {
  66. rot += (x1 - xmax);
  67. x1 = xmax;
  68. }
  69. /* go from left to right */
  70. if (x1 > x2) {
  71. style = reverse_mask(style);
  72. rot = (~rot) + x2 - x1;
  73. SWAP(x1, x2);
  74. }
  75. bit = 0x8000 >> (rot & 0xF );
  76. if (style == 0xFFFF)
  77. context->pixel_set(context->line[y1] + (x1 * context->target_bpp), color, x2 - x1 + 1);
  78. else {
  79. for (x = x1; x <= x2; x++) {
  80. if (style & bit)
  81. context->put_pixel(context, x, y1, color);
  82. RORW1(bit);
  83. }
  84. }
  85. /* diagonal line */
  86. } else {
  87. ax = ay = 1;
  88. if (dx < 0) {
  89. dx = -dx;
  90. ax = -1;
  91. }
  92. if (dy < 0) {
  93. dy = -dy;
  94. ay = -1;
  95. }
  96. d = (dx >= dy)? dy * 2 - dx : dy - dx * 2;
  97. dx *= 2;
  98. dy *= 2;
  99. /* clip x, y start values */
  100. x = MID(xmin, x1, xmax);
  101. d += ax * (x - x1) * dy;
  102. y = MID(ymin, y1, ymax);
  103. d -= ay * (y - y1) * dx;
  104. /* shift style if necessary */
  105. if (dx >= dy)
  106. rot += ax * (x - x1);
  107. else
  108. rot += ay * (y - y1);
  109. /* line terminates when x2 or y2 reached */
  110. x2 = x2 + ax;
  111. y2 = y2 + ay;
  112. /* shallow gradient */
  113. if (dx >= dy) {
  114. /* put y, x back on the line if clipped*/
  115. if (d >= dy) {
  116. skip = (d - dy) / dx + 1;
  117. y += ay * skip;
  118. d -= skip * dx;
  119. if ((y < ymin) || (y > ymax))
  120. goto done;
  121. } else if (d < (dy - dx)) {
  122. skip = ((dy - dx) - d) / dy + 1;
  123. x += ax * skip;
  124. d += skip * dy;
  125. rot += skip;
  126. if ((x < xmin) || (x > xmax))
  127. goto done;
  128. }
  129. bit = 0x8000 >> (rot & 0xF);
  130. y1 = y; /* first dirty row */
  131. while ((x != x2) && (y != y2)) {
  132. if (style & bit)
  133. context->put_pixel(context, x, y, color);
  134. RORW1(bit);
  135. if (d >= 0) {
  136. y += ay;
  137. d -= dx;
  138. }
  139. d += dy;
  140. x += ax;
  141. /* invariant: (-dx + dy) <= d < dy */
  142. }
  143. /* steep gradient */
  144. } else {
  145. /* put x, y back on the line if clipped */
  146. if (d < -dx) {
  147. skip = (-dx - d) / dy + 1;
  148. x += ax * skip;
  149. d += skip * dy;
  150. if ((x < xmin) || (x > xmax))
  151. goto done;
  152. } else if (d > dy - dx) {
  153. skip = (d - (dy - dx)) / dx + 1;
  154. y += ay * skip;
  155. d -= skip * dx;
  156. rot += skip;
  157. if ((y < ymin) || (y > ymax))
  158. goto done;
  159. }
  160. bit = 0x8000 >> (rot & 0xF);
  161. y1 = y; /* first dirty row */
  162. while ((y != y2) && (x != x2)) {
  163. if (style & bit)
  164. context->put_pixel(context, x, y, color);
  165. RORW1(bit);
  166. if (d <= 0) {
  167. x += ax;
  168. d += dy;
  169. }
  170. d -= dx;
  171. y += ay;
  172. /* invariant: (-dx) <= d < (-dx + dy) */
  173. }
  174. }
  175. y2 -= ay; /* last dirty row */
  176. }
  177. if (y1 > y2)
  178. SWAP(y1, y2);
  179. SET_DIRTY(context, y1, y2 - y1 + 1);
  180. done:
  181. DRIVER_UNLOCK();
  182. }
  183. FBCALL void fb_GfxLine(void *target, float fx1, float fy1, float fx2, float fy2, unsigned int color, int type, unsigned int style, int flags)
  184. {
  185. FB_GFXCTX *context;
  186. int x1, y1, x2, y2;
  187. FB_GRAPHICS_LOCK( );
  188. if (!__fb_gfx) {
  189. FB_GRAPHICS_UNLOCK( );
  190. return;
  191. }
  192. context = fb_hGetContext( );
  193. fb_hPrepareTarget(context, target);
  194. if (flags & DEFAULT_COLOR_1)
  195. color = context->fg_color;
  196. else
  197. color = fb_hFixColor(context->target_bpp, color);
  198. fb_hSetPixelTransfer(context,color);
  199. style &= 0xFFFF;
  200. fb_hFixRelative(context, flags, &fx1, &fy1, &fx2, &fy2);
  201. fb_hTranslateCoord(context, fx1, fy1, &x1, &y1);
  202. fb_hTranslateCoord(context, fx2, fy2, &x2, &y2);
  203. if (type == LINE_TYPE_LINE) {
  204. fb_GfxDrawLine( context, x1, y1, x2, y2, color, style );
  205. } else {
  206. fb_hFixCoordsOrder(&x1, &y1, &x2, &y2);
  207. fb_hGfxBox(x1, y1, x2, y2, color, (type == LINE_TYPE_BF), style);
  208. }
  209. FB_GRAPHICS_UNLOCK( );
  210. }