/* * Copyright (C) 1997-2005, R3vis Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA, or visit http://www.gnu.org/copyleft/lgpl.html. * * Original Contributor: * Wes Bethel, R3vis Corporation, Marin County, California * Additional Contributor(s): * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: rmx.c,v 1.13 2005/06/08 18:32:20 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.13 $ * $Log: rmx.c,v $ * Revision 1.13 2005/06/08 18:32:20 wes * Tweak in rmPipeCreateContext to gracefully return RM_WHACKED if * unable to create the requested visual. * * Revision 1.12 2005/05/16 01:04:29 wes * Streamlining process of creating context, add private_rmxCreateVisual * (code refactoring). * * Revision 1.11 2005/02/19 16:40:20 wes * Distro sync and consolidation. * Repairs to fix memory leak associated with repeated calls to rmPipeNew, * rmPipeMakeCurrent, rmPipeClose. * * Revision 1.10 2005/01/23 17:00:22 wes * Copyright updated to 2005. * * Revision 1.9 2004/09/28 00:42:24 wes * Removed some dead code. * * Revision 1.8 2004/09/26 21:44:57 wes * Modified "close context" routine in X11 to do more thorough checking * before closing the context, before destroying the window and closing * the display. Additionally, when the window or display are closed, * set the internal RMpipe variables so that the display and/or window * fields are effectively zeroed out. This will prevent errors if * rmPipeClose is called more than once on a single RMpipe. * * Revision 1.7 2004/01/16 16:49:50 wes * Updated copyright line for 2004. * * Revision 1.6 2003/12/12 00:35:15 wes * Fiddling with order of context destroy routines to avoid a problem * seen with the rm2screen demo on a RH8 system and the 44.96 nvidia drivers * (a segfault deep inside the nvidia driver). * * Revision 1.5 2003/10/03 19:19:07 wes * Migrate away from platform-specific interfaces to the OpenGL context, * and use a single interface: rmPipeSet/GetContext. * * Revision 1.4 2003/03/16 21:56:16 wes * Documentation updates. * * Revision 1.3 2003/02/14 00:20:12 wes * Remove dead code. * * Revision 1.2 2003/02/02 02:07:16 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.18 2003/01/27 05:04:42 wes * Changes to RMpipe API and initialization sequence to unify GLX, WGL and CR * platforms w/o too much disruption to existing apps. * * Revision 1.17 2003/01/16 22:21:17 wes * Updated all source files to reflect new organization of header files: * all header files formerly located in include/rmaux, include/rmi, include/rmv * are now located in include/rm. * * Revision 1.16 2002/12/31 00:55:22 wes * * Various enhancements to support Chromium - achitecture-specific sections * of RMpipe were cleaned up, etc. * * Revision 1.15 2002/12/04 14:50:33 wes * Cleanup SGI compiles. * * Revision 1.14 2002/09/17 14:16:58 wes * private_rmxPipeCreateContext will now return RM_WHACKED if it can't * obtain an OpenGL context with the requested visual type (e.g, GLX_STEREO). * * Revision 1.13 2002/04/30 19:37:09 wes * Updated copyright dates. * * Revision 1.12 2001/10/15 00:15:39 wes * Added new routine: rmPipeSetOffscreenWindow() - use this routine to * assign an offscreen (rather than onscreen) window to an RMpipe. This * new routine is needed to complement the code that destroys windows * when the RMpipe is closed. * * Revision 1.11 2001/07/15 17:14:52 wes * Added/fixed code that selects direct vs. indirect OpenGL contexts. * * Revision 1.10 2001/06/03 20:51:34 wes * Removed dead code. * * Revision 1.9 2001/05/26 14:39:34 wes * Reinstated code that attempts to create a direct OpenGL context * before falling back to an indirect OpenGL context. * * Revision 1.8 2001/03/31 17:12:39 wes * v1.4.0-alpha-2 checkin. * * Revision 1.7 2000/12/04 00:42:35 wes * Minor tweaks to eliminate compile warnings. * * Revision 1.6 2000/12/03 22:33:55 wes * Mods for thread-safety. * * Revision 1.5 2000/10/03 11:40:28 wes * Contributions from jdb - prototype cleanups. * * Revision 1.4 2000/05/14 23:37:11 wes * Added control via RMpipe attribute to how OpenGL matrix stack * is initialized or used during rendering. * * Revision 1.3 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * Revision 1.2 2000/02/29 23:43:53 wes * Compile warning cleanups. * * Revision 1.1.1.1 2000/02/28 21:29:40 wes * OpenRM 1.2 Checkin * * Revision 1.1.1.1 2000/02/28 17:18:48 wes * Initial entry - pre-RM120 release, source base for OpenRM 1.2. * */ #include #include "rmprivat.h" #ifdef RM_X #include /* * this file contains X/GLX specific functions used to manage * windows & pipes. * * Use of OpenGL requires some amount of interface with the native * window system. This interface can be (nearly completely) * encapsulated within the RMpipe object, or applications that already * have a significant base of window management code may choose to * manage their own windows. * * In this file are contained many of the X11 routines that are used * to interface between applications, X11 and OpenGL. Those applications * that wish to manage their own windows, visuals, etc. will make * extensive use of the routines in this file. */ /* PRIVATE declarations */ /* OpenGL attributes for single- and double-buffered true-color RGB with Z-buffer */ static int single_buffer_rgba[] = {GLX_RGBA, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None, None}; static int double_buffer_rgba[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None, None}; Colormap cmap; /* * ---------------------------------------------------- * @Name rmxPipeSetDisplay @pstart RMenum rmxPipeSetDisplay (RMpipe *toModify, Display *display) @pend @astart RMpipe *toModify - a handle to an RMpipe that will be modified by this routine (modified). Display *display - a handle to an opened X display (input). @aend @dstart This routine assigns an X display handle to an RMpipe, returning RM_CHILL upon success, or RM_WHACKED upon failure. Only those applications that want to do their own XOpenDisplay calls will make use of this routine. @dend * ---------------------------------------------------- */ RMenum rmxPipeSetDisplay (RMpipe *p, Display *d) { if (RM_ASSERT(p, "rmxPipeSetDisplay() error: the input RMpipe is NULL") == RM_WHACKED) return(RM_WHACKED); if (p->xdisplay != NULL) /* close the old one if assigned */ XCloseDisplay(p->xdisplay); p->xdisplay = d; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmxPipeGetDisplay @pstart Display * rmxPipeGetDisplay (const RMpipe *toQuery) @pend @astart const RMpipe *toQuery - a handle to an RMpipe object that will be queried (input). @aend @dstart Returns to the caller the X Display handle associated with an RMpipe. @dend * ---------------------------------------------------- */ Display * rmxPipeGetDisplay (const RMpipe *p) { if (RM_ASSERT(p, "rmxPipeGetDisplay() error: the input RMpipe is NULL") == RM_WHACKED) return(NULL); return(p->xdisplay); } /* * ---------------------------------------------------- * @Name rmxPipeSetColormap @pstart RMenum rmxPipeSetColormap (RMpipe *toModify, const Colormap newCmap) @pend @astart RMpipe *toModify - a handle to an RMpipe (modified). Colormap newCmap - an X colormap handle. @aend @dstart Directly assigns an X Colormap to an RMpipe object. This routine allows applications that require specific and precise control to modify the X Colormap within an RMpipe. The only time that the X Colormap is ever used inside an RMpipe is when rmauxCreateWindow is used to create a new X window. Returns RM_CHILL upon success, or RM_WHACKED upon failure. @dend * ---------------------------------------------------- */ RMenum rmxPipeSetColormap (RMpipe *pipe, const Colormap cmap) { if (RM_ASSERT(pipe, "rmxPipeSetColormap() error: the input RMpipe is NULL") == RM_WHACKED) return(RM_WHACKED); pipe->xcolormap = cmap; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmxPipeGetColormap @pstart Colormap rmxPipeGetColormap (const RMpipe *toQuery) @pend @astart const RMpipe *toQuery - a handle to an RMpipe (input). @aend @dstart Returns to the caller the X Colormap handle attribute of an RMpipe object. If the input RMpipe is NULL, a value of zero is returned. @dend * ---------------------------------------------------- */ Colormap rmxPipeGetColormap (const RMpipe *pipe) { if (RM_ASSERT(pipe, "rmxPipeGetColormap() error: the input RMpipe is NULL") == RM_WHACKED) return(0); return(pipe->xcolormap); } /* * ---------------------------------------------------- * @Name rmxGetSharableColormap @pstart Colormap rmxGetSharableColormap (Display *d, XVisualInfo *v) @pend @astart Display *d - a handle to an opened X Display (input). XVisualInfo *v - a handle to a valid XVisualInfo structure (input). @aend @dstart Obtains a standard, sharable colormap suitable for use by XCreateWindow. Returns a handle to a valid X Colormap upon success, otherwise zero is returned. Only those applications that create their own windows will need to use this routine. When using OpenGL, a sharable Colormap that is compatible with the OpenGL-compatible XVisual must be specified to XCreateWindow, otherwise a BadMatch error will be generated when the window is mapped. @dend * ---------------------------------------------------- */ Colormap rmxGetSharableColormap (Display *d, XVisualInfo *v) { int i, numCmaps, status; XStandardColormap *standardCmaps; Colormap c = 0; status = XmuLookupStandardColormap(d, v->screen, v->visualid, v->depth, XA_RGB_DEFAULT_MAP, False,True); if (status) { status = XGetRGBColormaps(d, RootWindow(d, v->screen), &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP); for (i = 0; i < numCmaps; i++) { if (standardCmaps[i].visualid == v->visualid) { c = standardCmaps[i].colormap; XFree(standardCmaps); return(c); } } c = XCreateColormap(d, RootWindow(d, v->screen), v->visual, AllocNone); } else c = DefaultColormap(d, v->screen); return(c); } /* * ---------------------------------------------------- * @Name rmxPipeSetVisual @pstart RMenum rmxPipeSetVisual(RMpipe *toModify, XVisualInfo *visual) @pend @astart RMpipe *toModify - a handle to an RMpipe object (modified). XVisualInfo *visual - a handle to an XVisualInfo structure (input). @aend @dstart This routine will assign the specified X Visual to the RMpipe object, returning RM_CHILL upon success or RM_WHACKED upon failure. Under usual circumstances, the XVisual inside an RMpipe is discovered and assigned by RM when rmPipeInit is called. The RM-discovered visual will be suitable for OpenGL rendering. This routine may be used by applications that wish to discover their own visual and assign that to an RMpipe. The X visual structure is used at the time that an OpenGL rendering context is created. When rmPipeInit is called, an OpenGL rendering context is created automatically. It will be a rare occurance when an application will call this routine. Usually, applications that create their own X windows will use rmxPipeGetVisual to obtain the X Visual that is compatible with OpenGL for use in creating an X window. This routine may be removed in a future version of RM (January 2000). @dend * ---------------------------------------------------- */ RMenum rmxPipeSetVisual (RMpipe *pipe, XVisualInfo *visual) { if ((RM_ASSERT(pipe, "rmxPipeSetVisual() error: the input RMpipe is NULL") == RM_WHACKED) || (RM_ASSERT(visual, "rmxPipeSetVisual() error: the input Xvisual is NULL") == RM_WHACKED)) return(RM_WHACKED); pipe->xvisual = visual; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmxPipeGetVisual @pstart XVisualInfo * rmxPipeGetVisual (const RMpipe *toQuery) @pend @astart const RMpipe *toQuery - a handle to an RMpipe (input). @aend @dstart Use this routine to obtain the handle of the XVisualInfo struct associated with an RMpipe object. This attribute will be valid only after the RMpipe has been initialized with rmPipeInit. Upon success, returns the handle to an XVisualInfo structure, or NULL upon failure. At this time (January 2000), no check is made to determine if the XVisualInfo structure inside the RMpipe is valid at the time when this routine is called. @dend * ---------------------------------------------------- */ XVisualInfo * rmxPipeGetVisual (const RMpipe *pipe) { if (RM_ASSERT(pipe, "rmxPipeGetVisual() error: the input RMpipe is NULL") == RM_WHACKED) return(NULL); return(pipe->xvisual); } /* * ---------------------------------------------------- * @Name rmPipeSetContext @pstart RMenum rmPipeSetContext (RMpipe *toModify, GLXContext context) @pend @astart RMpipe *toModify - a handle to an RMpipe object (modified). GLXContext context - a handle to a valid GLXContext (an OpenGL rendering context) (input). @aend @dstart Use this routine to assign an X11 OpenGL rendering context to an RMpipe. Inside this routine, the input context "theContext" is copied into a field internal to the RMpipe object. This routine would be used, for example, to obtain an OpenGL context from your application (e.g., some FLTK infrastructure) and to tell OpenRM to use it for subsequent rendering. Since this routine only makes a copy of the context, you need to "make it current" with a call to rmPipeMakeCurrent *after* you call rmPipeSetContext. This routine will return RM_WHACKED if the input RMpipe is NULL. Otherwise, it returns RM_CHILL. No error checking is performed on the input X11 OpenGL context. @dend * ---------------------------------------------------- */ RMenum rmPipeSetContext (RMpipe *pipe, const GLXContext context) { if (RM_ASSERT(pipe, "rmPipeSetContext [X11 version] error - the input RMpipe is NULL") == RM_WHACKED) return(RM_WHACKED); pipe->glxcontext = context; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPipeGetContext @pstart GLXContext rmPipeGetContext (const RMpipe *toQuery) @pend @astart RMpipe *toQuery - a handle to an RMpipe object (input). @aend @dstart Returns the current GLXContext associated with an RMpipe object upon success. A return value of zero is returned if there is a problem. Note that the GLXContext returned by this routine is not necessarily "active" unless this call is made after the RMpipe is "made current" by using rmPipeMakeCurrent. @dend * ---------------------------------------------------- */ GLXContext rmPipeGetContext (const RMpipe *pipe) { if (RM_ASSERT(pipe, "rmPipeGetContext (X11 version) error - the input RMpipe is NULL") == RM_WHACKED) return((GLXContext)0); return(pipe->glxcontext); } /* * ---------------------------------------------------- * @Name rmPipeSetWindow (X11) @pstart RMenum rmPipeSetWindow (RMpipe *toUse, Window theWindow, int windowWidth, int windowHeight) @pend @astart RMpipe *toUse - a handle to an RMpipe object (input, but not const). Window w - a valid X window handle (input). int windowWidth, int windowHeight - integer values specifying the pixel width & height of the window "w". @aend @dstart Use this routine to "bind" an X11 Window to an RMpipe. When this routine is called, the RMpipe's window attribute is set to the value specified by theWindow parameter, and the RMpipe's window pixel dimension attributes are set. Note that there are no event callbacks associated with the RMpipe: when the window geometry changes (size, etc) it is the responsibility of the application to inform RM that the window geometry has changed (rmPipeSetWindowSize). There are separate versions of this routine for Win32 and X. To assign an offscreen rendering area to the RMpipe, use the routine rmPipeSetOffscreenWindow() rather than rmPipeSetWindow(). @dend * ---------------------------------------------------- */ RMenum rmPipeSetWindow (RMpipe *pipe, Window w, int width, int height) { if (RM_ASSERT(pipe, "rmPipeSetWindow [X11 version] error: the input RMpipe is NULL") == RM_WHACKED) return(RM_WHACKED); pipe->xdrawable = w; rmPipeSetWindowSize(pipe, width, height); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPipeSetOffscreenWindow (X11) @pstart int rmPipeSetOffscreenWindow (RMpipe *toUse, GLXPixmap glxp, int windowWidth, int windowHeight) @pend @astart RMpipe *toUse - a handle to an RMpipe object (input, but not const). GLXPixmap - a valid GLXPixmap handle (input). int windowWidth, int windowHeight - integer values specifying the pixel width & height of the window "w". @aend @dstart Use this routine to "bind" an offscreen X11 rendering area, a GLXPixmap, to an RMpipe. When this routine is called, a number of things happen: 1. The RMpipe's notion of the window size is set (rmPipeSetWindowSize). 2. The GLXContext contained within the RMpipe is made current. 3. Final internal initialization within RM on the RMpipe's GLXContext is performed, readying both RM and OpenGL for use. After this call succeeds, on X11 systems is is safe to begin making raw OpenGL calls. Note that things work a bit differently in Win32. See rmauxSetInitFunc(). Returns RM_CHILL upon success, or RM_WHACKED upon failure. This routine should be used by all applications to activate an OpenGL context and to bind an offscreen rendering areaw to the RMpipe. Note that there are no event callbacks associated with the RMpipe: when the window geometry changes (size, etc) it is the responsibility of the application to inform RM that the window geometry has changed (rmPipeSetWindowSize). There are separate versions of this routine for Win32 and X. To bind a displayable window to an RMpipe, use rmPipeSetWindow(). @dend * ---------------------------------------------------- */ RMenum rmPipeSetOffscreenWindow (RMpipe *pipe, GLXPixmap glxp, int width, int height) { if (RM_ASSERT(pipe, "rmPipeSetWindow() error: the input RMpipe is NULL") == RM_WHACKED) return(RM_WHACKED); pipe->xdrawable = glxp; rmPipeSetWindowSize(pipe, width, height); pipe->xwindow_width = width; pipe->xwindow_height = height; pipe->offscreen = RM_TRUE; return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmPipeGetWindow @pstart Window rmPipeGetWindow (const RMpipe *toQuery) @pend @astart const RMpipe *toQuery - a handle to an RMpipe object (input). @aend @dstart Returns the window handle associated with an RMpipe object, or zero upon failure. Note there are separate versions of this routine for Win32 and X11. @dend * ---------------------------------------------------- */ Window rmPipeGetWindow (const RMpipe *pipe) { if (RM_ASSERT(pipe, "rmPipeGetWindow() error: the input RMpipe object is NULL") == RM_WHACKED) return((Window)NULL); return((Window)(pipe->xdrawable)); } /* * ---------------------------------------------------- * @Name rmPipeSwap1BuffersX11 @pstart RMenum rmPipeSwapBuffersX11 (RMpipe *p) @pend @astart RMpipe *p - a handle to an RMpipe (input). @aend @dstart @dend * ---------------------------------------------------- */ RMenum rmPipeSwapBuffersX11 (const RMpipe *p) { glXSwapBuffers(rmxPipeGetDisplay(p), rmPipeGetWindow(p)); return RM_CHILL; } /* * ---------------------------------------------------- * @Name rmxPipeCreateContext @pstart RMenum rmxPipeCreateContext (RMpipe *toModify) @pend @astart RMpipe *toModify - a handle to an RMpipe (input). @aend @dstart This routine will create a GLX OpenGL rendering context that matches the channel characteristics set in the RMpipe toModify. If successful, this routine returns RM_CHILL, and sets the RMpipe's context variable, along with the RMpipe's XVisual structure. If unsucessful, RM_WHACKED is returned, and no modifications to the RMpipe will occur. Failure can occur if (1) there is no GLX extension on the X Server; (2) the OpenGL implementation does not support the desired channel characteristics (e.g., if RM_MBUF_STEREO_CHANNEL is requested, but there is no stereo visual available). This routine is invoked only from within rmauxCreateXWindow(). Applications that want to create their own windows will need to call this routine prior to creating windows in X, and then use rmxPipeGetVisual() to obtain the appropriate XVisual structure to use when creating a window. @dend * ---------------------------------------------------- */ RMenum private_rmxPipeCreateContext (RMpipe *pipe) { Display *display; XVisualInfo *visual; #if 0 /* 1/25/03 - not really sure if this shared colormap stuff is really needed anymore. */ Colormap cmap; #endif GLXContext context; if ((display = rmxPipeGetDisplay(pipe)) == NULL) { rmError("rmxPipeCreateContext() - the RMpipe xdisplay variable is not set, so I can't create an OpenGL context. Please assign a Display using rmxPipeSetDisplay. "); return RM_WHACKED; } if (rmxPipeGetVisual(pipe) == NULL) visual = private_rmxCreateVisual(pipe); if (visual == NULL) { return RM_WHACKED; } /* 1/25/03 - not really sure if this shared colormap stuff is really needed anymore. */ #if 0 if (visual->class == PseudoColor) cmap = rmxGetSharableColormap(local_display, visual); else cmap = XCreateColormap(local_display, RootWindow(local_display, DefaultScreen(local_display)), visual->visual, AllocNone); #endif /* don't create a direct rendering context for offscreen formats! */ if (private_rmPipeIsOffscreenFormat(pipe)) context = NULL; else context = glXCreateContext(display, visual, NULL, True); if (context == NULL) { /* couldn't (or wouldn't) create a direct rendering context. try to create an indirect rendering context */ context = glXCreateContext(display, visual, NULL, False); if (context == NULL) /* we're hosed..there's no open gl here. */ return(RM_WHACKED); } /* ok, load everything up into the pipe structure now */ #if 0 rmxPipeSetColormap(pipe, cmap); #endif rmPipeSetContext(pipe, context); return(RM_CHILL); } /* PRIVATE */ void private_rmPipeCloseContextX11(RMpipe *toClose) { RMenum haveDisplay, haveContext, haveWindow; haveDisplay = rmxPipeGetDisplay(toClose) == NULL ? RM_FALSE : RM_TRUE; haveContext = rmPipeGetContext(toClose) == NULL ? RM_FALSE: RM_TRUE; haveWindow = rmPipeGetWindow(toClose) == 0 ? RM_FALSE : RM_TRUE; if (haveContext == RM_TRUE) { glXMakeCurrent(rmxPipeGetDisplay(toClose), None, NULL); glXDestroyContext(rmxPipeGetDisplay(toClose), rmPipeGetContext(toClose)); } if ((haveDisplay == RM_TRUE) && (haveWindow == RM_TRUE)) { if (private_rmPipeIsOffscreenFormat(toClose) != RM_TRUE) XDestroyWindow(rmxPipeGetDisplay(toClose), rmPipeGetWindow(toClose)); #if 0 /* else - an offscreen format. We can't use XDestroyWindow on an offscreen drawable. As of 5/2005, the offscreen drawable is a GLXPixmap. Unfortunately, the GLX API provides only glXCreateGLXPixmap to create them - there's no API routine to destroy them!!! We can't call XFreePixmap because the drawable isn't an XPixmap. For now, we just incur a big memory leak here. Hopefully applications won't be creating and destroying RMpipe's repeatedly where an offscreen format is requested, otherwise there will be a big memory leak. */ XFreePixmap(rmxPipeGetDisplay(toClose), rmPipeGetWindow(toClose)); #endif rmPipeSetWindow(toClose, 0, 0, 0); /* "zero out" window */ } if (haveDisplay == RM_TRUE) { XCloseDisplay(rmxPipeGetDisplay(toClose)); toClose->xdisplay = NULL; } } XVisualInfo * private_rmxCreateVisual(RMpipe *p) { RMenum cf; char *cfString; int *attribs=NULL; XVisualInfo *v=NULL; Display *d = rmxPipeGetDisplay(p); if (d == NULL) { rmError("private_rmxCreateVisual() - the input RMpipe does not have an open XDisplay. Please assign one using rmxPipeSetDisplay()."); return NULL; } cf = rmPipeGetChannelFormat(p); if (cf == RM_MBUF_STEREO_CHANNEL) { int indx = sizeof(double_buffer_rgba) / sizeof(int); cfString = strdup("RM_MBUF_STEREO_CHANNEL"); attribs = (int *)malloc(sizeof(int)*indx); memcpy((void *)attribs, (void *)double_buffer_rgba, sizeof(int)*indx); attribs[indx - 2] = GLX_STEREO; } else if ((cf == RM_OFFSCREEN_MONO_CHANNEL) || (cf == RM_OFFSCREEN_REDBLUE_STEREO_CHANNEL) || (cf == RM_OFFSCREEN_BLUERED_STEREO_CHANNEL)) { int indx = sizeof(single_buffer_rgba) / sizeof(int); cfString = strdup("RM_OFFSCREEN_STEREO_CHANNEL, RM_OFFSCREEN_REDBLUE_STEREO_CHANNEL, or RM_OFFSCREEN_BLUERED_STEREO_CHANNEL"); attribs = (int *)malloc(sizeof(int)*indx); memcpy((void *)attribs, (void *)single_buffer_rgba, sizeof(int)*indx); } else { int indx = sizeof(double_buffer_rgba) / sizeof(int); cfString = strdup("RM_MONO_CHANNEL"); attribs = (int *)malloc(sizeof(int)*indx); memcpy((void *)attribs, (void *)double_buffer_rgba, sizeof(int)*indx); attribs[indx-2] = None; } v = glXChooseVisual(d, DefaultScreen(d), attribs); free((void *)attribs); if (v == NULL) { char buf[2048]; sprintf(buf, "private_rmxCreateVisual: can't get the right visual type for the channel format specified in the RMpipe, which is %s. \n", cfString); rmWarning(buf); } else rmxPipeSetVisual(p, v); if (cfString != NULL) free((void *)cfString); return v; } #endif /* RM_X */ /* EOF */