Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/GLX/OgreConfigDialog.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 15.8 KB
RevLine 
[1]1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreConfigDialog.h"
30#include "OgreException.h"
31#include "OgreImage.h"
32#include "OgreLogManager.h"
33#include "OgreNoMemoryMacros.h"
34
35#include <cstdlib>
36#include <iostream>
37
38#include <string>
39
40#include <X11/X.h>
41#include <X11/Xutil.h>
42#include <X11/Xlib.h>
43#include <X11/keysym.h>
44
45#include <X11/Intrinsic.h>
46#include <X11/StringDefs.h>
47#include <X11/Xaw/Command.h>
48#include <X11/Xaw/Form.h>
49#include <X11/Xaw/Box.h>
50#include <X11/Shell.h>
51#include <X11/Xaw/Toggle.h>
52#include <X11/Xaw/MenuButton.h>
53#include <X11/Xaw/SimpleMenu.h>
54#include <X11/Xaw/SmeBSB.h>
55
56#include <list>
57
58namespace {
59/**
60Backdrop image. This must be sized mWidth by mHeight, and produce a
61RGB pixel format when loaded with Image::load .
62
63You can easily generate your own backdrop with the following python script:
64
65#!/usr/bin/python
66import sys
67pngstring=open(sys.argv[2], "rb").read()
68print "char %s[%i]={%s};" % (sys.argv[1],len(pngstring), ",".join([str(ord(x)) for x in pngstring]))
69
70Call this with
71$ bintoheader.py GLX_backdrop GLX_backdrop.png > GLX_backdrop.h
72
73*/
74#include "GLX_backdrop.h"
75
76};
77
78namespace Ogre {
79
80/**
81 * Single X window with image backdrop, making it possible to configure
82 * OGRE in a graphical way.
83 * XaW uses a not-very-smart widget positioning system, so I override it to use
84 * fixed positions. This works great, but it means you need to define the various
85 * positions manually.
86 * Furthermore, it has no OptionMenu by default, so I simulate this with dropdown
87 * buttons.
88 */
89class GLXConfigurator {
90        /* GUI constants */
91        static const int wWidth = 400;          // Width of window
92        static const int wHeight = 300;         // Height of window
93        static const int col1x = 20;            // Starting x of column 1 (labels)
94        static const int col2x = 180;           // Starting x of column 2 (options)
95        static const int col1w = 150;           // Width of column 1 (labels)
96        static const int col2w = 200;           // Width of column 2 (options)
97        static const int ystart = 105;          // Starting y of option table rows
98        static const int rowh = 20;             // Height of one row in the option table
99
100public:
101        GLXConfigurator();
102        virtual ~GLXConfigurator();
103
104        bool CreateWindow();
105        void Main();
106        /**
107         * Exit from main loop.
108         */
109        void Exit();
110protected:
111        Display *mDisplay;
112        Window mWindow;
113        Pixmap mBackDrop;
114
115        int mWidth, mHeight;
116        // Xt
117        XtAppContext appContext;
118        Widget toplevel;
119
120        /**
121         * Create backdrop image, and return it as a Pixmap.
122         */
123        virtual Pixmap CreateBackdrop(Window rootWindow, int depth);
124        /**
125         * Called after window initialisation.
126         */
127        virtual bool Init();
128        /**
129         * Called initially, and on expose.
130         */
131        virtual void Draw();
132public:
133        /* Local */
134        bool accept;
135        /* Class that binds a callback to a RenderSystem */
136        class RendererCallbackData {
137        public:
138                RendererCallbackData(GLXConfigurator *parent, RenderSystem *renderer, Widget optionmenu):
139                        parent(parent),
140                        renderer(renderer),
141                        optionmenu(optionmenu) {
142                }
143                GLXConfigurator *parent;
144                RenderSystem *renderer;
145                Widget optionmenu;
146        };
147        std::list<RendererCallbackData> mRendererCallbackData;
148
149        RenderSystem *mRenderer;
150        Widget box;                             // Box'o control widgets
151        std::list<Widget> mRenderOptionWidgets; // List of RenderSystem specific
152                                                // widgets for visibility management (cleared when another rendersystem is selected)
153        /* Class that binds a callback to a certain configuration option/value */
154        class ConfigCallbackData {
155        public:
156                ConfigCallbackData(GLXConfigurator *parent, const std::string &optionName, const std::string &valueName, Widget optionmenu):
157                        parent(parent),
158                        optionName(optionName),
159                        valueName(valueName),
160                        optionmenu(optionmenu) {
161                }
162                GLXConfigurator *parent;
163                std::string optionName, valueName;
164                Widget optionmenu;
165        };
166        std::list<ConfigCallbackData> mConfigCallbackData;
167
168        void SetRenderSystem(RenderSystem *sys) {
169                mRenderer = sys;
170        }
171private:
172        /* Callbacks that terminate modal dialog loop */
173        static void acceptHandler(Widget w, GLXConfigurator *obj, XtPointer callData) {
174                // Check if a renderer was selected, if not, don't accept
175                if(!obj->mRenderer)
176                        return;
177                obj->accept = true;
178                obj->Exit();
179        }
180        static void cancelHandler(Widget w, GLXConfigurator *obj, XtPointer callData) {
181                obj->Exit();
182        }
183        /* Callbacks that set a setting */
184        static void renderSystemHandler(Widget w, RendererCallbackData *cdata, XtPointer callData) {
185                // Set selected renderer its name
186                XtVaSetValues(cdata->optionmenu, XtNlabel, cdata->renderer->getName().c_str(), 0, NULL);
187                // Notify Configurator (and Ogre)
188                cdata->parent->SetRenderer(cdata->renderer);
189        }
190        static void configOptionHandler(Widget w, ConfigCallbackData *cdata, XtPointer callData) {
191                // Set selected renderer its name
192                XtVaSetValues(cdata->optionmenu, XtNlabel, cdata->valueName.c_str(), 0, NULL);
193                // Notify Configurator (and Ogre)
194                cdata->parent->SetConfigOption(cdata->optionName, cdata->valueName);
195        }
196
197        /* Functions reacting to GUI */
198        void SetRenderer(RenderSystem *);
199        void SetConfigOption(const std::string &optionName, const std::string &valueName);
200};
201
202GLXConfigurator::GLXConfigurator():
203        mDisplay(0), mWindow(0), mBackDrop(0),
204        mWidth(wWidth), mHeight(wHeight),
205        appContext(0), toplevel(0),
206
207        accept(false),
208        mRenderer(0) {
209}
210GLXConfigurator::~GLXConfigurator() {
211        if(mBackDrop)
212                XFreePixmap(mDisplay, mBackDrop);
213        if(toplevel) {
214                XtUnrealizeWidget(toplevel);
215                XtDestroyWidget(toplevel);
216        }
217        if(mDisplay) {
218                XCloseDisplay(mDisplay);
219        }
220}
221
222bool GLXConfigurator::CreateWindow() {
223
224
225        char *bla[] = {"Rendering Settings", "-bg", "honeydew3", "-fg", "black","-bd","darkseagreen4"};
226        int argc = sizeof(bla)/sizeof(*bla);
227
228        toplevel = XtVaOpenApplication(&appContext, "OGRE", NULL, 0, &argc, bla, NULL,sessionShellWidgetClass,
229                XtNwidth, mWidth,
230                XtNheight, mHeight,
231                XtNminWidth, mWidth,
232                XtNmaxWidth, mWidth,
233                XtNminHeight, mHeight,
234                XtNmaxHeight, mHeight,
235                XtNallowShellResize, False,
236                XtNborderWidth, 0,
237                XtNoverrideRedirect, True,
238                NULL, NULL);
239
240        /* Find out display and screen used */
241        mDisplay = XtDisplay(toplevel);
242        int screen = DefaultScreen(mDisplay);
243        Window rootWindow = RootWindow(mDisplay,screen);
244
245        /* Move to center of display */
246        int w = DisplayWidth(mDisplay, screen);
247        int h = DisplayHeight(mDisplay, screen);
248        XtVaSetValues(toplevel,
249                        XtNx, w/2-mWidth/2,
250                        XtNy, h/2-mHeight/2, 0, NULL);
251
252        /* Backdrop stuff */
253        mBackDrop = CreateBackdrop(rootWindow, DefaultDepth(mDisplay,screen));
254
255        /* Create toplevel */
256        box = XtVaCreateManagedWidget("box",formWidgetClass,toplevel,
257                XtNbackgroundPixmap, mBackDrop,
258                0,NULL);
259
260        /* Create renderer selection */
261        int cury = ystart + 0*rowh;
262
263        Widget lb1 = XtVaCreateManagedWidget("topLabel", labelWidgetClass, box, XtNlabel, "Select Renderer", XtNborderWidth, 0,
264                XtNwidth, col1w,        // Fixed width
265                XtNheight, 18,
266                XtNleft, XawChainLeft,
267                XtNtop, XawChainTop,
268                XtNright, XawChainLeft,
269                XtNbottom, XawChainTop,
270                XtNhorizDistance, col1x,
271                XtNvertDistance, cury,
272                XtNjustify, XtJustifyLeft,
273                NULL);
274        const char *curRenderName = " Select One "; // Name of current renderer, or hint to select one
275        if(mRenderer)
276                curRenderName = mRenderer->getName().c_str();
277        Widget mb1 = XtVaCreateManagedWidget("Menu", menuButtonWidgetClass, box, XtNlabel,curRenderName,
278                XtNresize, false,
279                XtNresizable, false,
280                XtNwidth, col2w,        // Fixed width
281                XtNheight, 18,
282                XtNleft, XawChainLeft,
283                XtNtop, XawChainTop,
284                XtNright, XawChainLeft,
285                XtNbottom, XawChainTop,
286                XtNhorizDistance, col2x,
287                XtNvertDistance, cury,
288                NULL);
289
290        Widget menu = XtVaCreatePopupShell("menu", simpleMenuWidgetClass, mb1,
291                0, NULL);
292
293        RenderSystemList* renderers = Root::getSingleton().getAvailableRenderers();
294        for (RenderSystemList::iterator pRend = renderers->begin();
295                        pRend != renderers->end(); pRend++) {
296                // Create callback data
297                mRendererCallbackData.push_back(RendererCallbackData(this, *pRend, mb1));
298
299                Widget entry = XtVaCreateManagedWidget("menuentry", smeBSBObjectClass, menu,
300                        XtNlabel, (*pRend)->getName().c_str(),
301                        0, NULL);
302                XtAddCallback(entry, XtNcallback, (XtCallbackProc)&GLXConfigurator::renderSystemHandler, &mRendererCallbackData.back());
303        }
304
305        Widget bottomPanel = XtVaCreateManagedWidget("bottomPanel", formWidgetClass, box,
306                XtNsensitive, True,
307                XtNborderWidth, 0,
308                XtNwidth, 150,  // Fixed width
309                XtNleft, XawChainLeft,
310                XtNtop, XawChainTop,
311                XtNright, XawChainLeft,
312                XtNbottom, XawChainTop,
313                XtNhorizDistance, mWidth - 160,
314                XtNvertDistance, mHeight - 40,
315                NULL);
316
317        Widget helloButton = XtVaCreateManagedWidget("cancelButton", commandWidgetClass, bottomPanel, XtNlabel," Cancel ", NULL);
318        XtAddCallback(helloButton, XtNcallback, (XtCallbackProc)&GLXConfigurator::cancelHandler, this);
319
320        Widget exitButton = XtVaCreateManagedWidget("acceptButton", commandWidgetClass, bottomPanel, XtNlabel," Accept ", XtNfromHoriz,helloButton, NULL);
321        XtAddCallback(exitButton, XtNcallback, (XtCallbackProc)&GLXConfigurator::acceptHandler, this);
322
323        XtRealizeWidget(toplevel);
324
325        if(mRenderer)
326                /* There was already a renderer selected; display its options */
327                SetRenderer(mRenderer);
328
329        return true;
330}
331
332Pixmap GLXConfigurator::CreateBackdrop(Window rootWindow, int depth) {
333        int bpl;
334        /* Find out number of bytes per pixel */
335        switch(depth) {
336        default:
337                LogManager::getSingleton().logMessage("GLX backdrop: Undsupported bit depth");
338                /* Unsupported bit depth */
339                return 0;
340        case 15:
341        case 16:
342                bpl = 2; break;
343        case 24:
344        case 32:
345                bpl = 4; break;
346        }
347        /* Create background pixmap */
348        unsigned char *data = 0; // Must be allocated with malloc
349
350        try {
351        String imgType = "png";
352        Image img;
353        MemoryDataStream *imgStream;
354        DataStreamPtr imgStreamPtr;
355
356        // Load backdrop image using OGRE
357        imgStream = new MemoryDataStream((void*)GLX_backdrop_data, sizeof(GLX_backdrop_data), false);
358        imgStreamPtr = DataStreamPtr(imgStream);
359                img.load(imgStreamPtr, imgType);
360
361        PixelBox src = img.getPixelBox(0, 0);
362
363                // Convert and copy image
364                data = (unsigned char*)malloc(mWidth * mHeight * bpl); // Must be allocated with malloc
365
366        PixelBox dst(src, bpl == 2 ? PF_B5G6R5 : PF_A8R8G8B8, data );
367
368        PixelUtil::bulkPixelConversion(src, dst);
369        } catch(Exception &e) {
370                // Could not find image; never mind
371                LogManager::getSingleton().logMessage("GLX backdrop image not found: Warning");
372                return 0;
373        }
374
375        GC context = XCreateGC (mDisplay, rootWindow, 0, NULL);
376
377        /* put my pixmap data into the client side X image data structure */
378        XImage *image = XCreateImage (mDisplay, NULL, depth, ZPixmap, 0,
379                (char*)data,
380                mWidth, mHeight, 8,
381                mWidth*bpl);
382#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
383        image->byte_order = MSBFirst;
384#else
385    image->byte_order = LSBFirst;
386#endif
387
388        /* tell server to start managing my pixmap */
389        Pixmap rv = XCreatePixmap(mDisplay, rootWindow, mWidth,
390                mHeight, depth);
391
392        /* copy from client to server */
393        XPutImage(mDisplay, rv, context, image, 0, 0, 0, 0,
394                mWidth, mHeight);
395
396        /* free up the client side pixmap data area */
397        XDestroyImage(image); // also cleans data
398        XFreeGC(mDisplay, context);
399
400        return rv;
401}
402bool GLXConfigurator::Init() {
403        // Init misc resources
404        return true;
405}
406void GLXConfigurator::Draw() {
407}
408void GLXConfigurator::Main() {
409        XtAppMainLoop(appContext);
410}
411void GLXConfigurator::Exit() {
412        XtAppSetExitFlag(appContext);
413}
414
415void GLXConfigurator::SetRenderer(RenderSystem *r) {
416        mRenderer = r;
417
418        // Destroy each widget of GUI of previously selected renderer
419        for(std::list<Widget>::iterator i=mRenderOptionWidgets.begin(); i!=mRenderOptionWidgets.end(); i++)
420                XtDestroyWidget(*i);
421        mRenderOptionWidgets.clear();
422        mConfigCallbackData.back();
423
424        // Create option GUI
425        int cury = ystart + 1*rowh + 10;
426
427        ConfigOptionMap options = mRenderer->getConfigOptions();
428        // Process each option and create an optionmenu widget for it
429        for (ConfigOptionMap::iterator it = options.begin();
430                                        it != options.end(); it++) {
431                Widget lb1 = XtVaCreateManagedWidget("topLabel", labelWidgetClass, box, XtNlabel, it->second.name.c_str(), XtNborderWidth, 0,
432                        XtNwidth, col1w,        // Fixed width
433                        XtNheight, 18,
434                        XtNleft, XawChainLeft,
435                        XtNtop, XawChainTop,
436                        XtNright, XawChainLeft,
437                        XtNbottom, XawChainTop,
438                        XtNhorizDistance, col1x,
439                        XtNvertDistance, cury,
440                        XtNjustify, XtJustifyLeft,
441                        NULL);
442                mRenderOptionWidgets.push_back(lb1);
443                Widget mb1 = XtVaCreateManagedWidget("Menu", menuButtonWidgetClass, box, XtNlabel, it->second.currentValue.c_str(),
444                        XtNresize, false,
445                        XtNresizable, false,
446                        XtNwidth, col2w,        // Fixed width
447                        XtNheight, 18,
448                        XtNleft, XawChainLeft,
449                        XtNtop, XawChainTop,
450                        XtNright, XawChainLeft,
451                        XtNbottom, XawChainTop,
452                        XtNhorizDistance, col2x,
453                        XtNvertDistance, cury,
454                        NULL);
455                mRenderOptionWidgets.push_back(mb1);
456
457                Widget menu = XtVaCreatePopupShell("menu", simpleMenuWidgetClass, mb1,
458                        0, NULL);
459
460                // Process each choice
461                StringVector::iterator opt_it;
462                for (opt_it = it->second.possibleValues.begin();
463                                opt_it != it->second.possibleValues.end(); opt_it++) {
464                        // Create callback data
465                        mConfigCallbackData.push_back(ConfigCallbackData(this, it->second.name, *opt_it, mb1));
466
467                        Widget entry = XtVaCreateManagedWidget("menuentry", smeBSBObjectClass, menu,
468                                XtNlabel, (*opt_it).c_str(),
469                                0, NULL);
470                        XtAddCallback(entry, XtNcallback, (XtCallbackProc)&GLXConfigurator::configOptionHandler, &mConfigCallbackData.back());
471                }
472                cury += rowh;
473        }
474}
475
476void GLXConfigurator::SetConfigOption(const std::string &optionName, const std::string &valueName) {
477        if(!mRenderer)
478                // No renderer set -- how can this be called?
479                return;
480        mRenderer->setConfigOption(optionName, valueName);
481}
482
483//------------------------------------------------------------------------------------//
484ConfigDialog::ConfigDialog() : mSelectedRenderSystem(0)
485{
486}
487
488//------------------------------------------------------------------------------------//
489bool ConfigDialog::display()
490{
491        GLXConfigurator test;
492        /* Select previously selected rendersystem */
493        if(Root::getSingleton().getRenderSystem())
494                test.SetRenderSystem(Root::getSingleton().getRenderSystem());
495        /* Attempt to create the window */
496        if(!test.CreateWindow())
497                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Could not create configuration dialog",
498                       "GLXConfig::display");
499
500        // Modal loop
501        test.Main();
502        if(!test.accept) // User did not accept
503                return false;
504
505        /* All done */
506        Root::getSingleton().setRenderSystem(test.mRenderer);
507
508        return true;
509}
510};
511
Note: See TracBrowser for help on using the repository browser.