Adds GLUT_OFFSCREEN as a display mode option. This includes:
authorRichard Rauch <rkr@olib.org>
Sat, 7 Feb 2004 10:40:59 +0000 (10:40 +0000)
committerRichard Rauch <rkr@olib.org>
Sat, 7 Feb 2004 10:40:59 +0000 (10:40 +0000)
 * Recognizing the mode when you call glutCreateWindow().
   (Offscreen looks and acts like a top-level window in many
   ways.)

 * During the life of the offscreen "window", various window-management
   functions are modified to respect offscreen status.

   (Excepting reshaping windows, there is not much useful interpretation
    for managment of offscreen areas.  Reshaping is possibly more work
    than it's worth to support, and GLUT specs allow us to ignore the
    request.)

 * Cleanup for "offscreen" windows is a little different than for regular
   windows.

Windows still don't start up quite ideally.  Offscreen windows should
probably get a reshape event, but not a display.

git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@451 7f0cb862-5218-0410-a997-914c9d46530a

src/freeglut_internal.h
src/freeglut_window.c

index a97e029..3d73efc 100644 (file)
@@ -341,6 +341,8 @@ struct tagSFG_Context
 
 #if TARGET_HOST_UNIX_X11
     XVisualInfo*    VisualInfo;      /* The window's visual information     */
+    Pixmap          Pixmap;          /* Used for offscreen rendering        */
+    //GLXPixmap       GLXPixMap;       /* Used for offscreen rendering        */
 #elif TARGET_HOST_WIN32
     HDC             Device;          /* The window's device context         */
 #endif
@@ -370,8 +372,8 @@ struct tagSFG_WindowState
     int             MouseX, MouseY;     /* The most recent mouse position    */
 
     GLboolean       IsGameMode;         /* Is this the game mode window?     */
-
     GLboolean       NeedToResize;       /* Do we need to resize the window?  */
+    GLboolean       IsOffscreen;        /* Tags a `window' as on/offscreen.  */
 };
 
 
