Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreGLXConfig.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006  
00007 Copyright © 2000-2004 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009  
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014  
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018  
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreGLXConfig.h"
00026 #include "OgreException.h"
00027 #include "OgreImage.h"
00028 #include "OgreLogManager.h"
00029 
00030 #include <cstdlib>
00031 #include <iostream>
00032 
00033 #include <string>
00034 
00035 #include <X11/X.h>
00036 #include <X11/Xutil.h>
00037 #include <X11/Xlib.h>
00038 #include <X11/keysym.h>
00039 #include <X11/extensions/xf86vmode.h>
00040 
00041 #include <X11/Intrinsic.h> 
00042 #include <X11/StringDefs.h> 
00043 #include <X11/Xaw/Command.h> 
00044 #include <X11/Xaw/Form.h> 
00045 #include <X11/Xaw/Box.h>
00046 #include <X11/Shell.h>
00047 #include <X11/Xaw/Toggle.h>
00048 #include <X11/Xaw/MenuButton.h>
00049 #include <X11/Xaw/SimpleMenu.h>
00050 #include <X11/Xaw/SmeBSB.h>
00051 
00052 #include <list>
00053 namespace Ogre {
00054 
00064 class GLXConfigurator {
00065     /* GUI constants */
00066     static const int wWidth = 400;      // Width of window
00067     static const int wHeight = 300;     // Height of window
00068     static const int col1x = 20;        // Starting x of column 1 (labels)
00069     static const int col2x = 180;       // Starting x of column 2 (options)
00070     static const int col1w = 150;       // Width of column 1 (labels)
00071     static const int col2w = 200;       // Width of column 2 (options)
00072     static const int ystart = 105;      // Starting y of option table rows
00073     static const int rowh = 20;     // Height of one row in the option table
00074     static const std::string GLXConfigurator::backdrop; // Background image, defined below
00075 
00076 public:
00077     GLXConfigurator();
00078     ~GLXConfigurator();
00079 
00080     bool CreateWindow();
00081     void Main();
00085     void Exit();
00086 protected:
00087     Display *mDisplay;
00088     Window mWindow;
00089     Pixmap mBackDrop;
00090 
00091     int mWidth, mHeight;
00092     // Xt
00093     XtAppContext appContext; 
00094     Widget toplevel;
00095 
00099     virtual Pixmap CreateBackdrop(Window rootWindow, int depth);
00103     virtual bool Init();
00107     virtual void Draw();
00108 public:
00109     /* Local */
00110     bool accept;
00111     /* Class that binds a callback to a RenderSystem */
00112     class RendererCallbackData {
00113     public:
00114         RendererCallbackData(GLXConfigurator *parent, RenderSystem *renderer, Widget optionmenu):
00115             parent(parent),
00116             renderer(renderer),
00117             optionmenu(optionmenu) {
00118         }
00119         GLXConfigurator *parent;
00120         RenderSystem *renderer;
00121         Widget optionmenu;
00122     };
00123     std::list<RendererCallbackData> mRendererCallbackData;
00124 
00125     RenderSystem *mRenderer;
00126     Widget box;                 // Box'o control widgets
00127     std::list<Widget> mRenderOptionWidgets; // List of RenderSystem specific
00128                         // widgets for visibility management (cleared when another rendersystem is selected)
00129     /* Class that binds a callback to a certain configuration option/value */
00130     class ConfigCallbackData {
00131     public:
00132         ConfigCallbackData(GLXConfigurator *parent, const std::string &optionName, const std::string &valueName, Widget optionmenu):
00133             parent(parent),
00134             optionName(optionName),
00135             valueName(valueName),
00136             optionmenu(optionmenu) {
00137         }
00138         GLXConfigurator *parent;
00139         std::string optionName, valueName;
00140         Widget optionmenu;
00141     };
00142     std::list<ConfigCallbackData> mConfigCallbackData;
00143 
00144     void SetRenderSystem(RenderSystem *sys) {
00145         mRenderer = sys;
00146     }
00147 private:
00148     /* Callbacks that terminate modal dialog loop */ 
00149     static void acceptHandler(Widget w, GLXConfigurator *obj, XtPointer callData) {
00150         // Check if a renderer was selected, if not, don't accept
00151         if(!obj->mRenderer)
00152             return;
00153         obj->accept = true;
00154         obj->Exit();
00155     } 
00156     static void cancelHandler(Widget w, GLXConfigurator *obj, XtPointer callData) { 
00157         obj->Exit();
00158     }
00159     /* Callbacks that set a setting */
00160     static void renderSystemHandler(Widget w, RendererCallbackData *cdata, XtPointer callData) {
00161         // Set selected renderer its name
00162         XtVaSetValues(cdata->optionmenu, XtNlabel, cdata->renderer->getName().c_str(), 0, NULL);
00163         // Notify Configurator (and Ogre)
00164         cdata->parent->SetRenderer(cdata->renderer);
00165     }
00166     static void configOptionHandler(Widget w, ConfigCallbackData *cdata, XtPointer callData) {
00167         // Set selected renderer its name
00168         XtVaSetValues(cdata->optionmenu, XtNlabel, cdata->valueName.c_str(), 0, NULL);
00169         // Notify Configurator (and Ogre)
00170         cdata->parent->SetConfigOption(cdata->optionName, cdata->valueName);
00171     }
00172 
00173     /* Functions reacting to GUI */
00174     void SetRenderer(RenderSystem *);
00175     void SetConfigOption(const std::string &optionName, const std::string &valueName);
00176 };
00177 /* 
00178  * Backdrop image. This must be sized mWidth by mHeight, and produce a
00179  * RGB pixel format when loaded with Image::load .
00180  */
00181 const std::string GLXConfigurator::backdrop = "GLX_backdrop.png";
00182 
00183 GLXConfigurator::GLXConfigurator():
00184     mDisplay(0), mWindow(0), mBackDrop(0),
00185     mWidth(wWidth), mHeight(wHeight),
00186     appContext(0), toplevel(0),
00187 
00188     accept(false),
00189     mRenderer(0) {
00190 }
00191 GLXConfigurator::~GLXConfigurator() {
00192     if(mBackDrop)
00193         XFreePixmap(mDisplay, mBackDrop);
00194     if(toplevel) {
00195         XtUnrealizeWidget(toplevel);
00196         XtDestroyWidget(toplevel);
00197     }
00198     if(mDisplay) {
00199         XCloseDisplay(mDisplay);
00200     }
00201 }
00202 
00203 bool GLXConfigurator::CreateWindow() {
00204 
00205 
00206     char *bla[] = {"Rendering Settings", "-bg", "black", "-fg", "green","-bd","darkgreen"};
00207     int argc = sizeof(bla)/sizeof(*bla);
00208 
00209     toplevel = XtVaOpenApplication(&appContext, "OGRE", NULL, 0, &argc, bla, NULL,sessionShellWidgetClass,
00210         XtNwidth, mWidth,
00211         XtNheight, mHeight,
00212         XtNminWidth, mWidth,
00213         XtNmaxWidth, mWidth,
00214         XtNminHeight, mHeight,
00215         XtNmaxHeight, mHeight,
00216         XtNallowShellResize, False,
00217         XtNborderWidth, 0,
00218         XtNoverrideRedirect, True,
00219         NULL, NULL); 
00220         
00221     /* Find out display and screen used */
00222     mDisplay = XtDisplay(toplevel);
00223     int screen = DefaultScreen(mDisplay);
00224     Window rootWindow = RootWindow(mDisplay,screen);
00225 
00226     /* Move to center of display */
00227     int w = DisplayWidth(mDisplay, screen); 
00228     int h = DisplayHeight(mDisplay, screen); 
00229     XtVaSetValues(toplevel, 
00230             XtNx, w/2-mWidth/2, 
00231             XtNy, h/2-mHeight/2, 0, NULL);
00232 
00233     /* Backdrop stuff */
00234     mBackDrop = CreateBackdrop(rootWindow, DefaultDepth(mDisplay,screen));
00235     
00236     /* Create toplevel */
00237     box = XtVaCreateManagedWidget("box",formWidgetClass,toplevel, 
00238         XtNbackgroundPixmap, mBackDrop,
00239         0,NULL);
00240 
00241     /* Create renderer selection */
00242     int cury = ystart + 0*rowh;
00243 
00244     Widget lb1 = XtVaCreateManagedWidget("topLabel", labelWidgetClass, box, XtNlabel, "Select Renderer", XtNborderWidth, 0, 
00245         XtNwidth, col1w,    // Fixed width
00246         XtNheight, 18,
00247         XtNleft, XawChainLeft,
00248         XtNtop, XawChainTop,
00249         XtNright, XawChainLeft,
00250         XtNbottom, XawChainTop,
00251         XtNhorizDistance, col1x,
00252         XtNvertDistance, cury,
00253         XtNjustify, XtJustifyLeft,
00254         NULL);
00255     const char *curRenderName = " Select One "; // Name of current renderer, or hint to select one
00256     if(mRenderer)
00257         curRenderName = mRenderer->getName().c_str();
00258     Widget mb1 = XtVaCreateManagedWidget("Menu", menuButtonWidgetClass, box, XtNlabel,curRenderName, 
00259         XtNresize, false,
00260         XtNresizable, false,
00261         XtNwidth, col2w,    // Fixed width
00262         XtNheight, 18,
00263         XtNleft, XawChainLeft,
00264         XtNtop, XawChainTop,
00265         XtNright, XawChainLeft,
00266         XtNbottom, XawChainTop,
00267         XtNhorizDistance, col2x,
00268         XtNvertDistance, cury,
00269         NULL);
00270 
00271     Widget menu = XtVaCreatePopupShell("menu", simpleMenuWidgetClass, mb1, 
00272         0, NULL);
00273 
00274     RenderSystemList* renderers = Root::getSingleton().getAvailableRenderers();
00275     for (RenderSystemList::iterator pRend = renderers->begin();
00276                     pRend != renderers->end(); pRend++) {
00277         // Create callback data
00278         mRendererCallbackData.push_back(RendererCallbackData(this, *pRend, mb1));
00279 
00280         Widget entry = XtVaCreateManagedWidget("menuentry", smeBSBObjectClass, menu,
00281             XtNlabel, (*pRend)->getName().c_str(),
00282             0, NULL);
00283         XtAddCallback(entry, XtNcallback, (XtCallbackProc)&GLXConfigurator::renderSystemHandler, &mRendererCallbackData.back());
00284     }
00285 
00286     Widget bottomPanel = XtVaCreateManagedWidget("bottomPanel", formWidgetClass, box, 
00287         XtNsensitive, True, 
00288         XtNborderWidth, 0, 
00289         XtNwidth, 150,  // Fixed width
00290         XtNleft, XawChainLeft,
00291         XtNtop, XawChainTop,
00292         XtNright, XawChainLeft,
00293         XtNbottom, XawChainTop,
00294         XtNhorizDistance, mWidth - 160,
00295         XtNvertDistance, mHeight - 40,
00296         NULL); 
00297 
00298     Widget helloButton = XtVaCreateManagedWidget("cancelButton", commandWidgetClass, bottomPanel, XtNlabel," Cancel ", NULL); 
00299     XtAddCallback(helloButton, XtNcallback, (XtCallbackProc)&GLXConfigurator::cancelHandler, this); 
00300 
00301     Widget exitButton = XtVaCreateManagedWidget("acceptButton", commandWidgetClass, bottomPanel, XtNlabel," Accept ", XtNfromHoriz,helloButton, NULL);
00302     XtAddCallback(exitButton, XtNcallback, (XtCallbackProc)&GLXConfigurator::acceptHandler, this); 
00303 
00304     XtRealizeWidget(toplevel); 
00305 
00306     if(mRenderer)
00307         /* There was already a renderer selected; display its options */
00308         SetRenderer(mRenderer);
00309 
00310     return true;
00311 }
00312 
00313 Pixmap GLXConfigurator::CreateBackdrop(Window rootWindow, int depth) {
00314     int bpl;
00315     /* Find out number of bytes per pixel */
00316     switch(depth) {
00317     default:
00318         LogManager::getSingleton().logMessage("GLX backdrop: Undsupported bit depth");
00319         /* Unsupported bit depth */
00320         return 0;
00321     case 15:
00322     case 16:
00323         bpl = 2; break;
00324     case 24:
00325     case 32:
00326         bpl = 4; break;
00327     }
00328     /* Create background pixmap */
00329     unsigned char *data = 0; // Must be allocated with malloc
00330 
00331     try {
00332         Image img;
00333         /* Load backdrop image using OGRE */
00334         img.load(backdrop);
00335         if(img.getWidth() != mWidth || img.getHeight() != mHeight ||
00336             img.getFormat() != PF_R8G8B8) {
00337             // Invalid image format or size
00338             LogManager::getSingleton().logMessage("GLX backdrop: Invalid image "+backdrop+", format must be R8G8B8");
00339             return 0;
00340         }
00341         // Convert and copy image
00342         unsigned char *imgdata = (unsigned char*)img.getData();
00343         
00344 
00345         data = (unsigned char*)malloc(mWidth * mHeight * bpl); // Must be allocated with malloc
00346         int sptr = 0, dptr = 0;
00347 
00348         switch(depth) {
00349         case 16:
00350             for(int y=0; y<mHeight; y++) {
00351                 for(int x=0; x<mWidth; x++) {
00352                     // 5/6/5
00353                     data[dptr + 0] = (imgdata[sptr + 0] & 0xF8) |
00354                              (imgdata[sptr + 1] >> 5);
00355                     data[dptr + 1] = ((imgdata[sptr + 1] << 3) & 0xE0) | 
00356                              (imgdata[sptr + 2] >> 3);
00357                     sptr += 3; dptr += 2;
00358                 }
00359             }
00360             break;
00361         case 24:
00362         case 32:
00363             for(int y=0; y<mHeight; y++) {
00364                 for(int x=0; x<mWidth; x++) {
00365                     data[dptr + 0] = 0;
00366                     data[dptr + 1] = imgdata[sptr + 0];
00367                     data[dptr + 2] = imgdata[sptr + 1];
00368                     data[dptr + 3] = imgdata[sptr + 2];
00369                 
00370                     sptr += 3;dptr += 4;
00371                 }
00372             }
00373             break;
00374         }
00375     } catch(Exception &e) {
00376         // Could not find image; never mind
00377         LogManager::getSingleton().logMessage("GLX backdrop image not found: Warning");
00378         return 0;
00379     }
00380     
00381     GC context = XCreateGC (mDisplay, rootWindow, 0, NULL);
00382 
00383     /* put my pixmap data into the client side X image data structure */
00384     XImage *image = XCreateImage (mDisplay, NULL, depth, ZPixmap, 0, 
00385         (char*)data,
00386         mWidth, mHeight, 8,
00387         mWidth*bpl);
00388     image->byte_order = MSBFirst;
00389 
00390     /* tell server to start managing my pixmap */
00391     Pixmap rv = XCreatePixmap(mDisplay, rootWindow, mWidth,
00392         mHeight, depth);
00393 
00394     /* copy from client to server */
00395     XPutImage(mDisplay, rv, context, image, 0, 0, 0, 0,
00396         mWidth, mHeight);
00397 
00398     /* free up the client side pixmap data area */
00399     XDestroyImage(image); // also cleans data
00400     XFreeGC(mDisplay, context);
00401 
00402     return rv;
00403 }
00404 bool GLXConfigurator::Init() {
00405     // Init misc resources
00406     return true;
00407 }
00408 void GLXConfigurator::Draw() {
00409 }
00410 void GLXConfigurator::Main() {
00411     XtAppMainLoop(appContext);
00412 }
00413 void GLXConfigurator::Exit() {
00414     XtAppSetExitFlag(appContext);
00415 }
00416 
00417 void GLXConfigurator::SetRenderer(RenderSystem *r) {
00418     mRenderer = r;
00419 
00420     // Destroy each widget of GUI of previously selected renderer
00421     for(std::list<Widget>::iterator i=mRenderOptionWidgets.begin(); i!=mRenderOptionWidgets.end(); i++)
00422         XtDestroyWidget(*i);
00423     mRenderOptionWidgets.clear();
00424     mConfigCallbackData.back();
00425 
00426     // Create option GUI
00427     int cury = ystart + 1*rowh + 10;
00428 
00429     ConfigOptionMap options = mRenderer->getConfigOptions();
00430     // Process each option and create an optionmenu widget for it
00431     for (ConfigOptionMap::iterator it = options.begin();
00432                     it != options.end(); it++) {
00433         Widget lb1 = XtVaCreateManagedWidget("topLabel", labelWidgetClass, box, XtNlabel, it->second.name.c_str(), XtNborderWidth, 0, 
00434             XtNwidth, col1w,    // Fixed width
00435             XtNheight, 18,
00436             XtNleft, XawChainLeft,
00437             XtNtop, XawChainTop,
00438             XtNright, XawChainLeft,
00439             XtNbottom, XawChainTop,
00440             XtNhorizDistance, col1x,
00441             XtNvertDistance, cury,
00442             XtNjustify, XtJustifyLeft,
00443             NULL);
00444         mRenderOptionWidgets.push_back(lb1);
00445         Widget mb1 = XtVaCreateManagedWidget("Menu", menuButtonWidgetClass, box, XtNlabel, it->second.currentValue.c_str(), 
00446             XtNresize, false,
00447             XtNresizable, false,
00448             XtNwidth, col2w,    // Fixed width
00449             XtNheight, 18,
00450             XtNleft, XawChainLeft,
00451             XtNtop, XawChainTop,
00452             XtNright, XawChainLeft,
00453             XtNbottom, XawChainTop,
00454             XtNhorizDistance, col2x,
00455             XtNvertDistance, cury,
00456             NULL);
00457         mRenderOptionWidgets.push_back(mb1);
00458 
00459         Widget menu = XtVaCreatePopupShell("menu", simpleMenuWidgetClass, mb1, 
00460             0, NULL);
00461 
00462         // Process each choice
00463         StringVector::iterator opt_it;
00464         for (opt_it = it->second.possibleValues.begin();
00465                         opt_it != it->second.possibleValues.end(); opt_it++) {
00466             // Create callback data
00467             mConfigCallbackData.push_back(ConfigCallbackData(this, it->second.name, *opt_it, mb1));
00468 
00469             Widget entry = XtVaCreateManagedWidget("menuentry", smeBSBObjectClass, menu,
00470                 XtNlabel, (*opt_it).c_str(),
00471                 0, NULL);
00472             XtAddCallback(entry, XtNcallback, (XtCallbackProc)&GLXConfigurator::configOptionHandler, &mConfigCallbackData.back());
00473         }
00474         cury += rowh;
00475     }
00476 }
00477 
00478 void GLXConfigurator::SetConfigOption(const std::string &optionName, const std::string &valueName) {
00479     if(!mRenderer)
00480         // No renderer set -- how can this be called?
00481         return;
00482     mRenderer->setConfigOption(optionName, valueName);
00483 }
00484 
00485 bool GLXConfig::display(void) {
00486     GLXConfigurator test;
00487     /* Should this be called here? */
00488     Root::getSingleton().restoreConfig();
00489     /* Select previously selected rendersystem */
00490     if(Root::getSingleton().getRenderSystem())
00491         test.SetRenderSystem(Root::getSingleton().getRenderSystem());
00492     /* Attempt to create the window */
00493     if(!test.CreateWindow()) {
00494         Except(Exception::ERR_INTERNAL_ERROR,
00495                "Could not create configuration dialog",
00496                "GLXConfig::display");
00497     }
00498     /* Modal loop */
00499     test.Main();
00500     if(!test.accept) {
00501         /* User did not accept */
00502         return false;
00503     }
00504 
00505     /* All done */
00506     Root::getSingleton().setRenderSystem(test.mRenderer);
00507     Root::getSingleton().saveConfig();
00508 
00509     return true;
00510 }
00511 
00512 };
00513 

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:27 2004