Adds GLUT_OFFSCREEN as a display mode option. This includes:

* 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: https://svn.code.sf.net/p/freeglut/code/trunk@451 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
rkrolib 2004-02-07 10:40:59 +00:00
parent 3119df3a6c
commit 190a260143
2 changed files with 194 additions and 142 deletions

View File

@ -341,6 +341,8 @@ struct tagSFG_Context
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
XVisualInfo* VisualInfo; /* The window's visual information */ XVisualInfo* VisualInfo; /* The window's visual information */
Pixmap Pixmap; /* Used for offscreen rendering */
//GLXPixmap GLXPixMap; /* Used for offscreen rendering */
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
HDC Device; /* The window's device context */ HDC Device; /* The window's device context */
#endif #endif
@ -370,8 +372,8 @@ struct tagSFG_WindowState
int MouseX, MouseY; /* The most recent mouse position */ int MouseX, MouseY; /* The most recent mouse position */
GLboolean IsGameMode; /* Is this the game mode window? */ GLboolean IsGameMode; /* Is this the game mode window? */
GLboolean NeedToResize; /* Do we need to resize the window? */ GLboolean NeedToResize; /* Do we need to resize the window? */
GLboolean IsOffscreen; /* Tags a `window' as on/offscreen. */
}; };

View 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 With a little thought, we should be able to greatly
* XXX simplify this. * XXX simplify this.
*/ */
if ( !window->IsMenu ) if( !window->IsMenu )
window->Window.VisualInfo = fgChooseVisual(); window->Window.VisualInfo = fgChooseVisual( );
else if ( fgStructure.MenuContext ) else if( fgStructure.MenuContext )
window->Window.VisualInfo = fgChooseVisual(); window->Window.VisualInfo = fgChooseVisual( );
else else
{ {
unsigned int current_DisplayMode = fgState.DisplayMode ; unsigned int current_DisplayMode = fgState.DisplayMode ;
fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ; fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ;
window->Window.VisualInfo = fgChooseVisual(); window->Window.VisualInfo = fgChooseVisual( );
fgState.DisplayMode = current_DisplayMode ; fgState.DisplayMode = current_DisplayMode ;
} }
if ( ! window->Window.VisualInfo ) if( ! window->Window.VisualInfo )
{ {
/* /*
* The "fgChooseVisual" returned a null meaning that the visual * The "fgChooseVisual" returned a null meaning that the visual
* context is not available. * context is not available.
* Try a couple of variations to see if they will work. * 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 ; fgState.DisplayMode |= GLUT_DOUBLE ;
window->Window.VisualInfo = fgChooseVisual(); window->Window.VisualInfo = fgChooseVisual( );
fgState.DisplayMode &= ~GLUT_DOUBLE ; fgState.DisplayMode &= ~GLUT_DOUBLE;
} }
/* /*
@ -299,66 +299,95 @@ void fgOpenWindow( SFG_Window* window, const char* title,
*/ */
} }
/*
* 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.
*/
assert( window->Window.VisualInfo != NULL ); assert( window->Window.VisualInfo != NULL );
/* window->State.IsOffscreen = GL_FALSE;
* XXX HINT: the masks should be updated when adding/removing callbacks. if( fgState.DisplayMode & GLUT_OFFSCREEN )
* 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
);
mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
if ( window->IsMenu )
{ {
winAttr.override_redirect = True; window->State.IsOffscreen = GL_TRUE;
mask |= CWOverrideRedirect; 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;
window->Window.Handle = XCreateWindow( winAttr.colormap = XCreateColormap(
fgDisplay.Display, fgDisplay.Display, fgDisplay.RootWindow,
window->Parent == NULL ? fgDisplay.RootWindow : window->Window.VisualInfo->visual, AllocNone
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 * The GLX context creation, possibly trying the direct context rendering
* or else use the current context if the user has so specified * 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 * If there isn't already an OpenGL rendering context for menu
* windows, make one * windows, make one
*/ */
if ( !fgStructure.MenuContext ) if( !fgStructure.MenuContext )
{ {
fgStructure.MenuContext = fgStructure.MenuContext =
(SFG_MenuContext *)malloc ( sizeof(SFG_MenuContext) ); (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) );
fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo; fgStructure.MenuContext->VisualInfo = window->Window.VisualInfo;
fgStructure.MenuContext->Context = glXCreateContext( fgStructure.MenuContext->Context = glXCreateContext(
fgDisplay.Display, fgStructure.MenuContext->VisualInfo, fgDisplay.Display, fgStructure.MenuContext->VisualInfo,
@ -372,15 +401,15 @@ void fgOpenWindow( SFG_Window* window, const char* title,
NULL, fgState.ForceDirectContext | fgState.TryDirectContext 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 ) if( ! window->Window.Context )
window->Window.Context = glXCreateContext( window->Window.Context = glXCreateContext(
fgDisplay.Display, window->Window.VisualInfo, fgDisplay.Display, window->Window.VisualInfo,
NULL, fgState.ForceDirectContext | fgState.TryDirectContext NULL, fgState.ForceDirectContext | fgState.TryDirectContext
); );
} }
else else
window->Window.Context = glXCreateContext( window->Window.Context = glXCreateContext(
@ -426,27 +455,31 @@ void fgOpenWindow( SFG_Window* window, const char* title,
wmHints.flags = StateHint; wmHints.flags = StateHint;
wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; 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 );
/* XSetWMProperties(
* Prepare the window and iconified window names... fgDisplay.Display,
*/ window->Window.Handle,
XStringListToTextProperty( (char **) &title, 1, &textProperty ); &textProperty,
&textProperty,
XSetWMProperties( 0,
fgDisplay.Display, 0,
window->Window.Handle, &sizeHints,
&textProperty, &wmHints,
&textProperty, NULL
0, );
0,
&sizeHints, XSetWMProtocols( fgDisplay.Display, window->Window.Handle,
&wmHints, &fgDisplay.DeleteWindow, 1 );
NULL
); XMapWindow( fgDisplay.Display, window->Window.Handle );
XSetWMProtocols( fgDisplay.Display, window->Window.Handle, }
&fgDisplay.DeleteWindow, 1 );
XMapWindow( fgDisplay.Display, window->Window.Handle );
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
WNDCLASS wc; WNDCLASS wc;
@ -552,7 +585,13 @@ void fgCloseWindow( SFG_Window* window )
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
glXDestroyContext( fgDisplay.Display, window->Window.Context ); 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 */ XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
@ -671,17 +710,19 @@ void FGAPIENTRY glutShowWindow( void )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); XMapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW ); ShowWindow( fgStructure.Window->Window.Handle, SW_SHOW );
#endif #endif
}
fgStructure.Window->State.Redisplay = GL_TRUE; fgStructure.Window->State.Redisplay = GL_TRUE;
} }
@ -693,21 +734,25 @@ void FGAPIENTRY glutHideWindow( void )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
if( fgStructure.Window->Parent == NULL ) if( fgStructure.Window->Parent == NULL )
XWithdrawWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, XWithdrawWindow( fgDisplay.Display,
fgDisplay.Screen ); fgStructure.Window->Window.Handle,
else fgDisplay.Screen );
XUnmapWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); else
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ XUnmapWindow( fgDisplay.Display,
fgStructure.Window->Window.Handle );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE ); ShowWindow( fgStructure.Window->Window.Handle, SW_HIDE );
#endif #endif
}
fgStructure.Window->State.Redisplay = GL_FALSE; fgStructure.Window->State.Redisplay = GL_FALSE;
} }
@ -720,19 +765,20 @@ void FGAPIENTRY glutIconifyWindow( void )
freeglut_assert_window; freeglut_assert_window;
fgStructure.Window->State.Visible = GL_FALSE; fgStructure.Window->State.Visible = GL_FALSE;
if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, XIconifyWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
fgDisplay.Screen ); fgDisplay.Screen );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE ); ShowWindow( fgStructure.Window->Window.Handle, SW_MINIMIZE );
#endif #endif
}
fgStructure.Window->State.Redisplay = GL_FALSE; fgStructure.Window->State.Redisplay = GL_FALSE;
} }
@ -743,12 +789,11 @@ void FGAPIENTRY glutSetWindowTitle( const char* title )
{ {
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
if( fgStructure.Window->Parent != NULL ) if( ! fgStructure.Window->Parent &&
return; ( GL_FALSE == fgStructure.Window->State.IsOffscreen ) )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
{
XTextProperty text; XTextProperty text;
text.value = (unsigned char *) title; text.value = (unsigned char *) title;
@ -763,14 +808,13 @@ void FGAPIENTRY glutSetWindowTitle( const char* title )
); );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
}
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
SetWindowText( fgStructure.Window->Window.Handle, title ); SetWindowText( fgStructure.Window->Window.Handle, title );
#endif #endif
}
} }
/* /*
@ -781,12 +825,11 @@ void FGAPIENTRY glutSetIconTitle( const char* title )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
if( fgStructure.Window->Parent != NULL ) if( ! fgStructure.Window->Parent &&
return; GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
{
XTextProperty text; XTextProperty text;
text.value = (unsigned char *) title; text.value = (unsigned char *) title;
@ -801,14 +844,13 @@ void FGAPIENTRY glutSetIconTitle( const char* title )
); );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
}
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
SetWindowText( fgStructure.Window->Window.Handle, title ); SetWindowText( fgStructure.Window->Window.Handle, title );
#endif #endif
}
} }
/* /*
@ -819,9 +861,13 @@ void FGAPIENTRY glutReshapeWindow( int width, int height )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
fgStructure.Window->State.NeedToResize = GL_TRUE; /* XXX Could delete/create/set-window-id for offscreen. */
fgStructure.Window->State.Width = width ; if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
fgStructure.Window->State.Height = height; {
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_ready;
freeglut_assert_window; freeglut_assert_window;
if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle, x, y ); XMoveWindow( fgDisplay.Display, fgStructure.Window->Window.Handle,
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ x, y );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
{
RECT winRect; RECT winRect;
GetWindowRect( fgStructure.Window->Window.Handle, &winRect ); GetWindowRect( fgStructure.Window->Window.Handle, &winRect );
@ -851,10 +899,9 @@ void FGAPIENTRY glutPositionWindow( int x, int y )
winRect.bottom - winRect.top, winRect.bottom - winRect.top,
TRUE TRUE
); );
}
#endif #endif
}
} }
/* /*
@ -865,21 +912,23 @@ void FGAPIENTRY glutPushWindow( void )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); XLowerWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
SetWindowPos( SetWindowPos(
fgStructure.Window->Window.Handle, fgStructure.Window->Window.Handle,
HWND_BOTTOM, HWND_BOTTOM,
0, 0, 0, 0, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE SWP_NOSIZE | SWP_NOMOVE
); );
#endif #endif
}
} }
/* /*
@ -890,21 +939,23 @@ void FGAPIENTRY glutPopWindow( void )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{
#if TARGET_HOST_UNIX_X11 #if TARGET_HOST_UNIX_X11
XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle ); XRaiseWindow( fgDisplay.Display, fgStructure.Window->Window.Handle );
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
SetWindowPos( SetWindowPos(
fgStructure.Window->Window.Handle, fgStructure.Window->Window.Handle,
HWND_TOP, HWND_TOP,
0, 0, 0, 0, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE SWP_NOSIZE | SWP_NOMOVE
); );
#endif #endif
}
} }
/* /*
@ -915,8 +966,9 @@ void FGAPIENTRY glutFullScreen( void )
freeglut_assert_ready; freeglut_assert_ready;
freeglut_assert_window; freeglut_assert_window;
#if TARGET_HOST_UNIX_X11 if( GL_FALSE == fgStructure.Window->State.IsOffscreen )
{ {
#if TARGET_HOST_UNIX_X11
int x, y; int x, y;
Window w; Window w;
@ -946,9 +998,7 @@ void FGAPIENTRY glutFullScreen( void )
); );
XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */
} }
}
#elif TARGET_HOST_WIN32 #elif TARGET_HOST_WIN32
{
RECT rect; RECT rect;
/* For fullscreen mode, force the top-left corner to 0,0 /* 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_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING |
SWP_NOZORDER SWP_NOZORDER
); );
}
#endif #endif
}
} }
/* /*
@ -994,7 +1044,7 @@ void* FGAPIENTRY glutGetWindowData( void )
void FGAPIENTRY glutSetWindowData(void* data) void FGAPIENTRY glutSetWindowData(void* data)
{ {
fgStructure.Window->UserData=data; fgStructure.Window->UserData = data;
} }
/*** END OF FILE ***/ /*** END OF FILE ***/