OpenGL 2.0: add 2 user-defined, per-context vertex attributes for coordinates and...
[freeglut] / src / fg_window.c
1 /*
2  * freeglut_window.c
3  *
4  * Window management methods.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Fri Dec 3 1999
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #define FREEGLUT_BUILDING_LIB
29 #include <GL/freeglut.h>
30 #include "fg_internal.h"
31
32 /*
33  * TODO BEFORE THE STABLE RELEASE:
34  *
35  *  fgSetupPixelFormat      -- ignores the display mode settings
36  *  fgOpenWindow()          -- check the Win32 version, -iconic handling!
37  *  fgCloseWindow()         -- check the Win32 version
38  *  glutCreateWindow()      -- Check when default position and size is {-1,-1}
39  *  glutCreateSubWindow()   -- Check when default position and size is {-1,-1}
40  *  glutDestroyWindow()     -- check the Win32 version
41  *  glutSetWindow()         -- check the Win32 version
42  *  glutSetWindowTitle()    -- check the Win32 version
43  *  glutSetIconTitle()      -- check the Win32 version
44  *  glutShowWindow()        -- check the Win32 version
45  *  glutHideWindow()        -- check the Win32 version
46  *  glutIconifyWindow()     -- check the Win32 version
47  *  glutPushWindow()        -- check the Win32 version
48  *  glutPopWindow()         -- check the Win32 version
49  */
50
51
52 extern void fgPlatformSetWindow ( SFG_Window *window );
53 extern void fgPlatformOpenWindow( SFG_Window* window, const char* title,
54                                   GLboolean positionUse, int x, int y,
55                                   GLboolean sizeUse, int w, int h,
56                                   GLboolean gameMode, GLboolean isSubWindow );
57 extern void fgPlatformCloseWindow( SFG_Window* window );
58 extern void fgPlatformGlutShowWindow( void );
59 extern void fgPlatformGlutHideWindow( void );
60 extern void fgPlatformGlutIconifyWindow( void );
61 extern void fgPlatformGlutSetWindowTitle( const char* title );
62 extern void fgPlatformGlutSetIconTitle( const char* title );
63 extern void fgPlatformGlutPositionWindow( int x, int y );
64 extern void fgPlatformGlutPushWindow( void );
65 extern void fgPlatformGlutPopWindow( void );
66 extern void fgPlatformGlutFullScreen( SFG_Window *win );
67 extern void fgPlatformGlutLeaveFullScreen( SFG_Window *win );
68 extern void fgPlatformGlutFullScreenToggle( SFG_Window *win );
69
70
71 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
72
73 int fghIsLegacyContextRequested( void )
74 {
75     return fgState.MajorVersion < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1);
76 }
77
78 int fghNumberOfAuxBuffersRequested( void )
79 {
80   if ( fgState.DisplayMode & GLUT_AUX4 ) {
81     return 4;
82   }
83   if ( fgState.DisplayMode & GLUT_AUX3 ) {
84     return 3;
85   }
86   if ( fgState.DisplayMode & GLUT_AUX2 ) {
87     return 2;
88   }
89   if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */
90     return fgState.AuxiliaryBufferNumber;
91   }
92   return 0;
93 }
94
95 int fghMapBit( int mask, int from, int to )
96 {
97   return ( mask & from ) ? to : 0;
98
99 }
100
101 void fghContextCreationError( void )
102 {
103     fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)",
104              fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags,
105              fgState.ContextProfile );
106 }
107
108
109 /* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */
110
111 /*
112  * Sets the OpenGL context and the fgStructure "Current Window" pointer to
113  * the window structure passed in.
114  */
115 void fgSetWindow ( SFG_Window *window )
116 {
117         fgPlatformSetWindow ( window );
118
119     fgStructure.CurrentWindow = window;
120 }
121
122 /*
123  * Opens a window. Requires a SFG_Window object created and attached
124  * to the freeglut structure. OpenGL context is created here.
125  */
126 void fgOpenWindow( SFG_Window* window, const char* title,
127                    GLboolean positionUse, int x, int y,
128                    GLboolean sizeUse, int w, int h,
129                    GLboolean gameMode, GLboolean isSubWindow )
130 {
131         fgPlatformOpenWindow( window, title,
132                    positionUse, x, y,
133                    sizeUse, w, h,
134                    gameMode, isSubWindow );
135
136     fgSetWindow( window );
137
138     window->Window.DoubleBuffered =
139         ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0;
140
141 #ifndef EGL_VERSION_1_0  /* No glDrawBuffer/glReadBuffer in GLES */
142     if ( ! window->Window.DoubleBuffered )
143     {
144         glDrawBuffer ( GL_FRONT );
145         glReadBuffer ( GL_FRONT );
146     }
147 #endif
148     window->Window.attribute_v_coord = -1;
149     window->Window.attribute_v_normal = -1;
150 }
151
152 /*
153  * Closes a window, destroying the frame and OpenGL context
154  */
155 void fgCloseWindow( SFG_Window* window )
156 {
157     /* if we're in gamemode and we're closing the gamemode window,
158      * call glutLeaveGameMode first to make sure the gamemode is
159      * properly closed before closing the window
160      */
161     if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID)
162         glutLeaveGameMode();
163
164         fgPlatformCloseWindow ( window );
165 }
166
167
168 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
169
170 /*
171  * Creates a new top-level freeglut window
172  */
173 int FGAPIENTRY glutCreateWindow( const char* title )
174 {
175     /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the
176      * XXX application has not already done so.  The "freeglut" community
177      * XXX decided not to go this route (freeglut-developer e-mail from
178      * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer]
179      * XXX Desired 'freeglut' behaviour when there is no current window"
180      */
181     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" );
182
183     return fgCreateWindow( NULL, title, fgState.Position.Use,
184                            fgState.Position.X, fgState.Position.Y,
185                            fgState.Size.Use, fgState.Size.X, fgState.Size.Y,
186                            GL_FALSE, GL_FALSE )->ID;
187 }
188
189 /*
190  * This function creates a sub window.
191  */
192 int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h )
193 {
194     int ret = 0;
195     SFG_Window* window = NULL;
196     SFG_Window* parent = NULL;
197
198     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" );
199     parent = fgWindowByID( parentID );
200     freeglut_return_val_if_fail( parent != NULL, 0 );
201     if ( x < 0 )
202     {
203         x = parent->State.Width + x ;
204         if ( w >= 0 ) x -= w ;
205     }
206
207     if ( w < 0 ) w = parent->State.Width - x + w ;
208     if ( w < 0 )
209     {
210         x += w ;
211         w = -w ;
212     }
213
214     if ( y < 0 )
215     {
216         y = parent->State.Height + y ;
217         if ( h >= 0 ) y -= h ;
218     }
219
220     if ( h < 0 ) h = parent->State.Height - y + h ;
221     if ( h < 0 )
222     {
223         y += h ;
224         h = -h ;
225     }
226
227     window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE );
228     ret = window->ID;
229
230     return ret;
231 }
232
233 /*
234  * Destroys a window and all of its subwindows
235  */
236 void FGAPIENTRY glutDestroyWindow( int windowID )
237 {
238     SFG_Window* window;
239     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
240     window = fgWindowByID( windowID );
241     freeglut_return_if_fail( window != NULL );
242     {
243         fgExecutionState ExecState = fgState.ExecState;
244         fgAddToWindowDestroyList( window );
245         fgState.ExecState = ExecState;
246     }
247 }
248
249 /*
250  * This function selects the specified window as the current window
251  */
252 void FGAPIENTRY glutSetWindow( int ID )
253 {
254     SFG_Window* window = NULL;
255
256     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
257     if( fgStructure.CurrentWindow != NULL )
258         if( fgStructure.CurrentWindow->ID == ID )
259             return;
260
261     window = fgWindowByID( ID );
262     if( window == NULL )
263     {
264         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
265         return;
266     }
267
268     fgSetWindow( window );
269 }
270
271 /*
272  * This function returns the ID number of the current window, 0 if none exists
273  */
274 int FGAPIENTRY glutGetWindow( void )
275 {
276     SFG_Window *win = fgStructure.CurrentWindow;
277     /*
278      * Since GLUT did not throw an error if this function was called without a prior call to
279      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.
280      * See Feature Request "[ 1307049 ] glutInit check".
281      */
282     if ( ! fgState.Initialised )
283         return 0;
284
285     while ( win && win->IsMenu )
286         win = win->Parent;
287     return win ? win->ID : 0;
288 }
289
290 /*
291  * This function makes the current window visible
292  */
293 void FGAPIENTRY glutShowWindow( void )
294 {
295     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
296     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
297
298         fgPlatformGlutShowWindow ();
299
300     fgStructure.CurrentWindow->State.Redisplay = GL_TRUE;
301 }
302
303 /*
304  * This function hides the current window
305  */
306 void FGAPIENTRY glutHideWindow( void )
307 {
308     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
309     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
310
311         fgPlatformGlutHideWindow ();
312
313     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
314 }
315
316 /*
317  * Iconify the current window (top-level windows only)
318  */
319 void FGAPIENTRY glutIconifyWindow( void )
320 {
321     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
322     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
323
324     fgStructure.CurrentWindow->State.Visible   = GL_FALSE;
325
326         fgPlatformGlutIconifyWindow ();
327
328     fgStructure.CurrentWindow->State.Redisplay = GL_FALSE;
329 }
330
331 /*
332  * Set the current window's title
333  */
334 void FGAPIENTRY glutSetWindowTitle( const char* title )
335 {
336     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
337     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
338     if( ! fgStructure.CurrentWindow->Parent )
339     {
340                 fgPlatformGlutSetWindowTitle ( title );
341     }
342 }
343
344 /*
345  * Set the current window's iconified title
346  */
347 void FGAPIENTRY glutSetIconTitle( const char* title )
348 {
349     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
350     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
351
352     if( ! fgStructure.CurrentWindow->Parent )
353     {
354                 fgPlatformGlutSetIconTitle ( title );
355     }
356 }
357
358 /*
359  * Change the current window's size
360  */
361 void FGAPIENTRY glutReshapeWindow( int width, int height )
362 {
363     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
364     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
365
366     if (glutGet(GLUT_FULL_SCREEN))
367     {
368       /*  Leave full screen state before resizing. */
369       glutLeaveFullScreen();
370     }
371
372     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE;
373     fgStructure.CurrentWindow->State.Width  = width ;
374     fgStructure.CurrentWindow->State.Height = height;
375 }
376
377 /*
378  * Change the current window's position
379  */
380 void FGAPIENTRY glutPositionWindow( int x, int y )
381 {
382     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
383     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
384
385     if (glutGet(GLUT_FULL_SCREEN))
386     {
387       /*  Leave full screen state before moving. */
388       glutLeaveFullScreen();
389     }
390
391         fgPlatformGlutPositionWindow ( x, y );
392 }
393
394 /*
395  * Lowers the current window (by Z order change)
396  */
397 void FGAPIENTRY glutPushWindow( void )
398 {
399     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
400     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
401
402         fgPlatformGlutPushWindow ();
403 }
404
405 /*
406  * Raises the current window (by Z order change)
407  */
408 void FGAPIENTRY glutPopWindow( void )
409 {
410     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
411     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
412
413         fgPlatformGlutPopWindow ();
414 }
415
416 /*
417  * Resize the current window so that it fits the whole screen
418  */
419 void FGAPIENTRY glutFullScreen( void )
420 {
421     SFG_Window *win;
422
423     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
424     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
425
426     win = fgStructure.CurrentWindow;
427
428     if (win->Parent)
429     {
430         /* Child windows cannot be made fullscreen, consistent with GLUT's behavior
431          * Also, what would it mean for a child window to be fullscreen, given that it
432          * is confined to its parent?
433          */
434         fgWarning("glutFullScreen called on a child window, ignoring...");
435         return;
436     }
437     else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID)
438     {
439         /* Ignore fullscreen call on GameMode window, those are always fullscreen already */
440         return;
441     }
442
443         fgPlatformGlutFullScreen ( win );
444 }
445
446 /*
447  * If we are fullscreen, resize the current window back to its original size
448  */
449 void FGAPIENTRY glutLeaveFullScreen( void )
450 {
451     SFG_Window *win;
452
453     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
454     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
455
456     win = fgStructure.CurrentWindow;
457
458         fgPlatformGlutLeaveFullScreen ( win );
459 }
460
461 /*
462  * Toggle the window's full screen state.
463  */
464 void FGAPIENTRY glutFullScreenToggle( void )
465 {
466     SFG_Window *win;
467
468     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
469     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
470
471     win = fgStructure.CurrentWindow;
472
473         fgPlatformGlutFullScreenToggle ( win );
474 }
475
476 /*
477  * A.Donev: Set and retrieve the window's user data
478  */
479 void* FGAPIENTRY glutGetWindowData( void )
480 {
481     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
482     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
483     return fgStructure.CurrentWindow->UserData;
484 }
485
486 void FGAPIENTRY glutSetWindowData(void* data)
487 {
488     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
489     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
490     fgStructure.CurrentWindow->UserData = data;
491 }
492
493 /*** END OF FILE ***/