FreeBASIC  0.91.0
gfx_print.c
Go to the documentation of this file.
1 /* graphical mode text output */
2 
3 #include "fb_gfx.h"
4 
5 typedef struct _fb_PrintInfo {
8  int dirty_end;
10 
11 static __inline__
12 void fb_hSetDirty( int *dirty_start, int *dirty_end,
13  int test_start, int test_end )
14 {
15  if( *dirty_start==*dirty_end ) {
16  *dirty_start = test_start;
17  *dirty_end = test_end;
18  } else {
19  if( test_start < *dirty_start )
20  *dirty_start = test_start;
21  if( test_end > *dirty_end )
22  *dirty_end = test_end;
23  }
24 }
25 
26 static
27 void fb_hHookConScrollGfx (FB_GFXCTX *context, int x1, int y1,
28  int x2, int y2,
29  int lines,
30  int *dirty_start, int *dirty_end )
31 {
32  int h = y2 - y1;
33  int w = x2 - x1;
34  int clear_row, clear_start = 0, clear_end = 0;
35 
36  if( lines==0 )
37  return;
38 
39  clear_end = y2;
40 
41  if( lines >= h || lines < 0 ) {
42  clear_start = y1;
43  } else {
44  int y_src = y1 + lines;
45  int y_dst = y1;
46 
47  h -= lines;
48  clear_start = y1 + h;
49 
50  while( h-- )
51  fb_hPixelCpy(context->line[y_dst++], context->line[y_src++], w);
52  }
53 
54  for( clear_row=clear_start; clear_row!=clear_end; ++clear_row )
55  context->pixel_set(context->line[clear_row], context->bg_color, w);
56 
57  fb_hSetDirty( dirty_start, dirty_end, y1, y2 );
58 }
59 
60 static void fb_hHookConScroll
61  (
63  int x1, int y1,
64  int x2, int y2,
65  int rows
66  )
67 {
68  int w = x2 - x1 + 1;
69  int h = y2 - y1 + 1;
70  int clear_start, clear_end;
71  fb_PrintInfo *pInfo = (fb_PrintInfo*) handle->Opaque;
72  int font_w = __fb_gfx->font->w;
73  int font_h = __fb_gfx->font->h;
74  fb_hHookConScrollGfx( pInfo->context, x1 * font_w, y1 * font_h,
75  (x2 + 1) * font_w, (y2 + 1) * font_h,
76  rows * font_h,
77  &pInfo->dirty_start, &pInfo->dirty_end );
78 
79  /* Don't foget to update the character cells */
80  clear_end = y2 + 1;
81  if( rows >= h ) {
82  clear_start = y1;
83  } else {
84  int y_src = y1 + rows;
85  int y_dst = y1;
86  size_t con_width = __fb_gfx->text_w;
87  GFX_CHAR_CELL *src = __fb_gfx->con_pages[ pInfo->context->work_page ] + y_src * con_width;
88  GFX_CHAR_CELL *dst = __fb_gfx->con_pages[ pInfo->context->work_page ] + y_dst * con_width;
89  size_t cell_line_width = w * sizeof( GFX_CHAR_CELL );
90 
91  h -= rows;
92  clear_start = y1 + h;
93 
94  while( h-- ) {
95  memcpy( dst, src, cell_line_width );
96  dst += con_width;
97  src += con_width;
98  }
99  }
100  fb_hClearCharCells( x1, clear_start, x2+1, clear_end,
101  pInfo->context->work_page, 32,
102  pInfo->context->fg_color, pInfo->context->bg_color );
103  handle->Coord.Y = handle->Border.Bottom;
104 }
105 
106 static int fb_hHookConWriteGfx
107  (
109  int target_x, int target_y,
110  const void *buffer, size_t length,
111  int *dirty_start, int *dirty_end
112  )
113 {
114 
115  const unsigned char *pachText = (const unsigned char *) buffer;
116 
117  /* cursor? */
118  if( (length == 1) && ((size_t)*pachText == 255) )
119  {
120  /* note: can't use 'mask' because it will be always 0 (due the endless
121  levels if indirection */
122  int x;
123  for( x = 0; x < __fb_gfx->font->w; x++ )
124  {
125  context->put_pixel( context,
126  target_x + x,
127  target_y + __fb_gfx->font->h - 1,
128  context->fg_color );
129  }
130  }
131  else
132  {
133  int char_bit_mask;
134  int char_row_byte_count = BYTES_PER_PIXEL(__fb_gfx->font->w);
135  size_t i, char_size = char_row_byte_count * __fb_gfx->font->h;
136 
137  for( i=0; i!=length; ++i ) {
138  size_t char_index = (size_t) *pachText++;
139  const unsigned char *src = &__fb_gfx->font->data[char_index * char_size];
140  int char_y;
141  for (char_y = 0; char_y != __fb_gfx->font->h; char_y++)
142  {
143  int char_x, char_row_byte;
144  int text_y = target_y + char_y;
145  int text_x = target_x;
146  for( char_row_byte=0; char_row_byte!=char_row_byte_count; ++char_row_byte )
147  {
148  unsigned char char_data = *src++;
149  for (char_x = 0, char_bit_mask = 1;
150  char_x != 8;
151  char_x++, char_bit_mask <<= 1)
152  {
153  unsigned color = (char_data & char_bit_mask) ? context->fg_color : context->bg_color;
154  context->put_pixel(context, text_x++, text_y, color);
155  }
156  }
157  }
158  target_x += __fb_gfx->font->w;
159  }
160  }
161 
162  fb_hSetDirty( dirty_start, dirty_end,
163  target_y, target_y + __fb_gfx->font->h );
164 
165  return TRUE;
166 }
167 
168 static int fb_hHookConWrite
169  (
170  fb_ConHooks *handle,
171  const void *buffer,
172  size_t length
173  )
174 {
175  const char *pachText = (const char *) buffer;
176  fb_PrintInfo *pInfo = (fb_PrintInfo*) handle->Opaque;
177  int target_x = handle->Coord.X * __fb_gfx->font->w;
178  int target_y = handle->Coord.Y * __fb_gfx->font->h;
179  int res = fb_hHookConWriteGfx( pInfo->context, target_x, target_y,
180  buffer, length,
181  &pInfo->dirty_start, &pInfo->dirty_end );
182 
183  /* Don't forget to update character cells */
184  GFX_CHAR_CELL *cell =
186  + handle->Coord.Y * __fb_gfx->text_w
187  + handle->Coord.X + length;
188  unsigned fg = pInfo->context->fg_color;
189  unsigned bg = pInfo->context->bg_color;
190 
191  while( length-- ) {
192  --cell;
193  cell->ch = pachText[length];
194  cell->fg = fg;
195  cell->bg = bg;
196  }
197 
198  return res;
199 }
200 
201 void fb_GfxPrintBufferEx( const void *buffer, size_t len, int mask )
202 {
203  FB_GFXCTX *context = fb_hGetContext();
204  const char *pachText = (const char *) buffer;
205  int win_left, win_top, win_cols, win_rows;
206  int view_top, view_bottom;
207  fb_PrintInfo info;
208  fb_ConHooks hooks;
209 
210  /* Do we want to correct the console cursor position? */
211  if( (mask & FB_PRINT_FORCE_ADJUST)==0 ) {
212  /* No, we can check for the length to avoid unnecessary stuff ... */
213  if( len==0 )
214  return;
215  }
216 
217  fb_hPrepareTarget(context, NULL);
219 
220  DRIVER_LOCK();
221 
222  fb_GetSize( &win_cols, &win_rows );
223  fb_ConsoleGetView( &view_top, &view_bottom );
224  win_left = win_top = 0;
225 
226  hooks.Opaque = &info;
227  hooks.Scroll = fb_hHookConScroll;
228  hooks.Write = fb_hHookConWrite;
229  hooks.Border.Left = win_left;
230  hooks.Border.Top = win_top + view_top - 1;
231  hooks.Border.Right = win_left + win_cols - 1;
232  hooks.Border.Bottom = win_top + view_bottom - 1;
233 
234  info.context = context;
235  info.dirty_start = info.dirty_end = 0;
236 
237  {
238  hooks.Coord.X = __fb_gfx->cursor_x;
239  hooks.Coord.Y = __fb_gfx->cursor_y;
240 
243  ++hooks.Coord.Y;
244  hooks.Coord.X = hooks.Border.Left;
245  fb_hConCheckScroll( &hooks );
246  }
247 
248  fb_ConPrintTTY( &hooks,
249  pachText,
250  len,
251  TRUE );
252 
253  if( hooks.Coord.X != hooks.Border.Left
254  || hooks.Coord.Y != (hooks.Border.Bottom+1) )
255  {
256  fb_hConCheckScroll( &hooks );
257  } else {
259  hooks.Coord.X = hooks.Border.Right;
260  hooks.Coord.Y = hooks.Border.Bottom;
261  }
262  fb_GfxLocateRaw( hooks.Coord.Y, hooks.Coord.X, -1 );
263  }
264 
265  SET_DIRTY(context, info.dirty_start, info.dirty_end - info.dirty_start);
266 
267  DRIVER_UNLOCK();
268 }
269 
270 void fb_GfxPrintBuffer( const char *buffer, int mask )
271 {
272  fb_GfxPrintBufferEx(buffer, strlen(buffer), mask);
273 }
274 
275 int fb_GfxLocateRaw( int y, int x, int cursor )
276 {
277  if (x > -1)
278  __fb_gfx->cursor_x = x;
279  if (y > -1)
280  __fb_gfx->cursor_y = y;
281  return (__fb_gfx->cursor_x & 0xFF) | ((__fb_gfx->cursor_y & 0xFF) << 8);
282 }
283 
284 int fb_GfxLocate( int y, int x, int cursor )
285 {
286  int ret;
288  ret = fb_GfxLocateRaw( y - 1, x - 1, cursor ) + 0x0101;
290  return ret;
291 }
292 
293 int fb_GfxGetX( void )
294 {
295  return __fb_gfx->cursor_x + 1;
296 }
297 
298 int fb_GfxGetY( void )
299 {
300  return __fb_gfx->cursor_y + 1;
301 }
302 
303 void fb_GfxGetXY( int *col, int *row )
304 {
305  if( col != NULL )
306  *col = fb_GfxGetX( );
307 
308  if( row != NULL )
309  *row = fb_GfxGetY( );
310 }
311 
312 void fb_GfxGetSize( int *cols, int *rows )
313 {
314  if( cols != NULL )
315  *cols = __fb_gfx->text_w;
316 
317  if( rows != NULL )
318  *rows = __fb_gfx->text_h;
319 }