/src/gfxlib2/gfx_draw.c

https://github.com/freebasic/fbc · C · 276 lines · 228 code · 39 blank · 9 comment · 69 complexity · 6c0d2bc682d671b2302b5c21e0192f91 MD5 · raw file

  1. /* DRAW command */
  2. #include "fb_gfx.h"
  3. #include <math.h>
  4. #include <ctype.h>
  5. #define FB_NAN ((intptr_t)0x80000000)
  6. #define SQRT_2 1.4142135623730950488016
  7. static float base_scale = 1.0;
  8. static int base_angle = 0;
  9. /* Returns sine of angle in degrees - quickly return exact values for 0/90/180/270 */
  10. static float dsin(int angle)
  11. {
  12. switch( angle )
  13. {
  14. case 0: return 0.0;
  15. case 90: return 1.0;
  16. case 180: return 0.0;
  17. case 270: return -1.0;
  18. default: return sin((float)angle * PI / 180.0);
  19. }
  20. }
  21. /* Returns cosine of angle in degrees - quickly return exact values for 0/90/180/270 */
  22. static float dcos(int angle)
  23. {
  24. switch( angle )
  25. {
  26. case 0: return 1.0;
  27. case 90: return 0.0;
  28. case 180: return -1.0;
  29. case 270: return 0.0;
  30. default: return cos((float)angle * PI / 180.0);
  31. }
  32. }
  33. /* Returns a value wrapped to the range 0..359 - avoids '%' in the range 0..719 for speed */
  34. static int mod360(int angle)
  35. {
  36. if( angle < 0 )
  37. {
  38. return ((angle + 1) % 360) + 359;
  39. }
  40. else if( angle >= 360 )
  41. {
  42. return (angle < 720)? (angle - 360) : (angle % 360);
  43. }
  44. else
  45. {
  46. return angle;
  47. }
  48. }
  49. static intptr_t parse_number(char **str)
  50. {
  51. char *c = *str;
  52. intptr_t n = FB_NAN;
  53. int negative = FALSE;
  54. while ((*c == ' ') || (*c == '\t') || (*c == '+') || (*c == '-'))
  55. {
  56. if (*c == '-')
  57. negative = !negative;
  58. c++;
  59. }
  60. while ((*c >= '0') && (*c <= '9')) {
  61. if (n == FB_NAN)
  62. n = 0;
  63. n = (n * 10) + (*c - '0');
  64. c++;
  65. }
  66. *str = c;
  67. if ((negative) && (n != FB_NAN))
  68. n = -n;
  69. return n;
  70. }
  71. FBCALL void fb_GfxDraw(void *target, FBSTRING *command)
  72. {
  73. FB_GFXCTX *context;
  74. float x, y, dx, dy, ax, ay, x2, y2;
  75. int angle = 0, diagonal = FALSE;
  76. char *c;
  77. intptr_t value1, value2;
  78. int draw = TRUE, move = TRUE, length = 0, flags, rel;
  79. FB_GRAPHICS_LOCK( );
  80. if ((!__fb_gfx) || (!command) || (!command->data)) {
  81. if (command)
  82. fb_hStrDelTemp(command);
  83. FB_GRAPHICS_UNLOCK( );
  84. return;
  85. }
  86. context = fb_hGetContext( );
  87. fb_hPrepareTarget(context, target);
  88. fb_hSetPixelTransfer(context, MASK_A_32);
  89. x = context->last_x;
  90. y = context->last_y;
  91. DRIVER_LOCK();
  92. flags = context->flags;
  93. context->flags |= CTX_VIEW_SCREEN;
  94. for (c = command->data; *c;) {
  95. switch (toupper(*c)) {
  96. case 'B':
  97. c++;
  98. draw = FALSE;
  99. break;
  100. case 'N':
  101. c++;
  102. move = FALSE;
  103. break;
  104. case 'C':
  105. c++;
  106. if ((value1 = parse_number(&c)) == FB_NAN)
  107. goto error;
  108. context->fg_color = fb_hFixColor(context->target_bpp, value1);
  109. break;
  110. case 'S':
  111. c++;
  112. if ((value1 = parse_number(&c)) == FB_NAN)
  113. goto error;
  114. base_scale = (float)value1 / 4.0;
  115. break;
  116. case 'A':
  117. c++;
  118. if ((value1 = parse_number(&c)) == FB_NAN)
  119. goto error;
  120. base_angle = (value1 & 0x3) * 90;
  121. break;
  122. case 'T':
  123. c++;
  124. if (toupper(*c) != 'A')
  125. goto error;
  126. c++;
  127. if ((value1 = parse_number(&c)) == FB_NAN)
  128. goto error;
  129. base_angle = mod360( value1 );
  130. break;
  131. case 'X':
  132. c++;
  133. /* Here we could be more severe with checking, but it's unlikely our substring
  134. * resides at location FB_NAN (0x80000000) */
  135. if ((value1 = parse_number(&c)) == FB_NAN)
  136. goto error;
  137. /* Store our current x/y for the recursive fb_GfxDraw() call */
  138. context->last_x = x;
  139. context->last_y = y;
  140. DRIVER_UNLOCK();
  141. fb_GfxDraw(target, (FBSTRING *)value1);
  142. DRIVER_LOCK();
  143. /* And update to x/y produced by the recursive fb_GfxDraw() call */
  144. x = context->last_x;
  145. y = context->last_y;
  146. break;
  147. case 'P':
  148. c++;
  149. if ((value1 = parse_number(&c)) == FB_NAN)
  150. goto error;
  151. value2 = value1;
  152. if (*c == ',') {
  153. c++;
  154. if ((value2 = parse_number(&c)) == FB_NAN)
  155. goto error;
  156. }
  157. DRIVER_UNLOCK();
  158. fb_GfxPaint(target, x, y, value1 & __fb_gfx->color_mask, value2 & __fb_gfx->color_mask, NULL, PAINT_TYPE_FILL, COORD_TYPE_A);
  159. DRIVER_LOCK();
  160. break;
  161. case 'M':
  162. c++;
  163. while ((*c == ' ') || (*c == '\t'))
  164. c++;
  165. rel = ((*c == '+') || (*c == '-'));
  166. if ((value1 = parse_number(&c)) == FB_NAN)
  167. goto error;
  168. if (*c++ != ',')
  169. goto error;
  170. if ((value2 = parse_number(&c)) == FB_NAN)
  171. goto error;
  172. x2 = (float)value1;
  173. y2 = (float)value2;
  174. if (rel) {
  175. ax = dcos(base_angle);
  176. ay = -dsin(base_angle);
  177. dx = x2;
  178. dy = y2;
  179. x2 = (((dx * ax) - (dy * ay)) * base_scale) + x;
  180. y2 = (((dy * ax) + (dx * ay)) * base_scale) + y;
  181. }
  182. if (draw) {
  183. DRIVER_UNLOCK();
  184. fb_GfxLine(target, (int)x, (int)y, (int)x2, (int)y2, 0, LINE_TYPE_LINE, 0xFFFF, COORD_TYPE_AA | DEFAULT_COLOR_1);
  185. DRIVER_LOCK();
  186. }
  187. if (move) {
  188. x = x2;
  189. y = y2;
  190. }
  191. move = draw = TRUE;
  192. break;
  193. case 'F': case 'D': angle += 90; /* fall through */
  194. case 'G': case 'L': angle += 90; /* fall through */
  195. case 'H': case 'U': angle += 90; /* fall through */
  196. case 'E': case 'R':
  197. diagonal = ((toupper(*c) >= 'E') && (toupper(*c) <= 'H'));
  198. c++;
  199. if ((value1 = parse_number(&c)) != FB_NAN)
  200. length = value1;
  201. else
  202. length = 1;
  203. angle = mod360( angle + base_angle );
  204. dx = (float)length * base_scale * dcos( angle );
  205. dy = (float)length * base_scale * -dsin( angle );
  206. if (diagonal) {
  207. x2 = x + (dx + dy);
  208. y2 = y + (dy - dx);
  209. }
  210. else {
  211. x2 = x + dx;
  212. y2 = y + dy;
  213. }
  214. if (draw) {
  215. fb_GfxDrawLine( context, CINT(x), CINT(y), CINT(x2), CINT(y2), context->fg_color, 0xffff );
  216. }
  217. if (move) {
  218. x = x2;
  219. y = y2;
  220. }
  221. angle = 0;
  222. move = draw = TRUE;
  223. break;
  224. default:
  225. c++;
  226. break;
  227. }
  228. }
  229. context->last_x = x;
  230. context->last_y = y;
  231. error:
  232. context->flags = flags;
  233. DRIVER_UNLOCK();
  234. /* del if temp */
  235. fb_hStrDelTemp( command );
  236. FB_GRAPHICS_UNLOCK( );
  237. }