Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource/src/orxonox/gui/GUIManager.cc @ 3338

Last change on this file since 3338 was 3338, checked in by rgrieder, 15 years ago

Improved exception-safety in the GUIManager.

  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *      Benjamin Knecht
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30/**
31@file
32@brief
33    Implementation of the GUIManager class.
34*/
35
36#include "GUIManager.h"
37
38#include <memory>
39extern "C" {
40#include <lua.h>
41}
42#include <CEGUIDefaultLogger.h>
43#include <CEGUIExceptions.h>
44#include <CEGUIInputEvent.h>
45#include <CEGUIResourceProvider.h>
46#include <CEGUISystem.h>
47#include <ogreceguirenderer/OgreCEGUIRenderer.h>
48
49#include "SpecialConfig.h" // Configures the macro below
50#ifdef CEGUILUA_USE_INTERNAL_LIBRARY
51#   include <ceguilua/CEGUILua.h>
52#else
53#   include <CEGUILua.h>
54#endif
55
56#include "util/Debug.h"
57#include "util/Exception.h"
58#include "util/OrxAssert.h"
59#include "core/Core.h"
60#include "core/Clock.h"
61#include "ToluaBindCore.h"
62#include "ToluaBindOrxonox.h"
63#include "core/Loader.h"
64
65namespace orxonox
66{
67    class CEGUILogger : public CEGUI::DefaultLogger
68    {
69    public:
70            void logEvent(const CEGUI::String& message, CEGUI::LoggingLevel level = CEGUI::Standard)
71        {
72            int orxonoxLevel = CEGUI::Standard;
73            switch (level)
74            {
75                case CEGUI::Errors:      orxonoxLevel = 1; break;
76                case CEGUI::Warnings:    orxonoxLevel = 2; break;
77                case CEGUI::Standard:    orxonoxLevel = 4; break;
78                case CEGUI::Informative: orxonoxLevel = 5; break;
79                case CEGUI::Insane:      orxonoxLevel = 6; break;
80                default: OrxAssert(false, "CEGUI log level out of range, inpect immediately!");
81            }
82            OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
83                << "CEGUI: " << message << std::endl;
84
85            CEGUI::DefaultLogger::logEvent(message, level);
86        }
87    };
88
89    static CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button);
90    GUIManager* GUIManager::singletonRef_s = 0;
91
92    /**
93    @brief
94        Constructs the GUIManager by starting up CEGUI
95
96        Creates the interface to Ogre, sets up the CEGUI renderer and the Lua script module together with the Lua engine.
97        The log is set up and connected to the CEGUILogger.
98        After Lua setup tolua++-elements are linked to Lua-state to give Lua access to C++-code.
99        Finally initial Lua code is executed (maybe we can do this with the CEGUI startup script automatically).
100    @param renderWindow
101        Ogre's render window. Without this, the GUI cannot be displayed.
102    @return true if success, otherwise false
103    */
104    GUIManager::GUIManager(Ogre::RenderWindow* renderWindow)
105        : renderWindow_(renderWindow)
106        , resourceProvider_(0)
107    {
108        assert(singletonRef_s == 0);
109        singletonRef_s = this;
110
111        using namespace CEGUI;
112
113        COUT(3) << "Initialising CEGUI." << std::endl;
114
115        try
116        {
117            // Note: No SceneManager specified yet
118            guiRenderer_.reset(new OgreCEGUIRenderer(renderWindow_, Ogre::RENDER_QUEUE_OVERLAY, false, 3000));
119            resourceProvider_ = guiRenderer_->createResourceProvider();
120            resourceProvider_->setDefaultResourceGroup("GUI");
121
122            // setup scripting
123            scriptModule_.reset(new LuaScriptModule());
124            luaState_ = scriptModule_->getLuaState();
125
126            // Create our own logger to specify the filepath
127            std::auto_ptr<CEGUILogger> ceguiLogger(new CEGUILogger());
128            ceguiLogger->setLogFilename(Core::getLogPathString() + "cegui.log");
129            // set the log level according to ours (translate by subtracting 1)
130            ceguiLogger->setLoggingLevel(
131                static_cast<LoggingLevel>(Core::getSoftDebugLevel(OutputHandler::LD_Logfile) - 1));
132            this->ceguiLogger_ = ceguiLogger.release();
133
134            // create the CEGUI system singleton
135            guiSystem_.reset(new System(guiRenderer_.get(), resourceProvider_, 0, scriptModule_.get()));
136
137            // do this after 'new CEGUI::Sytem' because that creates the lua state in the first place
138            tolua_Core_open(this->scriptModule_->getLuaState());
139            tolua_Orxonox_open(this->scriptModule_->getLuaState());
140
141            // initialise the basic lua code
142            this->loadLuaCode();
143        }
144        catch (CEGUI::Exception& ex)
145        {
146#if CEGUI_VERSION_MAJOR == 0 && CEGUI_VERSION_MINOR < 6
147            throw GeneralException(ex.getMessage().c_str());
148#else
149            throw GeneralException(ex.getMessage().c_str(), ex.getLine(),
150                ex.getFileName().c_str(), ex.getName().c_str());
151#endif
152        }
153    }
154
155    /**
156    @brief
157        Destructor of the GUIManager
158
159        Basically shuts down CEGUI and destroys the Lua engine and afterwards the interface to the Ogre engine.
160    */
161    GUIManager::~GUIManager()
162    {
163        // destroy our own tolua interfaces
164        lua_pushnil(luaState_);
165        lua_setglobal(luaState_, "Orxonox");
166        lua_pushnil(luaState_);
167        lua_setglobal(luaState_, "Core");
168
169        singletonRef_s = 0;
170    }
171
172    /**
173    @brief
174        Calls main Lua script
175    @todo
176        Replace loadGUI.lua with loadGUI_2.lua after merging this back to trunk.
177        However CEGUI is able to execute a startup script. We could maybe put this call in this startup code.
178
179        This function calls the main Lua script for our GUI.
180
181        Additionally we set the datapath variable in Lua. This is needed so Lua can access the data used for the GUI.
182    */
183    void GUIManager::loadLuaCode()
184    {
185        try
186        {
187            // set datapath for GUI data
188            lua_pushfstring(this->scriptModule_->getLuaState(), Core::getMediaPathString().c_str());
189            lua_setglobal(this->scriptModule_->getLuaState(), "datapath");
190            // call main Lua script
191            this->scriptModule_->executeScriptFile("loadGUI_3.lua", "GUI");
192        }
193        catch (CEGUI::Exception& ex)
194        {
195#if CEGUI_VERSION_MINOR < 6
196            throw GeneralException(ex.getMessage().c_str());
197#else
198            throw GeneralException(ex.getMessage().c_str(), ex.getLine(),
199                ex.getFileName().c_str(), ex.getName().c_str());
200#endif
201        }
202    }
203
204    /**
205    @brief
206        used to tick the GUI
207    @param time
208        clock which provides time value for the GUI System
209
210        Ticking the GUI means updating it with a certain regularity.
211        The elapsed time since the last call is given in the time value provided by the clock.
212        This time value is then used to provide a fluent animation of the GUI.
213    */
214    void GUIManager::update(const Clock& time)
215    {
216        assert(guiSystem_);
217        guiSystem_->injectTimePulse(time.getDeltaTime());
218    }
219
220    /**
221
222    */
223    void GUIManager::getLevelList()
224    {
225        lua_State* L = this->scriptModule_->getLuaState();
226        lua_newtable(L);
227
228        std::vector<std::string> list = Loader::getLevelList();
229
230        int j = 1;
231        for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); i++)
232        {
233            lua_pushnumber(L,j);
234            lua_pushstring(L,i->c_str());
235            lua_settable(L,-3);
236            j++;
237        }
238        lua_setglobal(L, "levellist");
239    }
240
241    /**
242    @brief
243        Tells the GUIManager which SceneManager to use
244    @param camera
245        The current camera on which the GUI should be displayed on.
246
247        In fact the GUIManager needs the SceneManager and not the Camera to display the GUI.
248        This means the GUI is not bound to a camera but rather to the SceneManager.
249        Hiding the GUI when needed can therefore not be resolved by just NOT setting the current camera.
250    */
251    void GUIManager::setCamera(Ogre::Camera* camera)
252    {
253        if (camera == NULL)
254            this->guiRenderer_->setTargetSceneManager(0);
255        else
256            this->guiRenderer_->setTargetSceneManager(camera->getSceneManager());
257    }
258
259    /**
260    @brief
261        Executes Lua code
262    @param str
263        reference to string object holding the Lua code which is to be executed
264
265        This function gives total access to the GUI. You can execute ANY Lua code here.
266    */
267    void GUIManager::executeCode(const std::string& str)
268    {
269        try
270        {
271            this->scriptModule_->executeString(str);
272        }
273        catch (const CEGUI::Exception& ex)
274        {
275            COUT(2) << "CEGUI Error: \"" << ex.getMessage() << "\" while executing code \"" << str << "\"" << std::endl;
276        }
277        catch (...)
278        {
279            COUT(2) << "Couldn't execute GUI related Lua code due to unknown reasons." << std::endl;
280        }
281    }
282
283    /**
284    @brief
285        Displays specified GUI on screen
286    @param name
287        The name of the GUI
288
289        The function executes the Lua function with the same name in case the GUIManager is ready.
290        For more details check out loadGUI_2.lua where the function presides.
291    */
292    void GUIManager::showGUI(const std::string& name)
293    {
294        this->executeCode(std::string("showGUI(\"") + name + "\")");
295    }
296
297    void GUIManager::keyPressed(const KeyEvent& evt)
298    {
299        guiSystem_->injectKeyDown(evt.getKeyCode());
300        guiSystem_->injectChar(evt.getText());
301    }
302    void GUIManager::keyReleased(const KeyEvent& evt)
303    {
304        guiSystem_->injectKeyUp(evt.getKeyCode());
305    }
306
307    /**
308    @brief
309        Function receiving a mouse button pressed event.
310    @param id
311        ID of the mouse button which got pressed
312
313        This function is inherited by MouseHandler and injects the event into CEGUI.
314        It is for CEGUI to process the event.
315    */
316    void GUIManager::buttonPressed(MouseButtonCode::ByEnum id)
317    {
318        try
319        {
320            guiSystem_->injectMouseButtonDown(convertButton(id));
321        }
322        catch (CEGUI::ScriptException& ex)
323        {
324            // We simply ignore the exception and proceed
325            COUT(1) << ex.getMessage() << std::endl;
326        }
327    }
328
329    /**
330    @brief
331        Function receiving a mouse button released event.
332    @param id
333        ID of the mouse button which got released
334
335        This function is inherited by MouseHandler and injects the event into CEGUI.
336        It is for CEGUI to process the event.
337    */
338    void GUIManager::buttonReleased(MouseButtonCode::ByEnum id)
339    {
340        try
341        {
342            guiSystem_->injectMouseButtonUp(convertButton(id));
343        }
344        catch (CEGUI::ScriptException& ex)
345        {
346            // We simply ignore the exception and proceed
347            COUT(1) << ex.getMessage() << std::endl;
348        }
349    }
350
351    void GUIManager::mouseMoved(IntVector2 abs, IntVector2 rel, IntVector2 clippingSize)
352    {
353        guiSystem_->injectMouseMove(static_cast<float>(rel.x), static_cast<float>(rel.y));
354    }
355    void GUIManager::mouseScrolled(int abs, int rel)
356    {
357        guiSystem_->injectMouseWheelChange(static_cast<float>(rel));
358    }
359
360    /**
361    @brief
362        converts mouse event code to CEGUI event code
363    @param button
364        code of the mouse button as we use it in Orxonox
365    @return
366        code of the mouse button as it is used by CEGUI
367
368        Simple convertion from mouse event code in Orxonox to the one used in CEGUI.
369     */
370    static inline CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button)
371    {
372        switch (button)
373        {
374        case MouseButtonCode::Left:
375            return CEGUI::LeftButton;
376
377        case MouseButtonCode::Right:
378            return CEGUI::RightButton;
379
380        case MouseButtonCode::Middle:
381            return CEGUI::MiddleButton;
382
383        case MouseButtonCode::Button3:
384            return CEGUI::X1Button;
385
386        case MouseButtonCode::Button4:
387            return CEGUI::X2Button;
388
389        default:
390            return CEGUI::NoButton;
391        }
392    }
393}
Note: See TracBrowser for help on using the repository browser.