FreeBASIC  0.91.0
gfx_line.c
Go to the documentation of this file.
1 /* LINE statement */
2 
3 #include "fb_gfx.h"
4 
5 
6 #define CLIP_LEFT_EDGE 0x1
7 #define CLIP_RIGHT_EDGE 0x2
8 #define CLIP_BOTTOM_EDGE 0x4
9 #define CLIP_TOP_EDGE 0x8
10 #define CLIP_INSIDE(a) (!a)
11 #define CLIP_REJECT(a,b) ((a) & (b))
12 #define CLIP_ACCEPT(a,b) (!((a) | (b)))
13 
14 
15 /*:::::*/
16 static int encode(FB_GFXCTX *context, int x, int y)
17 {
18  int code = 0;
19 
20  if (x < context->view_x)
21  code |= CLIP_LEFT_EDGE;
22  else if (x >= context->view_x + context->view_w)
23  code |= CLIP_RIGHT_EDGE;
24  if (y < context->view_y)
25  code |= CLIP_TOP_EDGE;
26  else if (y >= context->view_y + context->view_h)
27  code |= CLIP_BOTTOM_EDGE;
28  return code;
29 }
30 
31 
32 /*:::::*/
33 static int reverse_mask(int mask)
34 {
35  mask = ((mask >> 1) & 0x5555) | ((mask & 0x5555) << 1);
36  mask = ((mask >> 2) & 0x3333) | ((mask & 0x3333) << 2);
37  mask = ((mask >> 4) & 0x0F0F) | ((mask & 0x0F0F) << 4);
38  mask = ((mask >> 8) & 0x00FF) | ((mask & 0x00FF) << 8);
39 
40  return mask;
41 }
42 
43 
44 /*:::::*/
45 static int clip_line(FB_GFXCTX *context, int *x1, int *y1, int *x2, int *y2)
46 {
47  int code1, code2;
48  float m;
49 
50  while (1) {
51  code1 = encode(context, *x1, *y1);
52  code2 = encode(context, *x2, *y2);
53 
54  if (CLIP_ACCEPT(code1, code2))
55  break;
56  if (CLIP_REJECT(code1, code2))
57  return -1;
58  if (CLIP_INSIDE(code1)) {
59  SWAP(*x1, *x2);
60  SWAP(*y1, *y2);
61  SWAP(code1, code2);
62  }
63  if (*x1 != *x2)
64  m = (*y2 - *y1) / (float)(*x2 - *x1);
65  else
66  m = 1.0;
67  if (code1 & CLIP_LEFT_EDGE) {
68  *y1 += (context->view_x - *x1) * m;
69  *x1 = context->view_x;
70  }
71  else if (code1 & CLIP_RIGHT_EDGE) {
72  *y1 += (context->view_x + context->view_w - 1 - *x1) * m;
73  *x1 = context->view_x + context->view_w - 1;
74  }
75  else if (code1 & CLIP_TOP_EDGE) {
76  if (*x1 != *x2)
77  *x1 += (context->view_y - *y1) / m;
78  *y1 = context->view_y;
79  }
80  else if (code1 & CLIP_BOTTOM_EDGE) {
81  if (*x1 != *x2)
82  *x1 += (context->view_y + context->view_h - 1 - *y1) / m;
83  *y1 = context->view_y + context->view_h - 1;
84  }
85  }
86 
87  return 0;
88 }
89 
90 
91 /*:::::*/
92 FBCALL void fb_GfxLine(void *target, float fx1, float fy1, float fx2, float fy2, unsigned int color, int type, unsigned int style, int flags)
93 {
95  int x1, y1, x2, y2;
96  int x, y, len, d, dx, dy, ax, ay, bit = 0x8000;
97 
98  if (!__fb_gfx)
99  return;
100 
101  fb_hPrepareTarget(context, target);
102 
103  if (flags & DEFAULT_COLOR_1)
104  color = context->fg_color;
105  else
106  color = fb_hFixColor(context->target_bpp, color);
107 
108  fb_hSetPixelTransfer(context,color);
109 
110  style &= 0xFFFF;
111 
112  fb_hFixRelative(context, flags, &fx1, &fy1, &fx2, &fy2);
113 
114  fb_hTranslateCoord(context, fx1, fy1, &x1, &y1);
115  fb_hTranslateCoord(context, fx2, fy2, &x2, &y2);
116 
117  if (type == LINE_TYPE_LINE) {
118  if (clip_line(context, &x1, &y1, &x2, &y2))
119  return;
120 
121  DRIVER_LOCK();
122  if (x1 == x2) {
123  if (y1 > y2) {
124  SWAP(y1, y2);
125  style = reverse_mask(style);
126  bit = 1 << ((y2 - y1) & 0xF);
127  }
128  for (y = y1; y <= y2; y++) {
129  if (style & bit)
130  context->put_pixel(context, x1, y, color);
131  RORW1(bit);
132  }
133  }
134  else if (y1 == y2) {
135  if (x1 > x2) {
136  SWAP(x1, x2);
137  style = reverse_mask(style);
138  bit = 1 << ((x2 - x1) & 0xF);
139  }
140  if (style == 0xFFFF)
141  context->pixel_set(context->line[y1] + (x1 * __fb_gfx->bpp), color, x2 - x1 + 1);
142  else {
143  for (x = x1; x <= x2; x++) {
144  if (style & bit)
145  context->put_pixel(context, x, y1, color);
146  RORW1(bit);
147  }
148  }
149  }
150  else {
151  dx = x2 - x1;
152  dy = y2 - y1;
153  ax = ay = 1;
154  if (dx < 0) {
155  dx = -dx;
156  ax = -1;
157  }
158  if (dy < 0) {
159  dy = -dy;
160  ay = -1;
161  }
162  x = x1;
163  y = y1;
164  if (dx >= dy) {
165  len = dx + 1;
166  dy <<= 1;
167  d = dy - dx;
168  dx <<= 1;
169  for (; len; len--) {
170  if (style & bit)
171  context->put_pixel(context, x, y, color);
172  RORW1(bit);
173  if (d >= 0) {
174  y += ay;
175  d -= dx;
176  }
177  d += dy;
178  x += ax;
179  }
180  }
181  else {
182  len = dy + 1;
183  dx <<= 1;
184  d = dx - dy;
185  dy <<= 1;
186  for (; len; len--) {
187  if (style & bit)
188  context->put_pixel(context, x, y, color);
189  RORW1(bit);
190  if (d >= 0) {
191  x += ax;
192  d -= dy;
193  }
194  d += dx;
195  y += ay;
196  }
197  }
198  }
199  if (y1 > y2)
200  SWAP(y1, y2);
201  SET_DIRTY(context, y1, y2 - y1 + 1);
202  DRIVER_UNLOCK();
203  }
204  else {
205  fb_hFixCoordsOrder(&x1, &y1, &x2, &y2);
206  fb_hGfxBox(x1, y1, x2, y2, color, (type == LINE_TYPE_BF), style);
207  }
208 }