| /* |
| |
| BOILERPLATE |
| |
| To get started with mixed model programming with Motif and OpenGL, this |
| boilerplate `application' might help get you started. |
| |
| This program honors two environment variables: |
| |
| SETVISUAL <id> Makes the application use the indicated visual, |
| instead of the one chosen by glxChooseVisual. |
| |
| SAMEVISUAL Make the application use the same visual for the |
| GUI as for the 3D GL Widget. |
| |
| The basic idea is to minimize colormap `flash' on systems with only one |
| hardware colormap, especially when focus shifts between several |
| of the application's windows, e.g. the about box. |
| |
| If you have suggestions for improvements, please mail to: |
| |
| |
| Jeroen van der Zijp <jvz@cyberia.cfdrc.com> |
| |
| |
| Feel free to turn this into a useful program!! |
| |
| */ |
| |
| |
| /* |
| |
| This code is hereby placed under GNU GENERAL PUBLIC LICENSE. |
| Copyright (C) 1996 Jeroen van der Zijp <jvz@cyberia.cfdrc.com> |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program 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 General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| |
| /* Include the kitchen sink */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <X11/Intrinsic.h> |
| #include <X11/StringDefs.h> |
| #include <X11/cursorfont.h> |
| #include <X11/keysym.h> |
| #include <Xm/Xm.h> |
| #include <Xm/MainW.h> |
| #include <Xm/RowColumn.h> |
| #include <Xm/PushB.h> |
| #include <Xm/CascadeB.h> |
| #include <Xm/BulletinB.h> |
| #include <Xm/DialogS.h> |
| #include <Xm/Frame.h> |
| #include <Xm/MessageB.h> |
| #include <Xm/Form.h> |
| #include <Xm/Separator.h> |
| #include <Xm/MwmUtil.h> |
| |
| /* Now some good stuff */ |
| #include <GLwMDrawA.h> |
| #include <GL/gl.h> |
| #include <GL/glu.h> |
| #include <GL/glx.h> |
| |
| |
| /* Stuff */ |
| Display *display; |
| Visual *gui_visual; |
| Colormap gui_colormap; |
| Colormap gl_colormap; |
| XVisualInfo *gl_visualinfo; |
| XtAppContext app_context; |
| Widget toplevel; |
| Widget mainwindow; |
| Widget menubar; |
| Widget mainform; |
| Widget mainframe; |
| Widget glwidget; |
| Widget button; |
| Widget separator; |
| GLXContext glx_context; |
| |
| #ifndef __cplusplus |
| #define c_class class |
| #endif |
| |
| /* Requested attributes; fix as you see fit */ |
| static int glxConfig[]={ |
| GLX_RGBA, |
| GLX_DOUBLEBUFFER, |
| GLX_DEPTH_SIZE, 16, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| None |
| }; |
| |
| |
| /* Forwards */ |
| static void exposeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs); |
| static void initCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs); |
| static void resizeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs); |
| static void inputCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs); |
| static void byeCB(Widget w,XtPointer client_data,XtPointer call_data); |
| static void aboutCB(Widget w,XtPointer client_data,XtPointer call_data); |
| static char* showvisualclass(int cls); |
| |
| |
| |
| /* Sample application */ |
| int main(int argc, char *argv[]){ |
| char *thevisual; |
| XVisualInfo vi; |
| int nvisinfos,visid,n; |
| Arg args[30]; |
| Widget pane,cascade,but; |
| |
| /* |
| ** Initialize toolkit |
| ** We do *not* use XtAppInitialize as we want to figure visual and |
| ** colormap BEFORE we create the top level shell!!! |
| */ |
| XtToolkitInitialize(); |
| |
| /* Make application context */ |
| app_context=XtCreateApplicationContext(); |
| |
| /* Try open display */ |
| display=XtOpenDisplay(app_context,NULL,"boilerPlate","BoilerPlate",NULL,0,&argc,argv); |
| |
| /* Report failure */ |
| if(!display){ |
| fprintf(stderr,"Unable to open the specified display.\n"); |
| fprintf(stderr,"Set your `DISPLAY' environment variable properly or\n"); |
| fprintf(stderr,"use the `xhost' command to authorize access to the display.\n"); |
| exit(1); |
| } |
| |
| /* Check for extension; for Mesa, this is always cool */ |
| if(!glXQueryExtension(display,NULL,NULL)){ |
| fprintf(stderr,"The specified display does not support the OpenGL extension\n"); |
| exit(1); |
| } |
| |
| /* Init with default visual and colormap */ |
| gui_visual=DefaultVisual(display,0); |
| gui_colormap=DefaultColormap(display,0); |
| gl_colormap=DefaultColormap(display,0); |
| |
| /* User insists on a specific visual */ |
| if((thevisual=getenv("SETVISUAL"))!=NULL){ |
| if(sscanf(thevisual,"%x",&visid)==1){ |
| vi.visualid=visid; |
| gl_visualinfo=XGetVisualInfo(display,VisualIDMask,&vi,&nvisinfos); |
| } |
| else{ |
| fprintf(stderr,"Please set the `SETVISUAL' variable in hexadecimal\n"); |
| fprintf(stderr,"Use one of the Visual ID's reported by `xdpyinfo'\n"); |
| exit(1); |
| } |
| } |
| |
| /* Find visual the regular way */ |
| else{ |
| gl_visualinfo=glXChooseVisual(display,DefaultScreen(display),glxConfig); |
| } |
| |
| /* Make sure we have a visual */ |
| if(!gl_visualinfo){ |
| fprintf(stderr,"Unable to obtain visual for graphics\n"); |
| exit(1); |
| } |
| |
| /* Show what visual is being used */ |
| fprintf(stderr,"Using the following visual:\n"); |
| fprintf(stderr," visualid: %lx\n",gl_visualinfo->visualid); |
| fprintf(stderr," depth: %d\n",gl_visualinfo->depth); |
| fprintf(stderr," screen: %d\n",gl_visualinfo->screen); |
| fprintf(stderr," bits/rgb: %d\n",gl_visualinfo->bits_per_rgb); |
| fprintf(stderr," class: %s\n",showvisualclass(gl_visualinfo->c_class)); |
| |
| /* |
| ** If not using default visual, we need a colormap for this visual. |
| ** Yes, the GL widget can allocate one itself, but we want to make |
| ** sure the GUI and the 3D have the same one (if hardware does not |
| ** allow more than one simultaneously). |
| ** This prevents nasty flashing when the window with the 3D widget |
| ** looses the focus. |
| */ |
| if(gl_visualinfo->visual!=DefaultVisual(display,0)){ |
| fprintf(stderr,"Making another colormap\n"); |
| gl_colormap=XCreateColormap(display, |
| RootWindow(display,0), |
| gl_visualinfo->visual, |
| AllocNone); |
| if(!gl_colormap){ |
| fprintf(stderr,"Unable to create private colormap\n"); |
| exit(1); |
| } |
| } |
| |
| /* |
| ** Use common visual for GUI and GL? |
| ** Maybe you can invoke some hardware interrogation function and |
| ** see if more than one hardware map is supported. For the purpose |
| ** of this demo, we'll use an environment variable instead. |
| */ |
| if(getenv("SAMEVISUAL")!=NULL){ |
| gui_visual=gl_visualinfo->visual; |
| gui_colormap=gl_colormap; |
| } |
| |
| fprintf(stderr,"GUI uses visual: %lx\n",XVisualIDFromVisual(gui_visual)); |
| |
| /* Create application shell, finally */ |
| n=0; |
| XtSetArg(args[n],XmNvisual,gui_visual); n++; /* Plug in that visual */ |
| XtSetArg(args[n],XmNcolormap,gui_colormap); n++; /* And that colormap */ |
| toplevel=XtAppCreateShell("boilerPlate","BoilerPlate", |
| applicationShellWidgetClass,display,args,n); |
| |
| |
| /* Main window */ |
| n=0; |
| mainwindow=XmCreateMainWindow(toplevel,"window",args,n); |
| XtManageChild(mainwindow); |
| |
| /* Make a menu */ |
| n=0; |
| XtSetArg(args[n],XmNmarginWidth,0); n++; |
| XtSetArg(args[n],XmNmarginHeight,0); n++; |
| menubar=XmCreateMenuBar(mainwindow,"menubar",args,2); |
| XtManageChild(menubar); |
| |
| n=0; |
| pane=XmCreatePulldownMenu(menubar,"pane",args,n); |
| n=0; |
| but=XmCreatePushButton(pane,"Open",args,n); |
| XtManageChild(but); |
| but=XmCreatePushButton(pane,"Save",args,n); |
| XtManageChild(but); |
| but=XmCreatePushButton(pane,"Save As",args,n); |
| XtManageChild(but); |
| but=XmCreatePushButton(pane,"Quit",args,n); |
| XtAddCallback(but,XmNactivateCallback,byeCB,(XtPointer)NULL); |
| XtManageChild(but); |
| XtSetArg(args[0],XmNsubMenuId,pane); |
| cascade=XmCreateCascadeButton(menubar,"File",args,1); |
| XtManageChild(cascade); |
| |
| n=0; |
| pane=XmCreatePulldownMenu(menubar,"pane",args,n); |
| n=0; |
| but=XmCreatePushButton(pane,"About",args,n); |
| XtAddCallback(but,XmNactivateCallback,aboutCB,(XtPointer)NULL); |
| XtManageChild(but); |
| XtSetArg(args[0],XmNsubMenuId,pane); |
| cascade=XmCreateCascadeButton(menubar,"Help",args,1); |
| XtManageChild(cascade); |
| XtVaSetValues(menubar,XmNmenuHelpWidget,cascade,NULL); |
| |
| /* Main window form */ |
| n=0; |
| XtSetArg(args[n],XmNmarginWidth,5); n++; |
| XtSetArg(args[n],XmNmarginHeight,5); n++; |
| mainform=XmCreateForm(mainwindow,"mainForm",args,n); |
| XtManageChild(mainform); |
| |
| /* Some nice button */ |
| n=0; |
| XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++; |
| XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++; |
| button=XmCreatePushButton(mainform,"Bye",args,n); |
| XtAddCallback(button,XmNactivateCallback,byeCB,(XtPointer)NULL); |
| XtManageChild(button); |
| |
| n=0; |
| XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++; |
| XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++; |
| XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++; |
| XtSetArg(args[n],XmNbottomWidget,button); n++; |
| XtSetArg(args[n],XmNshadowType,XmSHADOW_ETCHED_IN); n++; |
| separator=XmCreateSeparator(mainform,"separator",args,n); |
| XtManageChild(separator); |
| |
| /* Main window frame */ |
| n = 0; |
| XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++; |
| XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++; |
| XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++; |
| XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++; |
| XtSetArg(args[n],XmNbottomWidget,separator); n++; |
| XtSetArg(args[n],XmNshadowType,XmSHADOW_IN); n++; |
| mainframe = XmCreateFrame(mainform,"mainFrame",args,n); |
| XtManageChild(mainframe); |
| |
| /* GL drawing area */ |
| n = 0; |
| XtSetArg(args[n],XmNcolormap,gl_colormap); n++; |
| XtSetArg(args[n],GLwNvisualInfo,gl_visualinfo); n++; |
| XtSetArg(args[n],GLwNinstallColormap,True); n++; |
| XtSetArg(args[n],XmNtraversalOn,True); n++; |
| XtSetArg(args[n],XmNwidth,400); n++; |
| XtSetArg(args[n],XmNheight,300); n++; |
| glwidget = GLwCreateMDrawingArea(mainframe,"glWidget",args,n); |
| XtAddCallback(glwidget,GLwNexposeCallback,(XtCallbackProc)exposeCB,(XtPointer)NULL); |
| XtAddCallback(glwidget,GLwNresizeCallback,(XtCallbackProc)resizeCB,(XtPointer)NULL); |
| XtAddCallback(glwidget,GLwNginitCallback,(XtCallbackProc)initCB,(XtPointer)NULL); |
| XtAddCallback(glwidget,GLwNinputCallback,(XtCallbackProc)inputCB,(XtPointer)NULL); |
| XtManageChild(glwidget); |
| |
| /* Set into main window */ |
| XmMainWindowSetAreas(mainwindow,menubar,NULL,NULL,NULL,mainform); |
| XtRealizeWidget(toplevel); |
| |
| /* Loop until were done */ |
| XtAppMainLoop(app_context); |
| return 0; |
| } |
| |
| |
| /* Show visual class */ |
| static char* showvisualclass(int cls){ |
| if(cls==TrueColor) return "TrueColor"; |
| if(cls==DirectColor) return "DirectColor"; |
| if(cls==PseudoColor) return "PseudoColor"; |
| if(cls==StaticColor) return "StaticColor"; |
| if(cls==GrayScale) return "GrayScale"; |
| if(cls==StaticGray) return "StaticGray"; |
| return "Unknown"; |
| } |
| |
| |
| static void exposeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){ |
| GLwDrawingAreaMakeCurrent(glwidget,glx_context); |
| |
| glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); |
| glMatrixMode(GL_PROJECTION); |
| |
| glLoadIdentity(); |
| glOrtho(-1.0,1.0,-1.0,1.0,0.0,1.0); |
| |
| glMatrixMode(GL_MODELVIEW); |
| |
| glLoadIdentity(); |
| |
| glColor3f(1.0,0.0,0.0); |
| glBegin(GL_LINE_STRIP); |
| glVertex3f(-1.0,-1.0,0.0); |
| glVertex3f( 1.0, 1.0,0.0); |
| glEnd(); |
| glXSwapBuffers(display,XtWindow(glwidget)); |
| } |
| |
| |
| /* Initialize widget */ |
| static void initCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){ |
| |
| /* First, create context. We prefer direct rendering */ |
| glx_context=glXCreateContext(display,gl_visualinfo,0,TRUE); |
| if(!glx_context){ |
| fprintf(stderr,"Unable to create gl context\n"); |
| exit(1); |
| } |
| |
| /* Make it current */ |
| GLwDrawingAreaMakeCurrent(glwidget,glx_context); |
| |
| /* Set a viewport */ |
| glViewport(0,0,cbs->width,cbs->height); |
| |
| /* You might want to do a lot more here ... */ |
| glEnable(GL_DEPTH_TEST); |
| glDepthFunc(GL_LEQUAL); |
| glClearColor(1.0,1.0,1.0,1.0); |
| glClearDepth(1.0); |
| |
| |
| } |
| |
| |
| /* Widget changed size, so adjust txform */ |
| static void resizeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){ |
| GLwDrawingAreaMakeCurrent(glwidget,glx_context); |
| glViewport(0,0,cbs->width,cbs->height); |
| |
| /* blablabla */ |
| } |
| |
| |
| /* Boilerplate event handling */ |
| static void inputCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){ |
| switch(cbs->event->type){ |
| case ButtonPress: |
| switch(cbs->event->xbutton.button){ |
| case Button1: fprintf(stderr,"Pressed 1\n"); break; |
| case Button2: fprintf(stderr,"Pressed 2\n"); break; |
| case Button3: fprintf(stderr,"Pressed 3\n"); break; |
| } |
| break; |
| case ButtonRelease: |
| switch(cbs->event->xbutton.button){ |
| case Button1: fprintf(stderr,"Released 1\n"); break; |
| case Button2: fprintf(stderr,"Released 2\n"); break; |
| case Button3: fprintf(stderr,"Released 3\n"); break; |
| } |
| break; |
| case MotionNotify: |
| fprintf(stderr,"Moved mouse to (%d %d)\n", |
| cbs->event->xbutton.x, |
| cbs->event->xbutton.y); |
| break; |
| } |
| } |
| |
| |
| /* Hasta la vista, baby */ |
| static void byeCB(Widget w,XtPointer client_data,XtPointer call_data){ |
| exit(0); |
| } |
| |
| |
| /* Pop informative panel */ |
| static void aboutCB(Widget w,XtPointer client_data,XtPointer call_data){ |
| Arg args[10]; |
| XmString str; |
| Widget box; |
| str=XmStringCreateLtoR("Boilerplate Mixed Model Programming Example\n\n (C) 1996 Jeroen van der Zijp \n\n jvz@cyberia.cfdrc.com",XmSTRING_DEFAULT_CHARSET); |
| XtSetArg(args[0],XmNnoResize,True); |
| XtSetArg(args[1],XmNautoUnmanage,True); |
| XtSetArg(args[2],XmNmessageString,str); |
| XtSetArg(args[3],XmNdefaultPosition,False); |
| box=XmCreateInformationDialog(toplevel,"About Boilerplate",args,4); |
| XtManageChild(box); |
| XtUnmanageChild(XmMessageBoxGetChild(box,XmDIALOG_HELP_BUTTON)); |
| XtUnmanageChild(XmMessageBoxGetChild(box,XmDIALOG_CANCEL_BUTTON)); |
| XmStringFree(str); |
| } |