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