1 /*
2      PLIB - A Suite of Portable Game Libraries
3      Copyright (C) 1998,2002  Steve Baker
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Library General Public
7      License as published by the Free Software Foundation; either
8      version 2 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Library General Public License for more details.
14 
15      You should have received a copy of the GNU Library General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 
19      For further information visit http://plib.sourceforge.net
20 
21      $Id: pu.cxx 2030 2005-05-23 21:24:26Z fayjf $
22 */
23 
24 #include "puLocal.h"
25 
26 #if defined(UL_AGL)
27 #  include <agl.h>
28 #elif defined(UL_CGL)
29 #  include <OpenGL/CGLCurrent.h>
30 #elif defined(UL_GLX)
31 #  include <GL/glx.h>
32 #endif
33 
34 
35 int puRefresh = TRUE ;
36 
37 
38 static puGetWindowCallback     cbGetWindow;
39 static puSetWindowCallback     cbSetWindow;
40 static puGetWindowSizeCallback cbGetWindowSize;
41 static puSetWindowSizeCallback cbSetWindowSize;
42 
43 
puSetWindowFuncs(puGetWindowCallback getWindow,puSetWindowCallback setWindow,puGetWindowSizeCallback getWindowSize,puSetWindowSizeCallback setWindowSize)44 void puSetWindowFuncs ( puGetWindowCallback   getWindow,
45 			puSetWindowCallback   setWindow,
46 			puGetWindowSizeCallback getWindowSize,
47 			puSetWindowSizeCallback setWindowSize )
48 {
49     cbGetWindow     = getWindow;
50     cbSetWindow     = setWindow;
51     cbGetWindowSize = getWindowSize;
52     cbSetWindowSize = setWindowSize;
53 }
54 
55 
puGetWindow()56 int puGetWindow ()
57 {
58     if ( !cbGetWindow )
59 	ulSetError ( UL_FATAL, "puGetWindow: Callbacks not initialized." ) ;
60     return ( *cbGetWindow ) () ;
61 }
62 
puSetWindow(int window)63 void puSetWindow ( int window )
64 {
65     if ( !cbSetWindow )
66 	ulSetError ( UL_WARNING, "puSetWindow: Cannot set window (null callback)." ) ;
67     else
68 	( *cbSetWindow ) ( window ) ;
69 }
70 
puGetWindowSize(int * width,int * height)71 void puGetWindowSize ( int *width, int *height )
72 {
73     if ( !cbGetWindowSize )
74 	ulSetError ( UL_FATAL, "puGetWindowSize: Callbacks not initialized." ) ;
75     ( *cbGetWindowSize ) ( width, height ) ;
76 }
77 
puSetWindowSize(int width,int height)78 void puSetWindowSize ( int width, int height )
79 {
80     if ( !cbSetWindowSize )
81 	ulSetError ( UL_WARNING, "puSetWindowSize: Cannot change size (null callback)." ) ;
82     else
83 	( *cbSetWindowSize ) ( width, height ) ;
84 }
85 
puGetWindowWidth()86 int puGetWindowWidth ()
87 {
88     int w, h ;
89     puGetWindowSize ( &w, &h ) ;
90     return w ;
91 }
92 
puGetWindowHeight()93 int puGetWindowHeight ()
94 {
95     int w, h ;
96     puGetWindowSize ( &w, &h ) ;
97     return h ;
98 }
99 
100 
101 
glIsValidContext(void)102 static bool glIsValidContext ( void )
103 {
104 #if defined(UL_WGL)
105   return ( wglGetCurrentContext () != NULL ) ;
106 #elif defined(UL_AGL)
107   return ( aglGetCurrentContext () != NULL ) ;
108 #elif defined(UL_CGL)
109   return ( CGLGetCurrentContext () != NULL ) ;
110 #elif defined(UL_GLX)
111   return ( glXGetCurrentContext () != NULL ) ;
112 #else
113   return true ;
114 #endif
115 }
116 
117 
118 static int _puCursor_enable = FALSE ;
119 static int _puCursor_x      = 0 ;
120 static int _puCursor_y      = 0 ;
121 static float _puCursor_bgcolour [4] = { 1.0f, 1.0f, 1.0f, 1.0f } ;
122 static float _puCursor_fgcolour [4] = { 0.0f, 0.0f, 0.0f, 1.0f } ;
123 
puHideCursor(void)124 void   puHideCursor ( void ) { _puCursor_enable = FALSE ; }
puShowCursor(void)125 void   puShowCursor ( void ) { _puCursor_enable = TRUE  ; }
puCursorIsHidden(void)126 int    puCursorIsHidden ( void ) { return ! _puCursor_enable ; }
127 
puCursor(int x,int y)128 void puCursor ( int x, int y )
129 {
130   _puCursor_x = x ;
131   _puCursor_y = y ;
132 }
133 
134 
puDrawCursor(int x,int y)135 static void puDrawCursor ( int x, int y )
136 {
137   glColor4fv ( _puCursor_bgcolour ) ;
138 
139   glBegin    ( GL_TRIANGLES ) ;
140   glVertex2i ( x, y ) ;
141   glVertex2i ( x + 13, y -  4 ) ;
142   glVertex2i ( x +  4, y - 13 ) ;
143 
144   glVertex2i ( x +  8, y -  3 ) ;
145   glVertex2i ( x + 17, y - 12 ) ;
146   glVertex2i ( x + 12, y - 17 ) ;
147 
148   glVertex2i ( x + 12, y - 17 ) ;
149   glVertex2i ( x +  3, y -  8 ) ;
150   glVertex2i ( x +  8, y -  3 ) ;
151   glEnd      () ;
152 
153   glColor4fv ( _puCursor_fgcolour ) ;
154 
155   glBegin    ( GL_TRIANGLES ) ;
156   glVertex2i ( x+1, y-1 ) ;
157   glVertex2i ( x + 11, y -  4 ) ;
158   glVertex2i ( x +  4, y - 11 ) ;
159 
160   glVertex2i ( x +  8, y -  5 ) ;
161   glVertex2i ( x + 15, y - 12 ) ;
162   glVertex2i ( x + 12, y - 15 ) ;
163 
164   glVertex2i ( x + 12, y - 15 ) ;
165   glVertex2i ( x +  5, y -  8 ) ;
166   glVertex2i ( x +  8, y -  5 ) ;
167   glEnd      () ;
168 }
169 
170 
171 // Pointer to linked list of objects to delete
172 // as a result of keyboarding or mouse clicking
173 
174 static puObject *objects_to_delete = NULL;
175 
176 
puDeleteObject(puObject * ob)177 void puDeleteObject ( puObject *ob )
178 {
179   if ( ob == NULL )
180     return ;
181 
182   puGroup *parent = ob->getParent () ;
183 
184   /* Add object to linked list to be deleted */
185   if ( objects_to_delete == NULL )
186     objects_to_delete = ob ;
187   else
188   {
189     /* Ensure that objects are deleted in the order of puDeleteObject calls */
190 
191     puObject *last ;
192 
193     for ( last = objects_to_delete ;
194           last -> getNextObject() != NULL ;
195           last = last -> getNextObject() )
196       /* Find last object. */ ;
197 
198     last -> setNextObject ( ob ) ;
199   }
200 
201   /* Remove from parent interface */
202 
203   if ( parent != ob && parent != NULL )
204      parent -> remove ( ob ) ;  /* Sets object's next and previous pointers to null as well */
205 }
206 
207 
puCleanUpJunk(void)208 void puCleanUpJunk ( void )
209 {
210   puObject * local_objects_to_delete = objects_to_delete ;
211   objects_to_delete = NULL ;
212   /* Step through the linked list of objects to delete, removing them. */
213   while ( local_objects_to_delete != NULL )
214   {
215     puObject *next_ob = local_objects_to_delete -> getNextObject() ;
216     delete local_objects_to_delete ;
217     local_objects_to_delete = next_ob ;
218 
219     /* If we've reached the end of the list, start over (in case we've deleted a group and
220      * it has put new widgets on the delete list)
221      */
222     if ( local_objects_to_delete == NULL )
223     {
224       local_objects_to_delete = objects_to_delete ;
225       objects_to_delete = NULL ;
226     }
227   }
228 }
229 
230 
231 static puObject *active_widget ;   /* Widget which is currently receiving user input */
232 static char *input_paste_buffer ;  /* Cut/Copy/Paste buffer for input widgets */
233 
234 static int firsttime = TRUE ;
235 
puRealInit(void)236 void puRealInit ( void )
237 {
238   if ( firsttime )
239   {
240     if ( ! glIsValidContext () )
241     {
242       ulSetError ( UL_FATAL,
243         "puInit called without a valid OpenGL context.");
244     }
245 
246     new puInterface ( 0, 0 ) ;
247 
248     active_widget = NULL ;
249     input_paste_buffer = NULL ;
250 
251     firsttime = FALSE ;
252   }
253 }
254 
puExit(void)255 void puExit ( void )
256 {
257   if ( firsttime )
258     ulSetError ( UL_FATAL, "puExit called without a previous call to puInit." ) ;
259 
260   delete puGetBaseLiveInterface () ;
261   firsttime = TRUE ;
262 }
263 
puSetOpenGLState(void)264 static void puSetOpenGLState ( void )
265 {
266   int w, h ;
267 
268   puGetWindowSize ( &w, &h ) ;
269 
270   glPushAttrib ( GL_ENABLE_BIT | GL_VIEWPORT_BIT  | GL_TRANSFORM_BIT | GL_LIGHTING_BIT ) ;
271 
272   glDisable      ( GL_LIGHTING   ) ;
273   glDisable      ( GL_FOG        ) ;
274   glDisable      ( GL_TEXTURE_2D ) ;
275   glDisable      ( GL_DEPTH_TEST ) ;
276   glDisable      ( GL_CULL_FACE  ) ;
277 
278   glViewport ( 0, 0, w, h ) ;
279 
280   glMatrixMode   ( GL_PROJECTION ) ;
281   glPushMatrix   () ;
282   glLoadIdentity () ;
283   glOrtho        ( 0, w, 0, h, -1, 1 ) ;
284   glMatrixMode   ( GL_MODELVIEW ) ;
285   glPushMatrix   () ;
286   glLoadIdentity () ;
287 }
288 
puRestoreOpenGLState(void)289 static void puRestoreOpenGLState ( void )
290 {
291   glMatrixMode   ( GL_PROJECTION ) ;
292   glPopMatrix    () ;
293   glMatrixMode   ( GL_MODELVIEW ) ;
294   glPopMatrix    () ;
295   glPopAttrib    () ;
296 }
297 
298 
puDisplay(void)299 void  puDisplay ( void )
300 {
301   puCleanUpJunk () ;
302 
303   puSetOpenGLState () ;
304   puGetUltimateLiveInterface () -> draw ( 0, 0 ) ;
305 
306   int h = puGetWindowHeight () ;
307 
308   if ( _puCursor_enable )
309     puDrawCursor ( _puCursor_x,
310                    h - _puCursor_y ) ;
311 
312   puRestoreOpenGLState () ;
313 
314   puRefresh = FALSE ;
315 }
316 
317 
puDisplay(int window_number)318 void  puDisplay ( int window_number )  /* Deprecated */
319 {
320   if ( window_number == puGetWindow () )
321     puDisplay () ;
322 }
323 
324 
puKeyboard(int key,int updown,int,int)325 int puKeyboard ( int key, int updown, int, int )
326 {
327   return puKeyboard ( key, updown ) ;
328 }
329 
330 
puKeyboard(int key,int updown)331 int puKeyboard ( int key, int updown )
332 {
333   int return_value = puGetBaseLiveInterface () -> checkKey ( key, updown ) ;
334 
335   puCleanUpJunk () ;
336 
337   return return_value ;
338 }
339 
340 
341 static int last_buttons = 0 ;
342 static int pu_mouse_x = 0 ;
343 static int pu_mouse_y = 0 ;
344 static int pu_mouse_offset_x = 0 ;
345 static int pu_mouse_offset_y = 0 ;
346 
puGetPressedButton()347 int puGetPressedButton ()
348 {
349   return last_buttons ;
350 }
351 
puMouse(int button,int updown,int x,int y)352 int puMouse ( int button, int updown, int x, int y )
353 {
354   puCursor ( x, y ) ;
355 
356   int h = puGetWindowHeight () ;
357 
358   if ( updown == PU_DOWN )
359     last_buttons |=  ( 1 << button ) ;
360   else
361     last_buttons &= ~( 1 << button ) ;
362 
363   pu_mouse_x = x ;
364   pu_mouse_y = h - y ;
365 
366   puObject *active = puActiveWidget () ;
367 
368   if ( ( last_buttons != 0 ) && ( active != NULL ) )
369   {
370     int x_offset, y_offset ;
371     active -> getAbsolutePosition ( &x_offset, &y_offset ) ;
372 
373     x_offset -= active -> getABox () -> min [0] ;
374     y_offset -= active -> getABox () -> min [1] ;
375 
376     if ( ( ! active -> isHit ( pu_mouse_x - x_offset, pu_mouse_y - y_offset ) ) &&
377          ( active -> getWhenToDeactivate () == PUDEACTIVATE_ON_MOUSE_CLICK ) )
378     {
379       active -> invokeDownCallback () ;
380       puDeactivateWidget () ;
381     }
382   }
383 
384   int return_value =  puGetBaseLiveInterface () -> checkHit ( button,
385     updown, pu_mouse_x, pu_mouse_y ) ;
386 
387   puCleanUpJunk () ;
388 
389   return return_value ;
390 }
391 
392 
puMouse(int x,int y)393 int puMouse ( int x, int y )
394 {
395   puCursor ( x, y ) ;
396 
397   // Pick buttons in order of descending priority:  Left, Right, Middle
398   int button =
399     (last_buttons & (1<<PU_LEFT_BUTTON  )) ?  PU_LEFT_BUTTON   :
400     (last_buttons & (1<<PU_MIDDLE_BUTTON)) ?  PU_MIDDLE_BUTTON :
401     (last_buttons & (1<<PU_RIGHT_BUTTON )) ?  PU_RIGHT_BUTTON  : PU_NOBUTTON ;
402 
403   int h = puGetWindowHeight () ;
404 
405   pu_mouse_x = x ;
406   pu_mouse_y = h - y ;
407 
408   /*
409     When you drag over an ACTIVE widget, you don't
410     affect any other widgets until you release the
411     mouse button.
412   */
413   if ( puActiveWidget () )
414   {
415     if ( puActiveWidget()->checkHit(button, PU_DRAG, pu_mouse_x - pu_mouse_offset_x,
416                                                      pu_mouse_y - pu_mouse_offset_y) )
417       return TRUE ;
418     else
419       return FALSE ;
420   }
421 
422   int return_value = puGetBaseLiveInterface () -> checkHit ( button,
423     PU_DRAG, pu_mouse_x, pu_mouse_y ) ;
424 
425   puCleanUpJunk () ;
426 
427   return return_value ;
428 }
429 
puMoveToLast(puObject * ob)430 void puMoveToLast (puObject *ob)
431 {
432   puGroup *parent = ob -> getParent () ;
433 
434   /* If no parent interface, return. */
435 
436   if ( ! parent ) return;
437 
438   /* Remove "ob" from present place in the "dlist" list */
439 
440   parent -> remove (ob) ;
441 
442   /* Place at the end of the list */
443 
444   parent -> add (ob) ;
445 
446   /*
447     Now repeat the process for the parent interface so that the interface will
448     be drawn last of all interfaces.
449   */
450 
451   puMoveToLast ( parent );
452 }
453 
puDeactivateWidget(void)454 void puDeactivateWidget ( void )  {  active_widget = NULL ; }
puSetActiveWidget(puObject * w,int x,int y)455 void puSetActiveWidget ( puObject *w, int x, int y )
456 {
457   active_widget = w ;
458   pu_mouse_offset_x = pu_mouse_x - x ;
459   pu_mouse_offset_y = pu_mouse_y - y ;
460 }
461 
puActiveWidget(void)462 puObject *puActiveWidget ( void ) {   return active_widget ; }
463 
puSetPasteBuffer(const char * ch)464 void puSetPasteBuffer ( const char *ch )
465 {
466   delete [] input_paste_buffer ;
467   input_paste_buffer = ulStrDup ( ch ) ;
468 }
469 
puGetPasteBuffer(void)470 char *puGetPasteBuffer ( void )  {  return input_paste_buffer ;  }
471 
puNeedRefresh(void)472 int  puNeedRefresh ( void )  {  return puRefresh ;  }
puPostRefresh(void)473 void puPostRefresh ( void )  {  puRefresh = TRUE ;  }
474 
475 
puSetResizeMode(int mode)476 void puSetResizeMode ( int mode )
477 {
478     static int last = 0;
479     if ( last == 0 && mode != 0 )
480 	ulSetError ( UL_WARNING, "puSetResizeMode is deprecated!" ) ;
481     last = mode ;
482 }
483