index 12e6b52..f99b673 100644 (file)
@@ -267,30 +267,30 @@ void fgOpenWindow( SFG_Window* window, const char* title,
      * XXX With a little thought, we should be able to greatly
      * XXX simplify this.
      */
-    if ( !window->IsMenu )
-      window->Window.VisualInfo = fgChooseVisual();
-    else if ( fgStructure.MenuContext )
-        window->Window.VisualInfo = fgChooseVisual();
+    if( !window->IsMenu )
+       window->Window.VisualInfo = fgChooseVisual( );
+    else if( fgStructure.MenuContext )
+        window->Window.VisualInfo = fgChooseVisual( );
     else
     {
         unsigned int current_DisplayMode = fgState.DisplayMode ;
         fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ;
-        window->Window.VisualInfo = fgChooseVisual();
+        window->Window.VisualInfo = fgChooseVisual( );
         fgState.DisplayMode = current_DisplayMode ;
     }
 
-    if ( ! window->Window.VisualInfo )
+    if( ! window->Window.VisualInfo )
     {
         /*
          * The "fgChooseVisual" returned a null meaning that the visual
          * context is not available.
          * Try a couple of variations to see if they will work.
          */
-        if ( ! ( fgState.DisplayMode & GLUT_DOUBLE ) )
+        if( !( fgState.DisplayMode & GLUT_DOUBLE ) )
         {
             fgState.DisplayMode |= GLUT_DOUBLE ;
-            window->Window.VisualInfo = fgChooseVisual();
-            fgState.DisplayMode &= ~GLUT_DOUBLE ;
+            window->Window.VisualInfo = fgChooseVisual( );
+            fgState.DisplayMode &= ~GLUT_DOUBLE;
         }
         
         /*
@@ -299,66 +299,95 @@ void fgOpenWindow( SFG_Window* window, const char* title,
          */
     }
 
-    assert( window->Window.VisualInfo != NULL );
-
     /*
-     * XXX HINT: the masks should be updated when adding/removing callbacks.
-     * XXX       This might speed up message processing. Is that true?
-     * XXX
-     * XXX A: Not appreciably, but it WILL make it easier to debug.
-     * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
-     * XXX    turns off events that it doesn't need and is a whole lot
-     * XXX    more pleasant to trace.  (Hint: Think mouse-motion!)
-     * XXX
-     * XXX    It may make a difference in networked environments or on
-     * XXX    some very slow systems, but I think that that is secondary
-     * XXX    to making debugging easier.
+     * XXX This seems to be abusing an assert() for error-checking.
+     * XXX It is possible that the visual simply can't be found,
+     * XXX in which case we should print an error and return a 0
+     * XXX for the window id, I think.
      */
-    winAttr.event_mask        = StructureNotifyMask | SubstructureNotifyMask |
-        ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask |
-        KeyRelease | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
-        PointerMotionMask | ButtonMotionMask;
-    winAttr.background_pixmap = None;
-    winAttr.background_pixel  = 0;
-    winAttr.border_pixel      = 0;
-
-    winAttr.colormap = XCreateColormap(
-        fgDisplay.Display, fgDisplay.RootWindow,
-        window->Window.VisualInfo->visual, AllocNone
-    );
-
-    mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
+    assert( window->Window.VisualInfo != NULL );
 
-    if ( window->IsMenu )
+    window->State.IsOffscreen = GL_FALSE;
+    if( fgState.DisplayMode & GLUT_OFFSCREEN )
     {
-        winAttr.override_redirect = True;
-        mask |= CWOverrideRedirect;
+       window->State.IsOffscreen = GL_TRUE;
+        window->Window.Pixmap = XCreatePixmap(
+            fgDisplay.Display, fgDisplay.RootWindow,
+            w, h,
+            window->Window.VisualInfo->depth
+        );
+        if( False != window->Window.Pixmap )
+        {
+            window->Window.Handle = glXCreateGLXPixmap(
+                fgDisplay.Display,
+                window->Window.VisualInfo,
+                window->Window.Pixmap
+            );
+            if( False == window->Window.Handle )
+                XFreePixmap( fgDisplay.Display, window->Window.Pixmap );
+        }
     }
+    else
+    {
+        /*
+         * XXX HINT: the masks should be updated when adding/removing callbacks.
+         * XXX       This might speed up message processing. Is that true?
+         * XXX
+         * XXX A: Not appreciably, but it WILL make it easier to debug.
+         * XXX    Try tracing old GLUT and try tracing freeglut.  Old GLUT
+         * XXX    turns off events that it doesn't need and is a whole lot
+         * XXX    more pleasant to trace.  (Hint: Think mouse-motion!)
+         * XXX
+         * XXX    It may make a difference in networked environments or on
+         * XXX    some very slow systems, but I think that that is secondary
+         * XXX    to making debugging easier.
+         */
+        winAttr.event_mask        =
+            StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
+            ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyRelease |
+            VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
+            PointerMotionMask | ButtonMotionMask;
+        winAttr.background_pixmap = None;
+        winAttr.background_pixel  = 0;
+        winAttr.border_pixel      = 0;
+
+        winAttr.colormap = XCreateColormap(
+            fgDisplay.Display, fgDisplay.RootWindow,
+            window->Window.VisualInfo->visual, AllocNone
+        );
 
-    window->Window.Handle = XCreateWindow(
-        fgDisplay.Display,
-        window->Parent == NULL ? fgDisplay.RootWindow :
-                                 window->Parent->Window.Handle,
-        x, y, w, h, 0,
-        window->Window.VisualInfo->depth, InputOutput,
-        window->Window.VisualInfo->visual, mask,
-        &winAttr
-    );
+        mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
+
+        if ( window->IsMenu )
+        {
+            winAttr.override_redirect = True;
+            mask |= CWOverrideRedirect;
+        }
 
+        window->Window.Handle = XCreateWindow(
+            fgDisplay.Display,
+            window->Parent == NULL ? fgDisplay.RootWindow :
+                                     window->Parent->Window.Handle,
+            x, y, w, h, 0,
+            window->Window.VisualInfo->depth, InputOutput,
+            window->Window.VisualInfo->visual, mask,
+            &winAttr
+        );
+    }
     /*
      * The GLX context creation, possibly trying the direct context rendering
      *  or else use the current context if the user has so specified
      */
-    if ( window->IsMenu )
+    if( window->IsMenu )
     {
         /*
          * If there isn't already an OpenGL rendering context for menu
          * windows, make one
          */
-        if ( !fgStructure.MenuContext )
+        if( !fgStructure.MenuContext )
         {
             fgStructure.MenuContext =
-                (SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) );
+                (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
             fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo;
             fgStructure.MenuContext->Context = glXCreateContext(
                 fgDisplay.Display, fgStructure.MenuContext->VisualInfo,
@@ -372,15 +401,15 @@ void fgOpenWindow( SFG_Window* window, const char* title,
             NULL, fgState.ForceDirectContext | fgState.TryDirectContext
         );
     }
-    else if ( fgState.UseCurrentContext )
+    else if( fgState.UseCurrentContext )
     {
-      window->Window.Context = glXGetCurrentContext();
+        window->Window.Context = glXGetCurrentContext( );
 
-      if ( ! window->Window.Context )
-        window->Window.Context = glXCreateContext(
-            fgDisplay.Display, window->Window.VisualInfo,
-            NULL, fgState.ForceDirectContext | fgState.TryDirectContext
-        );
+        if( ! window->Window.Context )
+            window->Window.Context = glXCreateContext(
+                fgDisplay.Display, window->Window.VisualInfo,
+                NULL, fgState.ForceDirectContext | fgState.TryDirectContext
+            );
     }
     else
         window->Window.Context = glXCreateContext(
@@ -426,27 +455,31 @@ void fgOpenWindow( SFG_Window* window, const char* title,
 
     wmHints.flags = StateHint;
     wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState;
+    if( GL_FALSE == window->State.IsOffscreen )
+    {
+        /*
+         * Prepare the window and iconified window names...
+         */
+        XStringListToTextProperty( (char **) &title, 1, &textProperty );
 
-    /*
-     * Prepare the window and iconified window names...
-     */
-    XStringListToTextProperty( (char **) &title, 1, &textProperty );
-
-    XSetWMProperties(
-        fgDisplay.Display,
-        window->Window.Handle,
-        &textProperty,
-        &textProperty,
-        0,
-        0,
-        &sizeHints,
-        &wmHints,
-        NULL
-    );
-    XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
-                     &fgDisplay.DeleteWindow, 1 );
-    XMapWindow( fgDisplay.Display, window->Window.Handle );
-
+        XSetWMProperties(
+            fgDisplay.Display,
+            window->Window.Handle,
+            &textProperty,
+            &textProperty,
+            0,
+            0,
+            &sizeHints,
+            &wmHints,
+            NULL
+        );
+    
+        XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
+                         &fgDisplay.DeleteWindow, 1 );
+    
+        XMapWindow( fgDisplay.Display, window->Window.Handle );
+    }
+    
 #elif TARGET_HOST_WIN32
 
     WNDCLASS wc;
@@ -552,7 +585,13 @@ void fgCloseWindow( SFG_Window* window )
 #if TARGET_HOST_UNIX_X11
 
     glXDestroyContext( fgDisplay.Display, window->Window.Context );
-    XDestroyWindow( fgDisplay.Display, window->Window.Handle );
+    if( GL_FALSE == window->State.IsOffscreen )
+        XDestroyWindow( fgDisplay.Display, window->Window.Handle );
+    else
+    {
+        glXDestroyGLXPixmap( fgDisplay.Display, window->Window.Handle );
+        XFreePixmap( fgDisplay.Display, window->Window.Pixmap );
+    }
     XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
 
 #elif TARGET_HOST_WIN32
@@ -671,17 +710,19 @@ void FGAPIENTRY glutShowWindow( void )
     freeglut_assert_ready;
     freeglut_assert_window;
 
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
-    XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
+        XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
+        XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
 
 #elif TARGET_HOST_WIN32
 
-    ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
+        ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
 
 #endif
-
+    }
     fgStructure.Window->State.Redisplay = GL_TRUE;
 }
 
@@ -693,21 +734,25 @@ void FGAPIENTRY glutHideWindow( void )
     freeglut_assert_ready;
     freeglut_assert_window;
 
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    if( fgStructure.Window->Parent == NULL )
-        XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
-                         fgDisplay.Screen );
-    else
-        XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
-    XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
+        if( fgStructure.Window->Parent == NULL )
+            XWithdrawWindow( fgDisplay.Display,
+                             fgStructure.Window->Window.Handle,
+                             fgDisplay.Screen );
+        else
+            XUnmapWindow( fgDisplay.Display,
+                          fgStructure.Window->Window.Handle );
+        XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
 
 #elif TARGET_HOST_WIN32
 
