FreeBASIC  0.91.0
gfx_paint.c
Go to the documentation of this file.
1 /* PAINT statement */
2 
3 #include "fb_gfx.h"
4 
5 
6 typedef struct SPAN
7 {
8  int y, x1, x2;
9  struct SPAN *row_next;
10  struct SPAN *next;
11 } SPAN;
12 
13 
14 /*:::::*/
15 static SPAN *add_span(FB_GFXCTX *context, SPAN **span, int *x, int y, unsigned int border_color)
16 {
17  SPAN *s;
18  int x1, x2;
19 
20  x1 = x2 = *x;
21  while ((x1 > context->view_x) && (context->get_pixel(context, x1 - 1, y) != border_color))
22  x1--;
23  while ((x2 < context->view_x + context->view_w - 1) && (context->get_pixel(context, x2 + 1, y) != border_color))
24  x2++;
25  *x = x2 + 1;
26  for (s = span[y]; s; s = s->row_next) {
27  if ((x1 == s->x1) && (x2 == s->x2))
28  return NULL;
29  }
30  s = (SPAN *)malloc(sizeof(SPAN));
31  s->x1 = x1;
32  s->x2 = x2;
33  s->y = y;
34  s->next = NULL;
35  s->row_next = span[y];
36  span[y] = s;
37 
38  return s;
39 }
40 
41 
42 /*:::::*/
43 FBCALL void fb_GfxPaint(void *target, float fx, float fy, unsigned int color, unsigned int border_color, FBSTRING *pattern, int mode, int flags)
44 {
46  int size, x, y;
47  unsigned char data[256], *dest, *src;
48  SPAN **span, *s, *tail, *head;
49 
50  if (!__fb_gfx)
51  return;
52 
53  fb_hPrepareTarget(context, target);
54 
55  if (flags & DEFAULT_COLOR_1)
56  color = context->fg_color;
57  else
58  color = fb_hFixColor(context->target_bpp, color);
59  if (flags & DEFAULT_COLOR_2)
60  border_color = color;
61  else
62  border_color = fb_hFixColor(context->target_bpp, border_color);
63 
64  fb_hSetPixelTransfer(context,color);
65 
66  fb_hFixRelative(context, flags, &fx, &fy, NULL, NULL);
67 
68  fb_hTranslateCoord(context, fx, fy, &x, &y);
69 
70  fb_hMemSet(data, 0, sizeof(data));
71  if ((mode == PAINT_TYPE_PATTERN) && (pattern)) {
72  fb_hMemCpy(data, pattern->data, MIN(256, FB_STRSIZE(pattern)));
73  }
74  if (pattern) {
75  /* del if temp */
76  fb_hStrDelTemp( pattern );
77  }
78 
79  if ((x < context->view_x) || (x >= context->view_x + context->view_w) ||
80  (y < context->view_y) || (y >= context->view_y + context->view_h))
81  return;
82 
83  if (context->get_pixel(context, x, y) == border_color)
84  return;
85 
86  size = sizeof(SPAN *) * (context->view_y + context->view_h);
87  span = (SPAN **)malloc(size);
88  fb_hMemSet(span, 0, size);
89 
90  tail = head = add_span(context, span, &x, y, border_color);
91 
92  /* Find all spans to paint */
93  while (tail) {
94  if (tail->y - 1 >= context->view_y) {
95  for (x = tail->x1; x <= tail->x2; x++) {
96  if (context->get_pixel(context, x, tail->y - 1) != border_color) {
97  s = add_span(context, span, &x, tail->y - 1, border_color);
98  if (s) {
99  head->next = s;
100  head = s;
101  }
102  }
103  }
104  }
105  if (tail->y + 1 < context->view_y + context->view_h) {
106  for (x = tail->x1; x <= tail->x2; x++) {
107  if (context->get_pixel(context, x, tail->y + 1) != border_color) {
108  s = add_span(context, span, &x, tail->y + 1, border_color);
109  if (s) {
110  head->next = s;
111  head = s;
112  }
113  }
114  }
115  }
116  tail = tail->next;
117  }
118 
119  DRIVER_LOCK();
120 
121  /* Fill spans */
122  for (y = context->view_y; y < context->view_y + context->view_h; y++) {
123  for (s = tail = span[y]; s; s = s->row_next, free(tail), tail = s) {
124 
125  dest = context->line[s->y] + (s->x1 * context->target_bpp);
126 
127  if (mode == PAINT_TYPE_FILL)
128  context->pixel_set(dest, color, s->x2 - s->x1 + 1);
129  else {
130  src = data + (((s->y & 0x7) << 3) * context->target_bpp);
131  if (s->x1 & 0x7) {
132  if ((s->x1 & ~0x7) == (s->x2 & ~0x7))
133  size = s->x2 - s->x1 + 1;
134  else
135  size = 8 - (s->x1 & 0x7);
136  fb_hPixelCpy(dest, src + ((s->x1 & 0x7) * context->target_bpp), size);
137  dest += size * context->target_bpp;
138  }
139  s->x2++;
140  for (x = (s->x1 + 7) >> 3; x < (s->x2 & ~0x7) >> 3; x++) {
141  fb_hPixelCpy(dest, src, 8);
142  dest += 8 * context->target_bpp;
143  }
144  if ((s->x2 & 0x7) && ((s->x1 & ~0x7) != (s->x2 & ~0x7)))
145  fb_hPixelCpy(dest, src, s->x2 & 0x7);
146  }
147 
148  if (__fb_gfx->framebuffer == context->line[0])
149  __fb_gfx->dirty[context->view_y + y] = TRUE;
150  }
151  }
152  free(span);
153 
154  DRIVER_UNLOCK();
155 
156 }