AllegroGL  0.4.4
gui.c
Go to the documentation of this file.
1 /* This code is (C) AllegroGL contributors, and double licensed under
2  * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3  */
12 #include "alleggl.h"
13 #include "allglint.h"
14 
15 #include <allegro/internal/aintern.h>
16 
17 
18 static struct {
19  GLuint texture;
20  int hidden;
21  int xfocus;
22  int yfocus;
23  int width;
24  int height;
25 } allegro_gl_mouse = { 0, TRUE, 0, 0, 0, 0};
26 
27 
58 int algl_do_dialog (DIALOG *dialog, int focus_obj)
59 {
60  DIALOG_PLAYER *player;
61 
62  AGL_LOG(2, "allegro_gl_do_dialog\n");
63 
64  /* Allegro GUI routines generally use the 2D gfx functions therefore
65  we set default behaviour to allegro_gl_set_allegro_mode so that we
66  can use the GUI functions "as is" */
68 
69  player = init_dialog (dialog, focus_obj);
70  show_mouse(screen);
71 
72  /* Nothing to do here.
73  * Redrawing is done from d_algl_viewport_proc() callback. */
74  while (update_dialog (player)) {}
75 
76  show_mouse(NULL);
77  /* restore previous projection matrices */
79 
80  return shutdown_dialog (player);
81 }
82 
83 
84 
111 int algl_popup_dialog (DIALOG *dialog, int focus_obj)
112 {
113  void *backdrop;
114  DIALOG_PLAYER *player;
115  GLint read_buffer;
116 
117  AGL_LOG(2, "allegro_gl_popup_dialog\n");
118 
119  /* Allegro GUI routines generally use the 2D gfx functions therefore
120  we set default behaviour to allegro_gl_set_allegro_mode so that we
121  can use the GUI functions "as is" */
123 
124  glGetIntegerv(GL_READ_BUFFER, &read_buffer);
125  glReadBuffer (GL_FRONT); /* TODO: don't clobber */
126  glDisable(GL_DEPTH_TEST);
127  backdrop = malloc (SCREEN_W * SCREEN_H * 3 * 4);
128  glReadPixels (0, 0, SCREEN_W, SCREEN_H, GL_RGB, GL_UNSIGNED_BYTE, backdrop);
129  glReadBuffer(read_buffer);
130 
131  player = init_dialog (dialog, focus_obj);
132  show_mouse(screen);
133 
134  while (update_dialog (player)) {
135 
136  /* Redraw the GUI every frame */
137  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
138  glRasterPos2f (0., SCREEN_H-.5); /* TODO: don't clobber */
139  glDrawPixels (SCREEN_W, SCREEN_H, GL_RGB, GL_UNSIGNED_BYTE, backdrop);
140  broadcast_dialog_message (MSG_DRAW, 0);
141 
142  /* Draw the mouse cursor */
143  algl_draw_mouse();
144 
145  /* Flip buffers */
146  allegro_gl_flip();
147  }
148 
149  glRasterPos2f (0., SCREEN_H-.5); /* TODO: don't clobber */
150  glDrawPixels (SCREEN_W, SCREEN_H, GL_RGB, GL_UNSIGNED_BYTE, backdrop);
151  glEnable(GL_DEPTH_TEST);
152  free (backdrop);
153 
154  show_mouse(NULL);
155  /* restore previous projection matrices */
157 
158  return shutdown_dialog (player);
159 }
160 
161 
162 
163 /* User mouse drawing callback */
164 static void (*__algl_user_draw_mouse)(void) = NULL;
165 
166 
187 void algl_draw_mouse (void)
188 {
189  AGL_LOG(2, "allegro_gl_draw_mouse\n");
190 
191  /* don't draw the mouse if it's not in our window */
192  if (!_mouse_on || allegro_gl_mouse.hidden) return;
193 
194  if (__algl_user_draw_mouse) {
195 
196  __algl_user_draw_mouse();
197 
198  } else {
199 
200 #if 0
201  float x = mouse_x;
202  float y = mouse_y;
203 
204  int depth_enabled = glIsEnabled (GL_DEPTH_TEST);
205  int cull_enabled = glIsEnabled (GL_CULL_FACE);
206  if (depth_enabled) glDisable (GL_DEPTH_TEST);
207  if (cull_enabled) glDisable (GL_CULL_FACE);
208 
209  glBegin (GL_TRIANGLES);
210 
211  #define draw(dx,dy) \
212  glVertex2f (x + dx, y + dy); \
213  glVertex2f (x + dx, y + dy + 10); \
214  glVertex2f (x + dx + 7, y + dy + 7); \
215  glVertex2f (x + dx + 1.5, y + dy + 6); \
216  glVertex2f (x + dx + 5.5, y + dy + 14); \
217  glVertex2f (x + dx + 7.5, y + dy + 14); \
218  glVertex2f (x + dx + 3.5, y + dy + 6); \
219  glVertex2f (x + dx + 1.5, y + dy + 6); \
220  glVertex2f (x + dx + 7.5, y + dy + 14);
221 
222  glColor3f (0, 0, 0);
223  draw(-1,0)
224  draw(1,0)
225  draw(0,-1)
226  draw(0,1)
227 
228  glColor3f (1, 1, 1);
229  draw(0,0)
230 
231  #undef draw
232 
233  glEnd();
234 
235  if (depth_enabled) glEnable (GL_DEPTH_TEST);
236  if (cull_enabled) glEnable (GL_CULL_FACE);
237 #endif
238 
239  int x = mouse_x - allegro_gl_mouse.xfocus;
240  int y = mouse_y - allegro_gl_mouse.yfocus;
241 
242  glPushAttrib(GL_COLOR_BUFFER_BIT);
243  glAlphaFunc(GL_GREATER, 0.5);
244  glEnable(GL_TEXTURE_2D);
245  glEnable(GL_ALPHA_TEST);
246 
247  glBindTexture(GL_TEXTURE_2D, allegro_gl_mouse.texture);
248  glColor4f(1., 1., 1., 1.);
249  glTranslatef(-0.375, -0.375, 0);
250  glBegin(GL_QUADS);
251  glTexCoord2f(0., 1.);
252  glVertex2f(x, y);
253  glTexCoord2f(0., 0.);
254  glVertex2f(x, y + allegro_gl_mouse.height);
255  glTexCoord2f(1., 0.);
256  glVertex2f(x + allegro_gl_mouse.width, y + allegro_gl_mouse.height);
257  glTexCoord2f(1., 1.);
258  glVertex2f(x + allegro_gl_mouse.width, y);
259  glEnd();
260  glTranslatef(0.375, 0.375, 0);
261  glPopAttrib();
262  glBindTexture(GL_TEXTURE_2D, 0);
263  glDisable(GL_TEXTURE_2D);
264  }
265 }
266 
267 
284 void algl_set_mouse_drawer (void (*user_draw_mouse)(void))
285 {
286  AGL_LOG(2, "allegro_gl_set_mouse_drawer\n");
287 
288  __algl_user_draw_mouse = user_draw_mouse;
289 }
290 
291 
292 
293 
294 
295 static DIALOG alert_dialog[] =
296 {
297  /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
298  { _gui_shadow_box_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
299  { _gui_ctext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
300  { _gui_ctext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
301  { _gui_ctext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
302  { _gui_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
303  { _gui_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
304  { _gui_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
305  { d_yield_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
306  { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
307 };
308 
309 
310 #define A_S1 1
311 #define A_S2 2
312 #define A_S3 3
313 #define A_B1 4
314 #define A_B2 5
315 #define A_B3 6
316 
317 
318 
329 int algl_alert3(AL_CONST char *s1, AL_CONST char *s2, AL_CONST char *s3, AL_CONST char *b1, AL_CONST char *b2, AL_CONST char *b3, int c1, int c2, int c3)
330 {
331  char tmp[16];
332  int avg_w, avg_h;
333  int len1, len2, len3;
334  int maxlen = 0;
335  int buttons = 0;
336  int b[3];
337  int c;
338 
339  AGL_LOG(2, "allegro_gl_alert3\n");
340 
341  #define SORT_OUT_BUTTON(x) { \
342  if (b##x) { \
343  alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
344  alert_dialog[A_B##x].key = c##x; \
345  alert_dialog[A_B##x].dp = (char *)b##x; \
346  len##x = gui_strlen(b##x); \
347  b[buttons++] = A_B##x; \
348  } \
349  else { \
350  alert_dialog[A_B##x].flags |= D_HIDDEN; \
351  len##x = 0; \
352  } \
353  }
354 
355  usetc(tmp+usetc(tmp, ' '), 0);
356 
357  avg_w = text_length(font, tmp);
358  avg_h = text_height(font);
359 
360  alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
361  alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = empty_string;
362 
363  if (s1) {
364  alert_dialog[A_S1].dp = (char *)s1;
365  maxlen = text_length(font, s1);
366  }
367 
368  if (s2) {
369  alert_dialog[A_S2].dp = (char *)s2;
370  len1 = text_length(font, s2);
371  if (len1 > maxlen)
372  maxlen = len1;
373  }
374 
375  if (s3) {
376  alert_dialog[A_S3].dp = (char *)s3;
377  len1 = text_length(font, s3);
378  if (len1 > maxlen)
379  maxlen = len1;
380  }
381 
382  SORT_OUT_BUTTON(1);
383  SORT_OUT_BUTTON(2);
384  SORT_OUT_BUTTON(3);
385 
386  len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
387  if (len1*buttons > maxlen)
388  maxlen = len1*buttons;
389 
390  maxlen += avg_w*4;
391  alert_dialog[0].w = maxlen;
392  alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
393  alert_dialog[0].x + maxlen/2;
394 
395  alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
396 
397  alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
398  alert_dialog[0].x + maxlen/2 - len1/2;
399 
400  if (buttons == 3) {
401  alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
402  alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
403  }
404  else if (buttons == 2) {
405  alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
406  alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
407  }
408 
409  alert_dialog[0].h = avg_h*8;
410  alert_dialog[A_S1].y = alert_dialog[0].y + avg_h;
411  alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2;
412  alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3;
413  alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
414  alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y = alert_dialog[0].y + avg_h*5;
415  alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h*2;
416 
417  centre_dialog(alert_dialog);
418  set_dialog_color(alert_dialog, gui_fg_color, gui_bg_color);
419  for (c = 0; alert_dialog[c].proc; c++)
420  if (alert_dialog[c].proc == _gui_ctext_proc)
421  alert_dialog[c].bg = -1;
422 
423  clear_keybuf();
424 
425  do {
426  } while (gui_mouse_b());
427 
428  c = algl_popup_dialog(alert_dialog, A_B1);
429 
430  if (c == A_B1)
431  return 1;
432  else if (c == A_B2)
433  return 2;
434  else
435  return 3;
436 }
437 
438 
439 
449 int algl_alert(AL_CONST char *s1, AL_CONST char *s2, AL_CONST char *s3, AL_CONST char *b1, AL_CONST char *b2, int c1, int c2)
450 {
451  int ret;
452 
453  AGL_LOG(2, "allegro_gl_alert\n");
454 
455  ret = algl_alert3(s1, s2, s3, b1, b2, NULL, c1, c2, 0);
456 
457  if (ret > 2)
458  ret = 2;
459 
460  return ret;
461 }
462 
463 
464 
477 int d_algl_viewport_proc(int msg, DIALOG *d, int c)
478 {
479  int ret = D_O_K;
480  typedef int (*_callback)(BITMAP*, int, int);
481  _callback callback = (_callback) d->dp;
482  BITMAP *viewport = create_sub_bitmap(screen, d->x, d->y, d->w, d->h);
483 
484  AGL_LOG(3, "d_algl_viewport_proc\n");
485 
486  if (msg == MSG_DRAW) {
487  /* Draws the background */
488  clear_to_color(viewport, d->bg);
489  }
490 
491  /* First we get back into a 3D mode */
493 
494  /* Save the Viewport and Scissor states */
495  glPushAttrib(GL_SCISSOR_BIT | GL_VIEWPORT_BIT);
496 
497  /* Adapt the viewport to the object size */
498  glViewport(d->x, SCREEN_H - d->y - d->h, d->w, d->h);
499  glScissor(d->x, SCREEN_H - d->y - d->h, d->w, d->h);
500  glEnable(GL_SCISSOR_TEST);
501 
502  /* Clear the depth buffer for this scissor region */
503  if (msg == MSG_DRAW) {
504  glClear(GL_DEPTH_BUFFER_BIT);
505  }
506 
507  /* Call the callback function */
508  if (callback)
509  ret = callback(viewport, msg, c);
510 
511  /* Restore the previous state */
512  glPopAttrib();
514  destroy_bitmap(viewport);
515 
516  /* Redraw the GUI every frame */
517  if (msg == MSG_IDLE) {
518  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
519  broadcast_dialog_message (MSG_DRAW, 0);
520 
521  /* Draw the mouse cursor */
522  algl_draw_mouse();
523 
524  /* Flip buffers */
525  allegro_gl_flip();
526  }
527 
528 
529  return ret;
530 }
531 
532 
533 
534 /*****************/
535 /* Mouse manager */
536 /*****************/
537 
538 int allegro_gl_set_mouse_sprite(BITMAP *sprite, int xfocus, int yfocus)
539 {
540  BITMAP *bmp = NULL;
541  GLint old_texture;
542 
543  AGL_LOG(2, "allegro_gl_set_mouse_sprite\n");
544 
545  glGetIntegerv(GL_TEXTURE_2D_BINDING, &old_texture);
546 
547  bmp = create_bitmap_ex(bitmap_color_depth(sprite),
548  __allegro_gl_make_power_of_2(sprite->w),
549  __allegro_gl_make_power_of_2(sprite->h));
550 
551  if (allegro_gl_mouse.texture) {
552  glDeleteTextures(1, &allegro_gl_mouse.texture);
553  allegro_gl_mouse.texture = 0;
554  }
555 
556  clear_to_color(bmp, bitmap_mask_color(sprite));
557  blit(sprite, bmp, 0, 0, 0, 0, sprite->w, sprite->h);
558 #ifdef DEBUGMODE
559  save_bmp("mcursor.bmp",bmp,NULL);
560 #endif
561 
562  allegro_gl_mouse.texture = allegro_gl_make_texture_ex(AGL_TEXTURE_RESCALE
563  | AGL_TEXTURE_MASKED | AGL_TEXTURE_FLIP, bmp, -1);
564  if (!allegro_gl_mouse.texture) {
565  destroy_bitmap(bmp);
566  return -1;
567  }
568 
569  glBindTexture(GL_TEXTURE_2D, allegro_gl_mouse.texture);
570  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
571  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
572 
573  if (allegro_gl_extensions_GL.SGIS_texture_edge_clamp) {
574  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
575  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
576  }
577  else {
578  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
579  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
580  }
581 
582  glBindTexture(GL_TEXTURE_2D, old_texture);
583 
584  allegro_gl_mouse.width = bmp->w;
585  allegro_gl_mouse.height = bmp->h;
586  allegro_gl_mouse.xfocus = xfocus;
587  allegro_gl_mouse.yfocus = yfocus;
588 
589  destroy_bitmap(bmp);
590  return 0;
591 }
592 
593 
594 
595 int allegro_gl_show_mouse(BITMAP* bmp, int x, int y)
596 {
597  AGL_LOG(3, "allegro_gl_show_mouse\n");
598  allegro_gl_mouse.hidden = FALSE;
599  return 0;
600 }
601 
602 
603 
604 void allegro_gl_hide_mouse(void)
605 {
606  AGL_LOG(3, "allegro_gl_hide_mouse\n");
607  allegro_gl_mouse.hidden = TRUE;
608 }
609 
610 
611 
612 void allegro_gl_move_mouse(int x, int y)
613 {
614  AGL_LOG(3, "allegro_gl_move_mouse\n");
615  /* This function is not called from the main thread, so
616  * we must not call any OpenGL command there !!!
617  */
618 }
619 
#define AGL_TEXTURE_MASKED
Generate an alpha channel for this texture, based on the Allegro mask color.
Definition: alleggl.h:537
GLuint allegro_gl_make_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
Uploads an Allegro BITMAP to the GL driver as a texture.
Definition: texture.c:1165
int d_algl_viewport_proc(int msg, DIALOG *d, int c)
Creates a viewport object where OpenGL commands can be performed.
Definition: gui.c:477
void allegro_gl_unset_allegro_mode(void)
Restores previous OpenGL settings.
Definition: glvtable.c:2491
void algl_draw_mouse(void)
Draws a mouse pointer on the screen.
Definition: gui.c:187
void algl_set_mouse_drawer(void(*user_draw_mouse)(void))
Sets (or clears) a user mouse drawing callback.
Definition: gui.c:284
void allegro_gl_flip(void)
Flips the front and back framebuffers.
Definition: alleggl.c:951
struct AGL_EXTENSION_LIST_GL allegro_gl_extensions_GL
List of OpenGL extensions supported by AllegroGL.
Definition: glext.c:55
int algl_alert(AL_CONST char *s1, AL_CONST char *s2, AL_CONST char *s3, AL_CONST char *b1, AL_CONST char *b2, int c1, int c2)
AllegroGL-friendly version of Allegro&#39;s alert.
Definition: gui.c:449
int algl_popup_dialog(DIALOG *dialog, int focus_obj)
AllegroGL-friendly version of popup_dialog.
Definition: gui.c:111
Main header file for AllegroGL.
void allegro_gl_set_allegro_mode(void)
Prepares for Allegro drawing to the screen.
Definition: glvtable.c:2422
#define AGL_TEXTURE_FLIP
Flip the texture on the x-axis.
Definition: alleggl.h:532
#define AGL_TEXTURE_RESCALE
Tell AllegroGL to allow rescaling of the bitmap.
Definition: alleggl.h:543
int algl_do_dialog(DIALOG *dialog, int focus_obj)
AllegroGL-friendly version of do_dialog.
Definition: gui.c:58
int algl_alert3(AL_CONST char *s1, AL_CONST char *s2, AL_CONST char *s3, AL_CONST char *b1, AL_CONST char *b2, AL_CONST char *b3, int c1, int c2, int c3)
AllegroGL-friendly version of Allegro&#39;s alert3.
Definition: gui.c:329