-    ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
+        ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
 
 #endif
-
+    }
     fgStructure.Window->State.Redisplay = GL_FALSE;
 }
 
@@ -720,19 +765,20 @@ void FGAPIENTRY glutIconifyWindow( void )
     freeglut_assert_window;
 
     fgStructure.Window->State.Visible   = GL_FALSE;
-
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
-                    fgDisplay.Screen );
-    XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
+        XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
+                        fgDisplay.Screen );
+        XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
 
 #elif TARGET_HOST_WIN32
 
-    ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
+        ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
 
 #endif
-
+    }
     fgStructure.Window->State.Redisplay = GL_FALSE;
 }
 
@@ -743,12 +789,11 @@ void FGAPIENTRY glutSetWindowTitle( const char* title )
 {
     freeglut_assert_ready;
     freeglut_assert_window;
-    if( fgStructure.Window->Parent != NULL )
-        return;
-
+    if( ! fgStructure.Window->Parent &&
+        ( GL_FALSE == fgStructure.Window->State.IsOffscreen ) )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    {
         XTextProperty text;
         
         text.value = (unsigned char *) title;
@@ -763,14 +808,13 @@ void FGAPIENTRY glutSetWindowTitle( const char* title )
         );
         
         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
-    }
 
 #elif TARGET_HOST_WIN32
 
