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  */
4 /** \file gui.c
5   * \brief AllegroGL GUI wrappers
6   *
7   * These are replacements for Allegro's do_dialog routine and
8   * standard dialogs (to use our version of the routine).
9   */
10 
11 
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 
28 /**
29  * \ingroup gui
30  * \brief AllegroGL-friendly version of do_dialog
31  *
32  * This behaves exactly like do_dialog but forces a screen clear,
33  * rerender, and flip, after each iteration of update_dialog.
34  *
35  * User gui components can do OpenGL or Allegro rendering to draw
36  * themselves.  They should take care not to alter any OpenGL state
37  * (or be aware that this will affect other components).  For the
38  * main render, they will be called in order, but this is not
39  * guarranteed at other times -- they may be called out of order;
40  * however the results will never be visible, so just don't crash.
41  *
42  * Before drawing the final (in-order) pass, the color and depth buffers will
43  * be cleared -- set your clear color to black or green or whatever you like.
44  * You can overdraw it with an object of course.
45  *
46  * Further notes: This routine uses allegro_gl_set_allegro_mode(), so
47  * your GUI components can use allegro_gl_unset_allegro_mode() to restore
48  * the old state while they draw themselves, provided that they use
49  * allegro_gl_set_allegro_mode() again afterwards.
50  *
51  * \param dialog an array of dialog objects terminated by one with a NULL
52  * dialog procedure.
53  * \param focus_obj index of the object on which the focus is set (-1 if you
54  * don't want anything to have the focus
55  *
56  * \sa algl_draw_mouse
57  */
algl_do_dialog(DIALOG * dialog,int focus_obj)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" */
67 	allegro_gl_set_allegro_mode();
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 */
78 	allegro_gl_unset_allegro_mode();
79 
80 	return shutdown_dialog (player);
81 }
82 
83 
84 
85 /**
86  * \ingroup gui
87  * \brief AllegroGL-friendly version of popup_dialog
88  *
89  * This routine is likely to be very slow.  It has to take a copy of the
90  * screen on entry, then where algl_do_dialog() would just clear the screen,
91  * this routine has to blit that copy back again after clearing.  This is
92  * the only way to do overlays without knowing what type of flipping is
93  * going on.
94  *
95  * Also, note that we don't save the depth buffer or anything like that so
96  * don't go around thinking that algl_popup_dialog won't affect anything
97  * when it's gone.
98  *
99  * So, unless you need overlays, it's recommended that you just use
100  * algl_do_dialog(), and if you do need overlays, it's recommended that you
101  * just use algl_do_dialog() and redraw the thing you're overlaying yourself.
102  * If you're lazy or that's impossible, use this routine...
103  *
104  * \param dialog an array of dialog objects terminated by one with a NULL
105  * dialog procedure.
106  * \param focus_obj index of the object on which the focus is set (-1 if you
107  * don't want anything to have the focus
108  *
109  * \sa algl_do_dialog, algl_draw_mouse
110  */
algl_popup_dialog(DIALOG * dialog,int focus_obj)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" */
122 	allegro_gl_set_allegro_mode();
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 */
156 	allegro_gl_unset_allegro_mode();
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 
167 /**
168  * \ingroup gui
169  * \brief Draws a mouse pointer on the screen
170  *
171  * This function draws a mouse pointer on the screen. By default, it displays
172  * Allegro's standard black arrow cursor. However the settings of the cursor
173  * can be altered by Allegro's functions for mouse cursor management like
174  * show_mouse, set_mouse_sprite, scare_mouse, and so on... As a consequence,
175  * it should be stressed that if show_mouse(NULL) is called then
176  * algl_draw_mouse() won't draw anything.
177  *
178  * Unlike Allegro, AllegroGL does not manage the mouse cursor with an
179  * interrupt routine, hence algl_draw_mouse() must be regularly called
180  * in order to display the mouse cursor (ideally it should be the last function
181  * called before allegro_gl_flip()). However if you use algl_do_dialog()
182  * then you do not need to make explicit calls to algl_draw_mouse() since
183  * algl_do_dialog() takes care of that for you.
184  *
185  * \sa algl_set_mouse_drawer
186  */
algl_draw_mouse(void)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 
268 /**
269  * \ingroup gui
270  * \brief Sets (or clears) a user mouse drawing callback
271  *
272  * This function allows to use a user-defined routine to display the mouse
273  * cursor. This allows nice effects like a spinning cube or any fancy thing
274  * you can think of to be used as a mouse cursor.
275  *
276  * When a user mouse drawing callback is enabled, set_mouse_sprite has no effect.
277  * However show_mouse and scare_mouse are still enabled.
278  *
279  * \param user_draw_mouse user routine that displays the mouse cursor (NULL if
280  * you want to get back to the standard behaviour)
281  *
282  * \sa algl_draw_mouse
283  */
algl_set_mouse_drawer(void (* user_draw_mouse)(void))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 
319 /**
320  * \ingroup gui
321  * \brief AllegroGL-friendly version of Allegro's alert3.
322  *
323  *  Displays a simple alert box, containing three lines of text (s1-s3),
324  *  and with either one, two, or three buttons. The text for these buttons
325  *  is passed in b1, b2, and b3 (NULL for buttons which are not used), and
326  *  the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
327  *  which button was selected.
328  */
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)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 
440 /**
441  * \ingroup gui
442  * \brief AllegroGL-friendly version of Allegro's alert.
443  *
444  *  Displays a simple alert box, containing three lines of text (s1-s3),
445  *  and with either one or two buttons. The text for these buttons is passed
446  *  in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
447  *  Returns 1 or 2 depending on which button was selected.
448  */
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)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 
465 /**
466  * \ingroup gui
467  * \brief Creates a viewport object where OpenGL commands can be performed.
468  *
469  *  The viewport and the scissor are updated so that this GUI object behaves
470  *  somewhat like a window. The dp field of the DIALOG object points to a
471  *  callback function : int (*callback)(BITMAP* viewport, int msg, int c) where:
472  *  viewport is a sub-bitmap of the screen limited to the area of the
473  *  DIALOG object. msg and c are the values that come from the GUI manager.
474  *  The callback function must return a sensible value to the GUI manager
475  *  like D_O_K if everything went right or D_EXIT to close the dialog.
476  */
d_algl_viewport_proc(int msg,DIALOG * d,int c)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 */
492 	allegro_gl_unset_allegro_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();
513 	allegro_gl_set_allegro_mode();
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 
allegro_gl_set_mouse_sprite(BITMAP * sprite,int xfocus,int yfocus)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 
allegro_gl_show_mouse(BITMAP * bmp,int x,int y)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 
allegro_gl_hide_mouse(void)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 
allegro_gl_move_mouse(int x,int y)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 
620