FreeBASIC  0.91.0
gfx_screen.c
Go to the documentation of this file.
1 /* screen function and drivers handling */
2 
3 #include "fb_gfx.h"
4 
5 #define NUM_MODES 22
6 
7 typedef struct {
8  unsigned short w;
9  unsigned short h;
10  unsigned char depth;
11  unsigned char scanline_size;
12  unsigned char num_pages;
13  signed char palette;
14  signed char font;
15  unsigned char text_w;
16  unsigned char text_h;
17 } MODEINFO;
18 
19 static const MODEINFO mode_info[NUM_MODES] = {
20  { 0, 0, 0, 0, 1, -1 , -1 , 0, 0 }, /* NULL mode */
21  { 320, 200, 2, 1, 8, FB_PALETTE_16 , FB_FONT_8, 40, 25 }, /* CGA mode 1 */
22  { 640, 200, 1, 2, 1, FB_PALETTE_16 , FB_FONT_8, 80, 25 }, /* CGA mode 2 */
23  /* Unsupported modes (3, 4, 5, 6): */
24  { 0, 0, 0, 0, 1, -1 , -1 , 0, 0 },
25  { 0, 0, 0, 0, 1, -1 , -1 , 0, 0 },
26  { 0, 0, 0, 0, 1, -1 , -1 , 0, 0 },
27  { 0, 0, 0, 0, 1, -1 , -1 , 0, 0 },
28  { 320, 200, 4, 1, 8, FB_PALETTE_16 , FB_FONT_8 , 40, 25 }, /* EGA mode 7 */
29  { 640, 200, 4, 2, 4, FB_PALETTE_16 , FB_FONT_8 , 80, 25 }, /* EGA mode 8 */
30  { 640, 350, 4, 1, 2, FB_PALETTE_64 , FB_FONT_14, 80, 25 }, /* EGA mode 9 */
31  { 640, 350, 1, 1, 2, FB_PALETTE_2 , FB_FONT_14, 80, 25 }, /* EGA mode 10 */
32  { 640, 480, 1, 1, 1, FB_PALETTE_2 , FB_FONT_16, 80, 30 }, /* VGA mode 11 */
33  { 640, 480, 4, 1, 1, FB_PALETTE_256, FB_FONT_16, 80, 30 }, /* VGA mode 12 */
34  { 320, 200, 8, 1, 1, FB_PALETTE_256, FB_FONT_8 , 40, 25 }, /* VGA mode 13 */
35  /* New modes: */
36  { 320, 240, 8, 1, 1, FB_PALETTE_256, FB_FONT_8 , 40, 30 }, /* 14: 320x240 */
37  { 400, 300, 8, 1, 1, FB_PALETTE_256, FB_FONT_8 , 50, 37 }, /* 15: 400x300 */
38  { 512, 384, 8, 1, 1, FB_PALETTE_256, FB_FONT_16, 64, 24 }, /* 16: 512x384 */
39  { 640, 400, 8, 1, 1, FB_PALETTE_256, FB_FONT_16, 80, 25 }, /* 17: 640x400 */
40  { 640, 480, 8, 1, 1, FB_PALETTE_256, FB_FONT_16, 80, 30 }, /* 18: 640x480 */
41  { 800, 600, 8, 1, 1, FB_PALETTE_256, FB_FONT_16, 100, 37 }, /* 19: 800x600 */
42  { 1024, 768, 8, 1, 1, FB_PALETTE_256, FB_FONT_16, 128, 48 }, /* 20: 1024x768 */
43  { 1280, 1024, 8, 1, 1, FB_PALETTE_256, FB_FONT_16, 160, 64 } /* 21: 1280x1024 */
44 };
45 
46 static int screen_id = 1;
47 static char window_title_buff[WINDOW_TITLE_SIZE] = { 0 };
48 static int exit_proc_set = FALSE;
49 
50 static int set_mode
51  (
52  int mode,
53  int w, int h,
54  int depth, int scanline_size,
55  int num_pages, int refresh_rate,
56  int palette, int font,
57  int flags, float aspect,
58  int text_w, int text_h
59  );
60 
61 static void release_gfx_mem(void)
62 {
63  if (__fb_gfx) {
64  if ((__fb_gfx->driver) && (__fb_gfx->driver->exit))
65  __fb_gfx->driver->exit();
67  if (__fb_gfx->page) {
68  int i;
69  for (i = 0; i < __fb_gfx->num_pages; i++) {
70  free(((void **)(__fb_gfx->page[i]))[-1]);
71  }
72  free(__fb_gfx->page);
73  }
75  free(__fb_gfx->device_palette);
76  if (__fb_gfx->palette)
77  free(__fb_gfx->palette);
80  if (__fb_gfx->dirty)
81  free(__fb_gfx->dirty);
82  if (__fb_gfx->key)
83  free(__fb_gfx->key);
84  if (__fb_gfx->event_queue) {
85  free(__fb_gfx->event_queue);
87  }
88  free(__fb_gfx);
89  __fb_gfx = NULL;
90  }
94  }
95 }
96 
97 static void exit_proc(void)
98 {
99  if( __fb_gfx )
100  set_mode( 0, 0, 0, 0, 0, 1, 0, 0, 0, SCREEN_EXIT, 0.0, 0, 0 );
101 }
102 
103 /* Dummy function to ensure that the CONSOLE "update" hook for a VIEW PRINT
104  * doesn't get called */
105 void fb_GfxViewUpdate( void )
106 {
107 }
108 
110 {
111  int i;
112 
113  if( __fb_gfx!=NULL ) {
114  /* Free the previously allocated character cells */
115  if( __fb_gfx->con_pages!=NULL ) {
116  for (i = 0; i < __fb_gfx->num_pages; i++) {
117  free(__fb_gfx->con_pages[i]);
118  }
119  free(__fb_gfx->con_pages);
120  }
121 
122  if( do_alloc ) {
123  size_t text_size = __fb_gfx->text_w * __fb_gfx->text_h;
124 
125  /* Allocate memory for all character cells */
126  __fb_gfx->con_pages = (GFX_CHAR_CELL **)malloc(sizeof(GFX_CHAR_CELL *) * __fb_gfx->num_pages);
127  for (i = 0; i < __fb_gfx->num_pages; i++) {
128  __fb_gfx->con_pages[i] =
129  (GFX_CHAR_CELL *)calloc(1, sizeof(GFX_CHAR_CELL) * text_size);
130  }
131 
132  /* Reset all character cells with default values */
133  fb_hClearCharCells( 0, 0,
135  context->work_page,
136  32,
137  context->fg_color, context->bg_color );
138  } else {
140  }
141  }
142 }
143 
144 void fb_hClearCharCells( int x1, int y1, int x2, int y2,
145  int page,
146  FB_WCHAR ch, unsigned fg, unsigned bg )
147 {
148  GFX_CHAR_CELL fill_cell = { ch, fg, bg };
149  int clear_w = x2 - x1;
150  int text_w = __fb_gfx->text_w;
151  int move_w = text_w - clear_w;
152  GFX_CHAR_CELL *cell_line = __fb_gfx->con_pages[page]
153  + y1 * text_w + x1;
154  int y;
155  for( y=y1; y!=y2; ++y ) {
156  int x = clear_w;
157  while( x-- ) {
158  memcpy( cell_line++,
159  &fill_cell,
160  sizeof( GFX_CHAR_CELL ) );
161  }
162  cell_line += move_w;
163  }
164 }
165 
166 static int set_mode
167  (
168  int mode,
169  int w, int h,
170  int depth, int scanline_size,
171  int num_pages, int refresh_rate,
172  int palette, int font,
173  int flags, float aspect,
174  int text_w, int text_h
175  )
176 {
177  const GFXDRIVER *driver = NULL;
179  int i, j, try_count;
180  char *c, *driver_name;
181  unsigned char *dest;
182 
183  /* normalize flags */
184  if ((flags >= 0) && (flags & DRIVER_SHAPED_WINDOW))
185  flags |= DRIVER_SHAPED_WINDOW | DRIVER_NO_FRAME | DRIVER_NO_SWITCH;
186 
187  release_gfx_mem();
188 
189  if( (mode == 0) || (w == 0) ) {
190  memset(&__fb_ctx.hooks, 0, sizeof(__fb_ctx.hooks));
191 
192  if (flags != SCREEN_EXIT) {
193  /* set and clear text screen mode or the width and line_len will be wrong */
194  fb_Width( 80, 25 );
195  fb_Cls( 0 );
196  }
197  /* reset viewport to console dimensions */
198  fb_ConsoleSetTopBotRows(-1, -1);
199  } else {
227  __fb_gfx = (FBGFX *)calloc(1, sizeof(FBGFX));
228  }
229 
230  if (__fb_gfx) {
231  __fb_gfx->id = screen_id++;
232  __fb_gfx->mode_num = mode;
233  __fb_gfx->w = w;
234  __fb_gfx->h = h;
235  __fb_gfx->depth = depth;
236  if ((flags >= 0) && (flags & DRIVER_OPENGL))
237  __fb_gfx->depth = MAX(16, __fb_gfx->depth);
238  __fb_gfx->default_palette = (palette >= 0) ? &__fb_palette[palette] : NULL;
239  __fb_gfx->scanline_size = scanline_size;
240  __fb_gfx->font = (font >= 0) ? &__fb_font[font] : NULL;
241 
242  if( aspect != 0.0f )
243  __fb_gfx->aspect = aspect;
244  else
245  __fb_gfx->aspect = (4.0 / 3.0) * ((float)__fb_gfx->h / (float)__fb_gfx->w);
246 
247  switch (__fb_gfx->depth) {
248  case 15:
249  case 16: __fb_gfx->color_mask = 0xFFFF; __fb_gfx->depth = 16; break;
250  case 24:
251  case 32: __fb_gfx->color_mask = 0xFFFFFFFF; __fb_gfx->depth = 32; break;
252  default: __fb_gfx->color_mask = (1 << __fb_gfx->depth) - 1;
253  }
254 
257  __fb_gfx->page = (unsigned char **)malloc(sizeof(unsigned char *) * num_pages);
258  for (i = 0; i < num_pages; i++) {
259  /* 0xF for the para alignment, p_size is sizeof(void *) rounded up to % 16 for the storage for the original pointer */
260  int p_size = (sizeof(void *) + 0xF) & 0xF;
261  void *tmp = malloc((__fb_gfx->pitch * __fb_gfx->h) + p_size + 0xF);
262  __fb_gfx->page[i] = (unsigned char *)(((intptr_t)tmp + p_size + 0xF) & ~0xF);
263  ((void **)(__fb_gfx->page[i]))[-1] = tmp;
264  }
265  __fb_gfx->num_pages = num_pages;
267 
268  /* dirty lines array may be bigger than needed; this is to please the
269  gfx driver which is not aware of the scanline size */
270  __fb_gfx->dirty = (char *)calloc(1, __fb_gfx->h * __fb_gfx->scanline_size);
271  __fb_gfx->device_palette = (unsigned int *)calloc(1, sizeof(int) * 256);
272  __fb_gfx->palette = (unsigned int *)calloc(1, sizeof(int) * 256);
273  __fb_gfx->color_association = (unsigned char *)malloc(16);
274  __fb_gfx->key = (char *)calloc(1, 128);
275  __fb_gfx->event_queue = (EVENT *)malloc(sizeof(EVENT) * MAX_EVENTS);
277  __fb_color_conv_16to32 = (unsigned int *)malloc(sizeof(int) * 512);
278  if (flags != DRIVER_NULL) {
279  if (flags & DRIVER_ALPHA_PRIMITIVES)
281  if (flags & DRIVER_OPENGL)
283  if (flags & DRIVER_HIGH_PRIORITY)
285  }
286 
288  fb_hSetupData();
289 
290  if (!__fb_window_title)
291  {
293  if ((c = strrchr(__fb_window_title, '.')))
294  *c = '\0';
295  }
296 
297  driver_name = __fb_gfx_driver_name;
298  if (!driver_name)
299  driver_name = getenv("FBGFX");
300  if ((flags == DRIVER_NULL) || ((driver_name) && (!strcasecmp(driver_name, "null"))))
301  driver = &__fb_gfxDriverNull;
302  else {
303  for (try_count = (driver_name ? 4 : 2); try_count; try_count--) {
304  for (i = 0; __fb_gfx_drivers_list[i >> 1]; i++) {
305  driver = __fb_gfx_drivers_list[i >> 1];
306  if ((driver_name) && !(try_count & 0x1) && (strcasecmp(driver_name, driver->name))) {
307  driver = NULL;
308  continue;
309  }
310  if (!driver->init(__fb_window_title, __fb_gfx->w, __fb_gfx->h * __fb_gfx->scanline_size, __fb_gfx->depth, (i & 0x1) ? 0 : refresh_rate, flags))
311  break;
312  driver->exit();
313  driver = NULL;
314  }
315  if (driver)
316  break;
317  if (driver_name) {
318  if (try_count == 3)
319  flags ^= DRIVER_FULLSCREEN;
320  }
321  else
322  flags ^= DRIVER_FULLSCREEN;
323  }
324  }
325 
326  if (!driver) {
327  exit_proc();
329  }
330  __fb_gfx->driver = driver;
331 
332  fb_GfxPalette(-1, 0, 0, 0);
333 
334  __fb_gfx->text_w = text_w;
335  __fb_gfx->text_h = text_h;
336 
337  context = fb_hGetContext();
338 
339  fb_hResetCharCells(context, TRUE);
340  for (i = 0; i < num_pages; i++) {
341  dest = __fb_gfx->page[i];
342  for (j = 0; j < __fb_gfx->h; j++) {
343  context->pixel_set(dest, context->bg_color, context->view_w);
344  dest += __fb_gfx->pitch;
345  }
346  }
347 
348  if( !exit_proc_set ) {
350  atexit(exit_proc);
351  }
352  }
353 
354  if( flags!=SCREEN_EXIT ) {
355  /* Reset VIEW PRINT
356  *
357  * Normally, resetting VIEW PRINT should also result in setting the cursor
358  * position to Y,X = 1,1 but this doesn't seem to be suitable (at least
359  * on Win32 platforms). I don't believe that this is a problem because
360  * on DOS, the cursor position will automatically be reset when the screen
361  * mode changes and not changing the console cursor position on Win32
362  * and Linux seem to be more "natural". */
363  fb_ConsoleViewEx( 0, 0, __fb_gfx!=NULL );
364  }
365 
366  return fb_ErrorSetNum( FB_RTERROR_OK );
367 }
368 
370  (
371  int mode, int depth, int num_pages,
372  int flags, int refresh_rate
373  )
374 {
375  if( (mode < 0) || (mode >= NUM_MODES) )
377 
378  const MODEINFO *info = &mode_info[mode];
379 
380  /* One of the unsupported modes? */
381  if( (mode > 0) && (info->w == 0) )
383 
384  switch( depth ) {
385  case 8:
386  case 15:
387  case 16:
388  case 24:
389  case 32:
390  /* user's depth overrides default for mode > 13 */
391  if( mode <= 13 ) {
392  depth = info->depth;
393  }
394  break;
395  default:
396  depth = info->depth;
397  break;
398  }
399 
400  if( num_pages <= 0 ) {
401  num_pages = info->num_pages;
402  }
403 
404  int res = set_mode( mode,
405  info->w, info->h,
406  depth, info->scanline_size,
407  num_pages, refresh_rate,
408  info->palette, info->font,
409  flags, 0.0,
410  info->text_w, info->text_h );
411 
412  if( res == FB_RTERROR_OK )
413  FB_HANDLE_SCREEN->line_length = 0;
414 
415  return fb_ErrorSetNum( FB_RTERROR_OK );
416 }
417 
418 FBCALL int fb_GfxScreenQB( int mode, int visible, int active )
419 {
420 
421  int res = fb_GfxScreen( mode, 0, 0, 0, 0 );
422  if( res != FB_RTERROR_OK )
423  return res;
424 
425  if( visible >= 0 || active >= 0 )
426  return fb_ErrorSetNum( fb_PageSet( visible, active ) );
427  else
428  return fb_ErrorSetNum( FB_RTERROR_OK );
429 }
430 
432  (
433  int w, int h,
434  int depth, int num_pages,
435  int flags, int refresh_rate
436  )
437 {
438  if ((w <= 0) || (h <= 0))
440 
441  switch (depth) {
442  case 1:
443  case 2:
444  case 4:
445  case 8:
446  case 15:
447  case 16:
448  case 24:
449  case 32:
450  break;
451  default:
453  }
454 
455  if( num_pages <= 0 ) {
456  num_pages = 1;
457  }
458 
459  int res = set_mode( -1,
460  w, h,
461  depth, 1,
462  num_pages, refresh_rate,
464  flags, 1.0,
465  w / __fb_font[FB_FONT_8].w, h / __fb_font[FB_FONT_8].h );
466 
467  if( res == FB_RTERROR_OK )
468  FB_HANDLE_SCREEN->line_length = 0;
469 
470  return res;
471 }
472 
474 {
478 
481 
482  /* del if temp */
483  fb_hStrDelTemp( title );
484 }