-    SetWindowText( fgStructure.Window->Window.Handle, title );
+        SetWindowText( fgStructure.Window->Window.Handle, title );
 
 #endif
-
+    }
 }
 
 /*
@@ -781,12 +825,11 @@ void FGAPIENTRY glutSetIconTitle( const char* title )
     freeglut_assert_ready;
     freeglut_assert_window;
 
-    if( fgStructure.Window->Parent != NULL )
-        return;
-
+    if( ! fgStructure.Window->Parent &&
+        GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    {
         XTextProperty text;
         
         text.value = (unsigned char *) title;
@@ -801,14 +844,13 @@ void FGAPIENTRY glutSetIconTitle( const char* title )
         );
 
         XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
-    }
 
 #elif TARGET_HOST_WIN32
 
-    SetWindowText( fgStructure.Window->Window.Handle, title );
+        SetWindowText( fgStructure.Window->Window.Handle, title );
 
 #endif
-
+    }
 }
 
 /*
@@ -819,9 +861,13 @@ void FGAPIENTRY glutReshapeWindow( int width, int height )
     freeglut_assert_ready;
     freeglut_assert_window;
 
-    fgStructure.Window->State.NeedToResize = GL_TRUE;
-    fgStructure.Window->State.Width  = width ;
-    fgStructure.Window->State.Height = height;
+    /* XXX Could delete/create/set-window-id for offscreen. */
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
+        fgStructure.Window->State.NeedToResize = GL_TRUE;
+        fgStructure.Window->State.Width  = width ;
+        fgStructure.Window->State.Height = height;
+    }
 }
 
 /*
@@ -832,14 +878,16 @@ void FGAPIENTRY glutPositionWindow( int x, int y )
     freeglut_assert_ready;
     freeglut_assert_window;
 
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y );
-    XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
+        XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
+                     x, y );
+        XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
 
 #elif TARGET_HOST_WIN32
 
-    {
         RECT winRect;
         
         GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
@@ -851,10 +899,9 @@ void FGAPIENTRY glutPositionWindow( int x, int y )
             winRect.bottom - winRect.top,
             TRUE
         );
-    }
 
 #endif
-
+    }
 }
 
 /*
@@ -865,21 +912,23 @@ void FGAPIENTRY glutPushWindow( void )
     freeglut_assert_ready;
     freeglut_assert_window;
 
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
+        XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
 
 #elif TARGET_HOST_WIN32
 
-    SetWindowPos(
-        fgStructure.Window->Window.Handle,
-        HWND_BOTTOM,
-        0, 0, 0, 0,
-        SWP_NOSIZE | SWP_NOMOVE
-    );
+        SetWindowPos(
+            fgStructure.Window->Window.Handle,
+            HWND_BOTTOM,
+            0, 0, 0, 0,
+            SWP_NOSIZE | SWP_NOMOVE
+        );
 
 #endif
-
+    }
 }
 
 /*
@@ -890,21 +939,23 @@ void FGAPIENTRY glutPopWindow( void )
     freeglut_assert_ready;
     freeglut_assert_window;
 
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
+    {
 #if TARGET_HOST_UNIX_X11
 
-    XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
+        XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
 
 #elif TARGET_HOST_WIN32
 
-    SetWindowPos(
-        fgStructure.Window->Window.Handle,
-        HWND_TOP,
-        0, 0, 0, 0,
-        SWP_NOSIZE | SWP_NOMOVE
-    );
+        SetWindowPos(
+            fgStructure.Window->Window.Handle,
+            HWND_TOP,
+            0, 0, 0, 0,
+            SWP_NOSIZE | SWP_NOMOVE
+        );
 
 #endif
-
+    }
 }
 
 /*
@@ -915,8 +966,9 @@ void FGAPIENTRY glutFullScreen( void )
     freeglut_assert_ready;
     freeglut_assert_window;
 
-#if TARGET_HOST_UNIX_X11
+    if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
     {
+#if TARGET_HOST_UNIX_X11
         int x, y;
         Window w;
 
@@ -946,9 +998,7 @@ void FGAPIENTRY glutFullScreen( void )
             );
             XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
         }
-    }
 #elif TARGET_HOST_WIN32
-    {
         RECT rect;
 
         /* For fullscreen mode, force the top-left corner to 0,0
@@ -980,8 +1030,8 @@ void FGAPIENTRY glutFullScreen( void )
                       SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
                       SWP_NOZORDER
                     );
-    }
 #endif
+    }
 }
 
 /*
@@ -994,7 +1044,7 @@ void* FGAPIENTRY glutGetWindowData( void )
 
 void FGAPIENTRY glutSetWindowData(void* data)
 {
-    fgStructure.Window->UserData=data;
+    fgStructure.Window->UserData = data;
 }
 
 /*** END OF FILE ***/