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