source: OGRE/trunk/ogrenew/PlatformManagers/GLX/src/OgreGLXConfig.cpp @ 692

Revision 692, 15.5 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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