Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/steering/src/external/ceguilua/ceguilua-0.6.2/ceguilua/CEGUILua.cpp @ 6107

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

Reverted trunk again. We might want to find a way to delete these revisions again (x3n's changes are still available as diff in the commit mails).

  • Property svn:eol-style set to native
File size: 22.9 KB
Line 
1/***********************************************************************
2        filename: CEGUILua.cpp
3        created:  16/3/2005
4        author:   Tomas Lindquist Olsen
5
6        purpose:  Implementation for LuaScriptModule class
7*************************************************************************/
8/***************************************************************************
9 *   Copyright (C) 2004 - 2008 Paul D Turner & The CEGUI Development Team
10 *
11 *   Permission is hereby granted, free of charge, to any person obtaining
12 *   a copy of this software and associated documentation files (the
13 *   "Software"), to deal in the Software without restriction, including
14 *   without limitation the rights to use, copy, modify, merge, publish,
15 *   distribute, sublicense, and/or sell copies of the Software, and to
16 *   permit persons to whom the Software is furnished to do so, subject to
17 *   the following conditions:
18 *
19 *   The above copyright notice and this permission notice shall be
20 *   included in all copies or substantial portions of the Software.
21 *
22 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 *   OTHER DEALINGS IN THE SOFTWARE.
29 ***************************************************************************/
30#include "CEGUI.h"
31#include "CEGUIConfig.h"
32#include "CEGUIPropertyHelper.h"
33#include "CEGUILua.h"
34#include "CEGUILuaFunctor.h"
35#include <vector>
36
37// include Lua libs and tolua++
38extern "C" {
39#include "lua.h"
40#include "lualib.h"
41#include "lauxlib.h"
42}
43
44#include "tolua/tolua++.h"
45
46// prototype for bindings initialisation function
47int tolua_CEGUI_open(lua_State* tolua_S);
48
49
50// Start of CEGUI namespace section
51namespace CEGUI
52{
53
54/*************************************************************************
55        Constructor (creates Lua state)
56*************************************************************************/
57LuaScriptModule::LuaScriptModule() :
58    d_errFuncIndex(LUA_NOREF)
59{
60    #if LUA_VERSION_NUM >= 501
61        static const luaL_Reg lualibs[] = {
62            {"", luaopen_base},
63            {LUA_LOADLIBNAME, luaopen_package},
64            {LUA_TABLIBNAME, luaopen_table},
65            {LUA_IOLIBNAME, luaopen_io},
66            {LUA_OSLIBNAME, luaopen_os},
67            {LUA_STRLIBNAME, luaopen_string},
68            {LUA_MATHLIBNAME, luaopen_math},
69        #if defined(DEBUG) || defined (_DEBUG)
70                {LUA_DBLIBNAME, luaopen_debug},
71        #endif
72            {0, 0}
73        };
74    #endif /* LUA_VERSION_NUM >= 501 */
75
76    // create a lua state
77    d_ownsState = true;
78    d_state = lua_open();
79
80    // init all standard libraries
81    #if LUA_VERSION_NUM >= 501
82            const luaL_Reg *lib = lualibs;
83            for (; lib->func; lib++)
84            {
85                lua_pushcfunction(d_state, lib->func);
86                lua_pushstring(d_state, lib->name);
87                lua_call(d_state, 1, 0);
88            }
89    #else /* LUA_VERSION_NUM >= 501 */
90        luaopen_base(d_state);
91        luaopen_io(d_state);
92        luaopen_string(d_state);
93        luaopen_table(d_state);
94        luaopen_math(d_state);
95        #if defined(DEBUG) || defined (_DEBUG)
96            luaopen_debug(d_state);
97        #endif
98    #endif /* LUA_VERSION_NUM >= 501 */
99
100    setModuleIdentifierString();
101}
102
103
104/*************************************************************************
105        Constructor (uses given Lua state)
106*************************************************************************/
107LuaScriptModule::LuaScriptModule(lua_State* state)
108{
109        // just use the given state
110        d_ownsState = false;
111        d_state = state;
112
113        setModuleIdentifierString();
114}
115
116
117/*************************************************************************
118        Destructor
119*************************************************************************/
120LuaScriptModule::~LuaScriptModule()
121{
122    if (d_state)
123    {
124        unrefErrorFunc();
125
126        if (d_ownsState)
127            lua_close( d_state );
128    }
129}
130
131
132/*************************************************************************
133        Execute script file
134*************************************************************************/
135void LuaScriptModule::executeScriptFile(const String& filename,
136    const String& resourceGroup)
137{
138    int top = lua_gettop(d_state);
139
140    executeScriptFile_impl(filename, resourceGroup,
141                           initErrorHandlerFunc(),
142                           top);
143
144    cleanupErrorHandlerFunc();
145}
146
147
148/*************************************************************************
149        Execute global script function
150*************************************************************************/
151int     LuaScriptModule::executeScriptGlobal(const String& function_name)
152{
153    int top = lua_gettop(d_state);
154    int r = executeScriptGlobal_impl(function_name, initErrorHandlerFunc(), top);
155    cleanupErrorHandlerFunc();
156
157    return r;
158}
159
160
161/*************************************************************************
162        Execute scripted event handler
163*************************************************************************/
164bool LuaScriptModule::executeScriptedEventHandler(const String& handler_name,
165    const EventArgs& e)
166{
167    int top = lua_gettop(d_state);
168    bool r = executeScriptedEventHandler_impl(handler_name, e,
169                                              initErrorHandlerFunc(), top);
170    cleanupErrorHandlerFunc();
171
172    return r;
173}
174
175
176/*************************************************************************
177        Execute script code string
178*************************************************************************/
179void LuaScriptModule::executeString(const String& str)
180{
181    int top = lua_gettop(d_state);
182
183    executeString_impl(str, initErrorHandlerFunc(), top);
184    cleanupErrorHandlerFunc();
185}
186
187
188/*************************************************************************
189        Create Lua bindings
190*************************************************************************/
191void LuaScriptModule::createBindings(void)
192{
193        CEGUI::Logger::getSingleton().logEvent( "---- Creating Lua bindings ----" );
194        // init CEGUI module
195        tolua_CEGUI_open(d_state);
196}
197
198
199/*************************************************************************
200        Destroy Lua bindings
201*************************************************************************/
202void LuaScriptModule::destroyBindings(void)
203{
204        CEGUI::Logger::getSingleton().logEvent( "---- Destroying Lua bindings ----" );
205        // is this ok ?
206        lua_pushnil(d_state);
207        lua_setglobal(d_state,"CEGUI");
208}
209
210
211/*************************************************************************
212        Set the ID string for the module
213*************************************************************************/
214void LuaScriptModule::setModuleIdentifierString()
215{
216    // set ID string
217    d_identifierString = "CEGUI::LuaScriptModule - Official Lua based scripting module for CEGUI";
218        d_language = "Lua";
219}
220
221
222/*************************************************************************
223        Subscribe to a scripted event handler
224*************************************************************************/
225Event::Connection LuaScriptModule::subscribeEvent(EventSet* target,
226    const String& event_name, const String& subscriber_name)
227{
228    const String& err_str = getActivePCallErrorHandlerString();
229    const int err_ref     = getActivePCallErrorHandlerReference();
230
231    // do the real subscription
232    LuaFunctor functor((err_ref == LUA_NOREF) ?
233                LuaFunctor(d_state, subscriber_name, LUA_NOREF, err_str) :
234                LuaFunctor(d_state, subscriber_name, LUA_NOREF, err_ref));
235    Event::Connection con =
236        target->subscribeEvent(event_name, Event::Subscriber(functor));
237
238    // make sure we don't release the reference we just made when 'functor' is
239    // destroyed as it goes out of scope.
240    functor.index = LUA_NOREF;
241    functor.d_errFuncIndex = LUA_NOREF;
242
243    // return the event connection
244    return con;
245}
246
247
248/*************************************************************************
249        Subscribe to a scripted event handler
250*************************************************************************/
251Event::Connection LuaScriptModule::subscribeEvent(EventSet* target,
252    const String& event_name, Event::Group group, const String& subscriber_name)
253{
254    const String& err_str = getActivePCallErrorHandlerString();
255    const int err_ref     = getActivePCallErrorHandlerReference();
256
257    // do the real subscription
258    LuaFunctor functor((err_ref == LUA_NOREF) ?
259                LuaFunctor(d_state, subscriber_name, LUA_NOREF, err_str) :
260                LuaFunctor(d_state, subscriber_name, LUA_NOREF, err_ref));
261    Event::Connection con =
262        target->subscribeEvent(event_name, group, Event::Subscriber(functor));
263
264    // make sure we don't release the reference we just made when 'functor' is
265    // destroyed as it goes out of scope.
266    functor.index = LUA_NOREF;
267    functor.d_errFuncIndex = LUA_NOREF;
268
269    // return the event connection
270    return con;
271}
272
273//----------------------------------------------------------------------------//
274void LuaScriptModule::setDefaultPCallErrorHandler(
275    const String& error_handler_function)
276{
277    unrefErrorFunc();
278
279    d_errFuncName = error_handler_function;
280    d_errFuncIndex = LUA_NOREF;
281}
282
283//----------------------------------------------------------------------------//
284void LuaScriptModule::setDefaultPCallErrorHandler(int function_reference)
285{
286    unrefErrorFunc();
287
288    d_errFuncIndex = function_reference;
289    d_errFuncName.clear();
290}
291
292//----------------------------------------------------------------------------//
293const String& LuaScriptModule::getActivePCallErrorHandlerString() const
294{
295    if ((d_activeErrFuncIndex == LUA_NOREF) && d_activeErrFuncName.empty())
296        return d_errFuncName;
297    else
298        return d_activeErrFuncName;
299}
300
301//----------------------------------------------------------------------------//
302int LuaScriptModule::getActivePCallErrorHandlerReference() const
303{
304    if ((d_activeErrFuncIndex == LUA_NOREF) && d_activeErrFuncName.empty())
305        return d_errFuncIndex;
306    else
307        return d_activeErrFuncIndex;
308}
309
310//----------------------------------------------------------------------------//
311int LuaScriptModule::initErrorHandlerFunc()
312{
313    d_activeErrFuncName = d_errFuncName;
314
315    // should we create a registry reference for named function
316    if ((d_errFuncIndex == LUA_NOREF) && !d_errFuncName.empty())
317    {
318        int top = lua_gettop(d_state);
319
320        LuaFunctor::pushNamedFunction(d_state, d_errFuncName);
321        // reference function
322        d_errFuncIndex = luaL_ref(d_state, LUA_REGISTRYINDEX);
323
324        lua_settop(d_state, top);
325    }
326
327    // init handler via function index in registry
328    return initErrorHandlerFunc(d_errFuncIndex);
329}
330
331//----------------------------------------------------------------------------//
332int LuaScriptModule::initErrorHandlerFunc(const String func_name)
333{
334    d_activeErrFuncName = func_name;
335
336    // string has some text in it?
337    if (!func_name.empty())
338    {
339        LuaFunctor::pushNamedFunction(d_state, func_name);
340        return lua_gettop(d_state);
341    }
342
343    // use no error handler function.
344    return 0;
345}
346
347//----------------------------------------------------------------------------//
348int LuaScriptModule::initErrorHandlerFunc(int func)
349{
350    d_activeErrFuncIndex = func;
351
352    // check if we have a valid registry index for the error handler function
353    if (func != LUA_NOREF)
354    {
355        lua_rawgeti(d_state, LUA_REGISTRYINDEX, func);
356        return lua_gettop(d_state);
357    }
358
359    // use no error handler function.
360    return 0;
361}
362
363//----------------------------------------------------------------------------//
364void LuaScriptModule::cleanupErrorHandlerFunc()
365{
366    d_activeErrFuncIndex = LUA_NOREF;
367    d_activeErrFuncName.clear();
368}
369
370//----------------------------------------------------------------------------//
371void LuaScriptModule::unrefErrorFunc()
372{
373    if ((d_errFuncIndex != LUA_NOREF) && !d_errFuncName.empty())
374    {
375        luaL_unref(d_state, LUA_REGISTRYINDEX, d_errFuncIndex);
376        d_errFuncIndex = LUA_NOREF;
377    }
378}
379
380//----------------------------------------------------------------------------//
381void LuaScriptModule::executeScriptFile(const String& filename,
382    const String& resourceGroup, const String& error_handler)
383{
384    int top = lua_gettop(d_state);
385
386    executeScriptFile_impl(filename, resourceGroup,
387                           initErrorHandlerFunc(error_handler),
388                           top);
389    cleanupErrorHandlerFunc();
390}
391
392//----------------------------------------------------------------------------//
393void LuaScriptModule::executeScriptFile(const String& filename,
394    const String& resourceGroup, const int error_handler)
395{
396    int top = lua_gettop(d_state);
397
398    executeScriptFile_impl(filename, resourceGroup,
399                           initErrorHandlerFunc(error_handler),
400                           top);
401    cleanupErrorHandlerFunc();
402}
403
404//----------------------------------------------------------------------------//
405int LuaScriptModule::executeScriptGlobal(const String& function_name,
406    const String& error_handler)
407{
408    int top = lua_gettop(d_state);
409    int r = executeScriptGlobal_impl(function_name,
410                                     initErrorHandlerFunc(error_handler),
411                                     top);
412    cleanupErrorHandlerFunc();
413
414    return r;
415}
416
417//----------------------------------------------------------------------------//
418int LuaScriptModule::executeScriptGlobal(const String& function_name,
419    const int error_handler)
420{
421    int top = lua_gettop(d_state);
422    int r = executeScriptGlobal_impl(function_name,
423                                     initErrorHandlerFunc(error_handler),
424                                     top);
425    cleanupErrorHandlerFunc();
426
427    return r;
428}
429
430//----------------------------------------------------------------------------//
431bool LuaScriptModule::executeScriptedEventHandler(const String& handler_name,
432    const EventArgs& e, const String& error_handler)
433{
434    int top = lua_gettop(d_state);
435
436    bool r =executeScriptedEventHandler_impl(handler_name, e,
437                                             initErrorHandlerFunc(error_handler),
438                                             top);
439    cleanupErrorHandlerFunc();
440
441    return r;
442}
443
444//----------------------------------------------------------------------------//
445bool LuaScriptModule::executeScriptedEventHandler(const String& handler_name,
446    const EventArgs& e, const int error_handler)
447{
448    int top = lua_gettop(d_state);
449    bool r = executeScriptedEventHandler_impl(handler_name, e,
450                                              initErrorHandlerFunc(error_handler),
451                                              top);
452    cleanupErrorHandlerFunc();
453
454    return r;
455}
456
457//----------------------------------------------------------------------------//
458void LuaScriptModule::executeString(const String& str,
459    const String& error_handler)
460{
461    int top = lua_gettop(d_state);
462
463    executeString_impl(str, initErrorHandlerFunc(error_handler), top);
464    cleanupErrorHandlerFunc();
465}
466
467//----------------------------------------------------------------------------//
468void LuaScriptModule::executeString(const String& str, const int error_handler)
469{
470    int top = lua_gettop(d_state);
471
472    executeString_impl(str, initErrorHandlerFunc(error_handler), top);
473    cleanupErrorHandlerFunc();
474}
475
476//----------------------------------------------------------------------------//
477Event::Connection LuaScriptModule::subscribeEvent(EventSet* target,
478    const String& event_name, const String& subscriber_name,
479    const String& error_handler)
480{
481    // do the real subscription
482    LuaFunctor functor(d_state, subscriber_name, LUA_NOREF, error_handler);
483    Event::Connection con =
484        target->subscribeEvent(event_name, Event::Subscriber(functor));
485
486    // make sure we don't release the references we just made when 'functor' is
487    // destroyed as it goes out of scope.
488    functor.index = LUA_NOREF;
489    functor.d_errFuncIndex = LUA_NOREF;
490
491    // return the event connection
492    return con;
493}
494
495//----------------------------------------------------------------------------//
496Event::Connection LuaScriptModule::subscribeEvent(EventSet* target,
497    const String& event_name, const String& subscriber_name,
498    const int error_handler)
499{
500    // do the real subscription
501    LuaFunctor functor(d_state, subscriber_name, LUA_NOREF, error_handler);
502    Event::Connection con =
503        target->subscribeEvent(event_name, Event::Subscriber(functor));
504
505    // make sure we don't release the references we just made when 'functor' is
506    // destroyed as it goes out of scope.
507    functor.index = LUA_NOREF;
508    functor.d_errFuncIndex = LUA_NOREF;
509
510    // return the event connection
511    return con;
512}
513
514
515//----------------------------------------------------------------------------//
516Event::Connection LuaScriptModule::subscribeEvent(EventSet* target,
517    const String& event_name, Event::Group group, const String& subscriber_name,
518    const String& error_handler)
519{
520    // do the real subscription
521    LuaFunctor functor(d_state, subscriber_name, LUA_NOREF, error_handler);
522    Event::Connection con =
523        target->subscribeEvent(event_name, group, Event::Subscriber(functor));
524
525    // make sure we don't release the references we just made when 'functor' is
526    // destroyed as it goes out of scope.
527    functor.index = LUA_NOREF;
528    functor.d_errFuncIndex = LUA_NOREF;
529
530    // return the event connection
531    return con;
532}
533
534//----------------------------------------------------------------------------//
535Event::Connection LuaScriptModule::subscribeEvent(EventSet* target,
536    const String& event_name, Event::Group group, const String& subscriber_name,
537    const int error_handler)
538{
539    // do the real subscription
540    LuaFunctor functor(d_state, subscriber_name, LUA_NOREF, error_handler);
541    Event::Connection con =
542        target->subscribeEvent(event_name, group, Event::Subscriber(functor));
543
544    // make sure we don't release the references we just made when 'functor' is
545    // destroyed as it goes out of scope.
546    functor.index = LUA_NOREF;
547    functor.d_errFuncIndex = LUA_NOREF;
548
549    // return the event connection
550    return con;
551}
552
553//----------------------------------------------------------------------------//
554void LuaScriptModule::executeScriptFile_impl(const String& filename,
555    const String& resourceGroup, const int err_idx, const int top)
556{
557    // load file
558    RawDataContainer raw;
559    System::getSingleton().getResourceProvider()->loadRawDataContainer(filename,
560        raw, resourceGroup.empty() ? d_defaultResourceGroup : resourceGroup);
561
562    // load code into lua
563    int loaderr = luaL_loadbuffer(d_state,
564                                  reinterpret_cast<char*>(raw.getDataPtr()),
565                                  raw.getSize(), filename.c_str());
566
567    System::getSingleton().getResourceProvider()->unloadRawDataContainer( raw );
568
569    if (loaderr)
570    {
571        String errMsg = lua_tostring(d_state,-1);
572        lua_settop(d_state,top);
573        throw ScriptException("Unable to execute Lua script file: '" +
574                              filename + "'\n\n" + errMsg + "\n");
575    }
576
577    // call it
578    if (lua_pcall(d_state, 0, 0, err_idx))
579    {
580        String errMsg = lua_tostring(d_state,-1);
581        lua_settop(d_state,top);
582        throw ScriptException("Unable to execute Lua script file: '" +
583                              filename + "'\n\n" + errMsg + "\n");
584    }
585
586    lua_settop(d_state,top); // just in case :P
587}
588
589//----------------------------------------------------------------------------//
590int LuaScriptModule::executeScriptGlobal_impl(const String& function_name,
591    const int err_idx, const int top)
592{
593    // get the function from lua
594    lua_getglobal(d_state, function_name.c_str());
595
596    // is it a function
597    if (!lua_isfunction(d_state,-1))
598    {
599        lua_settop(d_state,top);
600        throw ScriptException("Unable to get Lua global: '" + function_name +
601                              "' as name not represent a global Lua function" );
602    }
603
604    // call it
605    int error = lua_pcall(d_state, 0, 1, err_idx);
606
607    // handle errors
608    if (error)
609    {
610        String errMsg = lua_tostring(d_state,-1);
611        lua_settop(d_state,top);
612        throw ScriptException("Unable to evaluate Lua global: '" + 
613                              function_name + "\n\n" + errMsg + "\n");
614    }
615
616    // get return value
617    if (!lua_isnumber(d_state,-1))
618    {
619        // log that return value is invalid. return -1 and move on.
620        lua_settop(d_state,top);
621        ScriptException("Unable to get Lua global : '" + function_name +
622                        "' return value as it's not a number");
623        return -1;
624    }
625
626    int ret = static_cast<int>(lua_tonumber(d_state,-1));
627    lua_settop(d_state,top);
628
629    // return it
630    return ret;
631}
632
633//----------------------------------------------------------------------------//
634bool LuaScriptModule::executeScriptedEventHandler_impl(
635    const String& handler_name, const EventArgs& e, const int err_idx,
636    const int top)
637{
638    LuaFunctor::pushNamedFunction(d_state, handler_name);
639
640    ScriptWindowHelper* helper = 0;
641    // If this is an event that was triggered by a window then make a "this"
642    // pointer to the window for the script.
643    if(e.d_hasWindow)
644    {
645        WindowEventArgs& we = (WindowEventArgs&)e;
646        helper = new ScriptWindowHelper(we.window);
647        lua_pushlightuserdata(d_state,(void*)helper);
648        lua_setglobal(d_state,"this");
649    }
650
651    // push EventArgs as the first parameter
652    tolua_pushusertype(d_state, (void*)&e, "const CEGUI::EventArgs");
653
654    // call it
655    int error = lua_pcall(d_state, 1, 1, err_idx);
656
657    // handle errors
658    if (error)
659    {
660        String errStr(lua_tostring(d_state,-1));
661        lua_settop(d_state,top);
662        //cleanup the helper object if any
663        if(helper)
664        {
665            delete helper;
666            helper = 0;
667        }
668
669        throw ScriptException("Unable to evaluate the Lua event handler: '" +
670                              handler_name + "'\n\n" + errStr + "\n");
671    }
672
673    // retrieve result
674    bool ret = lua_isboolean(d_state, -1) ? lua_toboolean(d_state, -1 ) : true;
675    lua_settop(d_state,top);
676
677    if(helper)
678    {
679        delete helper;
680        helper = 0;
681    }
682
683    return ret;
684}
685
686//----------------------------------------------------------------------------//
687void LuaScriptModule::executeString_impl(const String& str, const int err_idx,
688    const int top)
689{
690    // load code into lua and call it
691    int error = luaL_loadbuffer(d_state, str.c_str(), str.length(), str.c_str()) ||
692                lua_pcall(d_state, 0, 0, err_idx);
693
694    // handle errors
695    if (error)
696    {
697        String errMsg = lua_tostring(d_state,-1);
698        lua_settop(d_state,top);
699        throw ScriptException("Unable to execute Lua script string: '" +
700                              str + "'\n\n" + errMsg + "\n");
701    }
702
703    lua_settop(d_state,top);
704}
705
706//----------------------------------------------------------------------------//
707
708
709} // namespace CEGUI
Note: See TracBrowser for help on using the repository browser.