Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ceguilua/ceguilua-0.6.2/ceguilua/CEGUILua.cpp @ 2710

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

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

  • 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.