From 863cd6a2902b97c3328a6bd4cd41b9182b78aadd Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 9 Nov 2012 00:06:17 +0100 Subject: [PATCH] Canvas/Nasal and Nasal/C++ binding experiments --- src/Scripting/NasalCanvas.cxx | 786 ++++++++++++++++++++++++++---- src/Scripting/NasalCanvas.hxx | 6 - src/Scripting/NasalPositioned.cxx | 2 +- src/Scripting/NasalSys.cxx | 6 +- src/Scripting/nasal-props.cxx | 2 +- 5 files changed, 696 insertions(+), 106 deletions(-) diff --git a/src/Scripting/NasalCanvas.cxx b/src/Scripting/NasalCanvas.cxx index 08f7b9b3c..dba285147 100644 --- a/src/Scripting/NasalCanvas.cxx +++ b/src/Scripting/NasalCanvas.cxx @@ -22,13 +22,19 @@ # include "config.h" #endif +#include #include #include "NasalCanvas.hxx" +#include +#include
+//#include #include +#include +#include #include - +#include #include #include @@ -36,24 +42,10 @@ #include #include -static naRef canvasPrototype; static naRef elementPrototype; -static naRef eventPrototype; +static naRef propsNodePrototype; -static void canvasGhostDestroy(void* g); -static void elementGhostDestroy(void* g); -static void eventGhostDestroy(void* g); - -static const char* canvasGhostGetMember(naContext c, void* g, naRef field, naRef* out); -naGhostType CanvasGhostType = { canvasGhostDestroy, "canvas", canvasGhostGetMember, 0 }; - -static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out); -static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value); -naGhostType ElementGhostType = { elementGhostDestroy, "canvas.element", - elementGhostGetMember, elementGhostSetMember }; - -static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* out); -naGhostType EventGhostType = { eventGhostDestroy, "ga-event", eventGhostGetMember, 0 }; +extern naRef propNodeGhostCreate(naContext c, SGPropertyNode* n); static void hashset(naContext c, naRef hash, const char* key, naRef val) { @@ -62,31 +54,649 @@ static void hashset(naContext c, naRef hash, const char* key, naRef val) naHash_set(hash, s, val); } +template +typename boost::enable_if, naRef>::type +convertToNasal(T val) +{ + return naNum(val); +} + +//void initCanvasPython() +//{ +// using namespace boost::python; +// class_("Canvas"); +//} + +namespace sc = simgear::canvas; + +naRef canvasGetTexture(naContext c, sc::Canvas* canvas) +{ + //{ parents : [Node], _g : node } + naRef parents = naNewVector(c); + naVec_append(parents, propsNodePrototype); + + naRef node = naNewHash(c); + hashset(c, node, "parents", parents); + hashset(c, node, "_g", propNodeGhostCreate(c, canvas->getProps())); + + return node; +} + +namespace nasal +{ + + template + struct class_traits + { + typedef boost::false_type::type is_shared; + typedef T raw_type; + }; + + template + struct class_traits > + { + typedef boost::true_type::type is_shared; + typedef T raw_type; + }; + + template + struct class_traits > + { + typedef boost::true_type::type is_shared; + typedef T raw_type; + }; + + template + struct class_traits > + { + typedef boost::true_type::type is_shared; + typedef T raw_type; + }; + + template + struct SharedPointerPolicy + { + typedef typename class_traits::raw_type raw_type; + + /** + * Create a shared pointer on the heap to handle the reference counting for + * the passed shared pointer while it is used in Nasal space. + */ + static T* createInstance(const T& ptr) + { + return new T(ptr); + } + + static raw_type* getRawPtr(void* ptr) + { + return static_cast(ptr)->get(); + } + }; + + template + struct RawPointerPolicy + { + typedef typename class_traits::raw_type raw_type; + + static T* createInstance() + { + return new T(); + } + + static raw_type* getRawPtr(void* ptr) + { + BOOST_STATIC_ASSERT((boost::is_same::value)); + return static_cast(ptr); + } + }; + + class class_metadata + { + public: + void addNasalBase(const naRef& parent) + { + assert( naIsHash(parent) ); + _parents.push_back(parent); + } + + protected: + const std::string _name; + naGhostType _ghost_type; + std::vector _base_classes; + std::vector _parents; + + explicit class_metadata(const std::string& name): + _name(name) + { + + } + + void addBaseClass(class_metadata* base) + { + assert(base); + std::cout << _name << ": addBase(" << base->_name << ")" << std::endl; + _base_classes.push_back(base); + } + + naRef getParents(naContext c) + { + naRef parents = naNewVector(c); + for(size_t i = 0; i < _parents.size(); ++i) + naVec_append(parents, _parents[i]); + return parents; + } + }; + + /** + * Class for exposing C++ objects to Nasal + */ + template + class class_: + public class_metadata, + protected boost::mpl::if_< typename class_traits::is_shared, + SharedPointerPolicy, + RawPointerPolicy >::type + { + private: + typedef typename class_traits::raw_type raw_type; + + public: + + typedef boost::function getter_t; + typedef std::map GetterMap; + + static class_& init(const std::string& name) + { + getSingletonHolder().reset( new class_(name) ); + return *getSingletonPtr(); + } + + static naRef f_create(naContext c, naRef me, int argc, naRef* args) + { + return create(c); + } + + static naRef create( naContext c ) + { + return makeGhost(c, class_::createInstance()); + } + + // TODO use variadic template when supporting C++11 + template + static naRef create( naContext c, const A1& a1 ) + { + return makeGhost(c, class_::createInstance(a1)); + } + + class_& bases(const naRef& parent) + { + addNasalBase(parent); + return *this; + } + + template + typename boost::enable_if + < boost::is_convertible, + class_ + >::type& + bases() + { + Base* base = Base::getSingletonPtr(); + addBaseClass( base ); + + // Replace any getter that is not available in the current class. + // TODO check if this is the correct behavior of function overriding + const typename Base::GetterMap& base_getter = base->getGetter(); + for( typename Base::GetterMap::const_iterator getter = + base_getter.begin(); + getter != base_getter.end(); + ++getter ) + { + if( _getter.find(getter->first) == _getter.end() ) + _getter.insert( *getter ); + } + + return *this; + } + + template + typename boost::enable_if_c + < !boost::is_convertible< Type, class_metadata>::value, + class_ + >::type& + bases() + { + return bases< class_ >(); + } + + template + class_& def( const std::string& field, + Var (raw_type::*getter)() const ) + { + _getter[field] = boost::bind( &convertToNasal, + boost::bind(getter, _2) ); + return *this; + } + + class_& def_readonly( const std::string& field, + getter_t getter ) + { + _getter[field] = getter; + return *this; + } + + /** + * Data member + */ + template + class_& def_readonly( const std::string& field, + Var raw_type::*var ) + { + _getter[field] = boost::bind( &convertToNasal, + boost::bind(var, _2) ); + return *this; + } + + static class_* getSingletonPtr() + { + return getSingletonHolder().get(); + } + + const GetterMap& getGetter() const + { + return _getter; + } + + private: + + typedef std::auto_ptr class_ptr; + GetterMap _getter; + + explicit class_(const std::string& name): + class_metadata( name ) + { + _ghost_type.destroy = &destroyGhost; + _ghost_type.name = _name.c_str(); + _ghost_type.get_member = &getMember; + _ghost_type.set_member = 0; + } + + static class_ptr& getSingletonHolder() + { + static class_ptr instance; + return instance; + } + + static naRef makeGhost(naContext c, void *ptr) + { + std::cout << "makeGhost " << ptr << std::endl; + return naNewGhost2(c, &getSingletonPtr()->_ghost_type, ptr); + } + + static void destroyGhost(void *ptr) + { + std::cout << "destroyGhost " << ptr << std::endl; + delete (T*)ptr; + } + + static const char* getMember(naContext c, void* g, naRef field, naRef* out) + { + const std::string key = naStr_data(field); + if( key == "parents" ) + { + *out = getSingletonPtr()->getParents(c); + return ""; + } + + typename GetterMap::iterator getter = + getSingletonPtr()->_getter.find(key); + + if( getter == getSingletonPtr()->_getter.end() ) + return 0; + + *out = getter->second(c, class_::getRawPtr(g)); + return ""; + } + }; +} + +struct Base +{ + int getInt() const + { + return 8; + } +}; + +struct Test: + public Base +{ + Test(): x(1) {} + int x; +}; + +typedef nasal::class_ NasalCanvas; + +void initCanvas() +{ + + NasalCanvas::init("Canvas") + .def_readonly("texture", &canvasGetTexture) + .def("size_x", &sc::Canvas::getSizeX) + .def("size_y", &sc::Canvas::getSizeY); + nasal::class_::init("canvas.Element"); + nasal::class_::init("canvas.Group") + .bases(); + + nasal::class_::init("BaseClass") + .def("int", &Base::getInt); + nasal::class_::init("TestClass") + .bases() + .def_readonly("x", &Test::x); +} + +/** + * A Nasal Hash + */ +class Hash +{ + public: + + /** + * Initialize from an existing Nasal Hash + * + * @param hash Existing Nasal Hash + * @param c Nasal context + */ + Hash(const naRef& hash, naContext c): + _hash(hash), + _context(c) + { + assert( naIsHash(_hash) ); + } + + void set(const std::string& name, naRef val) + { + naHash_set(_hash, stringToNasal(name), val); + } + + void set(const std::string& name, naCFunction func) + { + set(name, naNewFunc(_context, naNewCCode(_context, func))); + } + + void set(const std::string& name, const std::string& str) + { + set(name, stringToNasal(str)); + } + + void set(const std::string& name, double num) + { + set(name, naNum(num)); + } + + /** + * Create a new child hash (module) + * + * @param name Name of the new hash inside this hash + */ + Hash createHash(const std::string& name) + { + naRef hash = naNewHash(_context); + set(name, hash); + return Hash(hash, _context); + } + + protected: + naRef _hash; + naContext _context; + + naRef stringToNasal(const std::string& str) + { + naRef s = naNewString(_context); + naStr_fromdata(s, str.c_str(), str.size()); + return s; + } +}; + +/** + * Class for exposing C++ objects to Nasal + */ +template +class NasalObject +{ + public: + // TODO use variadic template when supporting C++11 + template + static naRef create( naContext c, const A1& a1 ) + { + return makeGhost(c, new T(a1)); + } + + template + static naRef create( naContext c, const A1& a1, + const A2& a2 ) + { + return makeGhost(c, new T(a1, a2)); + } + + template + static naRef create( naContext c, const A1& a1, + const A2& a2, + const A3& a3 ) + { + return makeGhost(c, new T(a1, a2, a3)); + } + + template + static naRef create( naContext c, const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4 ) + { + return makeGhost(c, new T(a1, a2, a3, a4)); + } + + template + static naRef create( naContext c, const A1& a1, + const A2& a2, + const A3& a3, + const A4& a4, + const A5& a5 ) + { + return makeGhost(c, new T(a1, a2, a3, a4, a5)); + } + + // TODO If you need more arguments just do some copy&paste :) + + static Derived& getInstance() + { + static Derived instance; + return instance; + } + + void setParent(const naRef& parent) + { + // TODO check if we need to take care of reference counting/gc + _parents.resize(1); + _parents[0] = parent; + } + + protected: + + // TODO switch to boost::/std::function (with C++11 lambdas this can make + // adding setters easier and shorter) + typedef naRef (Derived::*getter_t)(naContext, const T&); + typedef std::map GetterMap; + + const std::string _ghost_name; + std::vector _parents; + GetterMap _getter; + + NasalObject(const std::string& ghost_name): + _ghost_name( ghost_name ) + { + _ghost_type.destroy = &destroyGhost; + _ghost_type.name = _ghost_name.c_str(); + _ghost_type.get_member = &Derived::getMember; + _ghost_type.set_member = 0; + + _getter["parents"] = &NasalObject::getParents; + } + + naRef getParents(naContext c, const T&) + { + naRef parents = naNewVector(c); + for(size_t i = 0; i < _parents.size(); ++i) + naVec_append(parents, _parents[i]); + return parents; + } + + static naRef makeGhost(naContext c, void *ptr) + { + std::cout << "create " << ptr << std::endl; + return naNewGhost2(c, &(getInstance()._ghost_type), ptr); + } + + static void destroyGhost(void *ptr) + { + std::cout << "destroy " << ptr << std::endl; + delete (T*)ptr; + } + + static const char* getMember(naContext c, void* g, naRef field, naRef* out) + { + typename GetterMap::iterator getter = + getInstance()._getter.find(naStr_data(field)); + + if( getter == getInstance()._getter.end() ) + return 0; + + *out = (getInstance().*getter->second)(c, *static_cast(g)); + return ""; + } + + private: + + naGhostType _ghost_type; + +}; + static naRef stringToNasal(naContext c, const std::string& s) { return naStr_fromdata(naNewString(c), - const_cast(s.c_str()), + const_cast(s.c_str()), s.length()); } -static naRef eventTypeToNasal(naContext c, osgGA::GUIEventAdapter::EventType ty) -{ - switch (ty) { - case osgGA::GUIEventAdapter::PUSH: return stringToNasal(c, "push"); - case osgGA::GUIEventAdapter::RELEASE: return stringToNasal(c, "release"); - case osgGA::GUIEventAdapter::DOUBLECLICK: return stringToNasal(c, "double-click"); - case osgGA::GUIEventAdapter::DRAG: return stringToNasal(c, "drag"); - case osgGA::GUIEventAdapter::MOVE: return stringToNasal(c, "move"); - case osgGA::GUIEventAdapter::SCROLL: return stringToNasal(c, "scroll"); - case osgGA::GUIEventAdapter::KEYUP: return stringToNasal(c, "key-up"); - case osgGA::GUIEventAdapter::KEYDOWN: return stringToNasal(c, "key-down"); +typedef osg::ref_ptr GUIEventPtr; - default: - break; - } - - return naNil(); -} +class NasalCanvasEvent: + public NasalObject +{ + public: + + NasalCanvasEvent(): + NasalObject("CanvasEvent") + { + _getter["type"] = &NasalCanvasEvent::getEventType; + } + + naRef getEventType(naContext c, const GUIEventPtr& event) + { +#define RET_EVENT_STR(type, str)\ + case osgGA::GUIEventAdapter::type:\ + return stringToNasal(c, str); + + switch( event->getEventType() ) + { + RET_EVENT_STR(PUSH, "push"); + RET_EVENT_STR(RELEASE, "release"); + RET_EVENT_STR(DOUBLECLICK, "double-click"); + RET_EVENT_STR(DRAG, "drag"); + RET_EVENT_STR(MOVE, "move"); + RET_EVENT_STR(SCROLL, "scroll"); + RET_EVENT_STR(KEYUP, "key-up"); + RET_EVENT_STR(KEYDOWN, "key-down"); + +#undef RET_EVENT_STR + + default: + return naNil(); + } + } +}; + +//using simgear::canvas::CanvasPtr; +// +///** +// * Expose Canvas to Nasal +// */ +//class NasalCanvas: +// public NasalObject +//{ +// public: +// +// NasalCanvas(): +// NasalObject("Canvas") +// { +// _getter["texture"] = &NasalCanvas::getTexture; +// _getter["size_x"] = &NasalCanvas::getSizeX; +// _getter["size_y"] = &NasalCanvas::getSizeY; +// } +// +// static naRef f_create(naContext c, naRef me, int argc, naRef* args) +// { +// std::cout << "NasalCanvas::create" << std::endl; +// +// CanvasMgr* canvas_mgr = +// static_cast(globals->get_subsystem("Canvas")); +// if( !canvas_mgr ) +// return naNil(); +// +// return create(c, canvas_mgr->createCanvas()); +// } +// +// static naRef f_setPrototype(naContext c, naRef me, int argc, naRef* args) +// { +// if( argc != 1 || !naIsHash(args[0]) ) +// naRuntimeError(c, "Invalid argument(s)"); +// +// getInstance().setParent(args[0]); +// +// return naNil(); +// } +// +// naRef getTexture(naContext c, const CanvasPtr& canvas) +// { +// //{ parents : [Node], _g : node } +// naRef parents = naNewVector(c); +// naVec_append(parents, propsNodePrototype); +// +// naRef node = naNewHash(c); +// hashset(c, node, "parents", parents); +// hashset(c, node, "_g", propNodeGhostCreate(c, canvas->getProps())); +// +// return node; +// } +// +// naRef getSizeX(naContext c, const CanvasPtr& canvas) +// { +// return naNum(canvas->getSizeX()); +// } +// +// naRef getSizeY(naContext c, const CanvasPtr& canvas) +// { +// return naNum(canvas->getSizeY()); +// } +//}; + +static void elementGhostDestroy(void* g); + +static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out); +static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value); +naGhostType ElementGhostType = { elementGhostDestroy, "canvas.element", + elementGhostGetMember, elementGhostSetMember }; static simgear::canvas::Element* elementGhost(naRef r) { @@ -95,37 +705,16 @@ static simgear::canvas::Element* elementGhost(naRef r) return 0; } -static simgear::canvas::Canvas* canvasGhost(naRef r) -{ - if (naGhost_type(r) == &CanvasGhostType) - return (simgear::canvas::Canvas*) naGhost_ptr(r); - return 0; -} - static void elementGhostDestroy(void* g) { } -static void canvasGhostDestroy(void* g) -{ -} - -static void eventGhostDestroy(void* g) -{ - osgGA::GUIEventAdapter* gea = static_cast(g); - gea->unref(); -} - static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); osgGA::GUIEventAdapter* gea = (osgGA::GUIEventAdapter*) g; - - if (!strcmp(fieldName, "parents")) { - *out = naNewVector(c); - naVec_append(*out, eventPrototype); - } else if (!strcmp(fieldName, "type")) *out = eventTypeToNasal(c, gea->getEventType()); - else if (!strcmp(fieldName, "windowX")) *out = naNum(gea->getWindowX()); + + if (!strcmp(fieldName, "windowX")) *out = naNum(gea->getWindowX()); else if (!strcmp(fieldName, "windowY")) *out = naNum(gea->getWindowY()); else if (!strcmp(fieldName, "time")) *out = naNum(gea->getTime()); else if (!strcmp(fieldName, "button")) *out = naNum(gea->getButton()); @@ -136,23 +725,6 @@ static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* return ""; } -static const char* canvasGhostGetMember(naContext c, void* g, naRef field, naRef* out) -{ - const char* fieldName = naStr_data(field); - simgear::canvas::Canvas* cvs = (simgear::canvas::Canvas*) g; - - if (!strcmp(fieldName, "parents")) { - *out = naNewVector(c); - naVec_append(*out, canvasPrototype); - } else if (!strcmp(fieldName, "sizeX")) *out = naNum(cvs->getSizeX()); - else if (!strcmp(fieldName, "sizeY")) *out = naNum(cvs->getSizeY()); - else { - return 0; - } - - return ""; -} - static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out) { const char* fieldName = naStr_data(field); @@ -180,10 +752,10 @@ static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value static naRef f_canvas_getElement(naContext c, naRef me, int argc, naRef* args) { - simgear::canvas::Canvas* cvs = canvasGhost(me); - if (!cvs) { - naRuntimeError(c, "canvas.getElement called on non-canvas object"); - } +// simgear::canvas::Canvas* cvs = canvasGhost(me); +// if (!cvs) { +// naRuntimeError(c, "canvas.getElement called on non-canvas object"); +// } return naNil(); } @@ -228,26 +800,42 @@ static naRef f_element_addScrollCallback(naContext c, naRef me, int argc, naRef* return naNil(); } -static naRef f_canvas(naContext c, naRef me, int argc, naRef* args) +static naRef f_createCanvas(naContext c, naRef me, int argc, naRef* args) { + std::cout << "f_createCanvas" << std::endl; + + CanvasMgr* canvas_mgr = + static_cast(globals->get_subsystem("Canvas")); + if( !canvas_mgr ) + return naNil(); + + return NasalCanvas::create(c, canvas_mgr->createCanvas()); +} + +static naRef f_setCanvasPrototype(naContext c, naRef me, int argc, naRef* args) +{ + if( argc != 1 || !naIsHash(args[0]) ) + naRuntimeError(c, "Invalid argument(s)"); + + NasalCanvas::getSingletonPtr()->addNasalBase(args[0]); + return naNil(); } -// Table of extension functions. Terminate with zeros. -static struct { const char* name; naCFunction func; } funcs[] = { - { "getCanvas", f_canvas }, - { 0, 0 } -}; - naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave) { - canvasPrototype = naNewHash(c); + naRef props_module = naHash_cget(globals, (char*)"props"); + if( naIsNil(props_module) ) + std::cerr << "No props module" << std::endl; + + propsNodePrototype = naHash_cget(props_module, (char*)"Node"); + if( naIsNil(propsNodePrototype) ) + std::cerr << "Failed to get props.Node" << std::endl; + + /*naNewHash(c); hashset(c, gcSave, "canvasProto", canvasPrototype); - hashset(c, canvasPrototype, "getElement", naNewFunc(c, naNewCCode(c, f_canvas_getElement))); - - eventPrototype = naNewHash(c); - hashset(c, gcSave, "eventProto", eventPrototype); + hashset(c, canvasPrototype, "getElement", naNewFunc(c, naNewCCode(c, f_canvas_getElement)));*/ // set any event methods elementPrototype = naNewHash(c); @@ -257,11 +845,15 @@ naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave) hashset(c, elementPrototype, "addDragCallback", naNewFunc(c, naNewCCode(c, f_element_addDragCallback))); hashset(c, elementPrototype, "addMoveCallback", naNewFunc(c, naNewCCode(c, f_element_addMoveCallback))); hashset(c, elementPrototype, "addScrollCallback", naNewFunc(c, naNewCCode(c, f_element_addScrollCallback))); - - for(int i=0; funcs[i].name; i++) { - hashset(c, globals, funcs[i].name, - naNewFunc(c, naNewCCode(c, funcs[i].func))); - } - + + Hash globals_module(globals, c), + canvas_module = globals_module.createHash("canvas"); + + canvas_module.set("_new", f_createCanvas); + canvas_module.set("_setPrototype", f_setCanvasPrototype); + canvas_module.set("testClass", nasal::class_::f_create); + + initCanvas(); + return naNil(); } diff --git a/src/Scripting/NasalCanvas.hxx b/src/Scripting/NasalCanvas.hxx index c68fc0410..394a1194b 100644 --- a/src/Scripting/NasalCanvas.hxx +++ b/src/Scripting/NasalCanvas.hxx @@ -23,12 +23,6 @@ #include -// forward decls -namespace canvas -{ - class Element; -} - naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave); #endif // of SCRIPTING_NASAL_CANVAS_HXX diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx index 24f5564ba..9deebee89 100644 --- a/src/Scripting/NasalPositioned.cxx +++ b/src/Scripting/NasalPositioned.cxx @@ -314,7 +314,7 @@ naRef ghostForWaypt(naContext c, const Waypt* wpt) if (!wpt) { return naNil(); } - + Waypt::get(wpt); // take a ref return naNewGhost2(c, &WayptGhostType, (void*) wpt); } diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 24b78b4e4..44053f279 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -557,7 +557,6 @@ void FGNasalSys::init() hashset(_globals, "__gcsave", _gcHash); initNasalPositioned(_globals, _context, _gcHash); - initNasalCanvas(_globals, _context, _gcHash); NasalClipboard::init(this); initNasalCondition(_globals, _context, _gcHash); @@ -565,6 +564,11 @@ void FGNasalSys::init() simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); loadScriptDirectory(nasalDir); + // NasalCanvas needs to be initialized after the props module from props.nas + // (located in $FG_ROOT/Nasal/) has been loaded but before loading the + // canvas module or any script creating a canvas. + initNasalCanvas(_globals, _context, _gcHash); + // Add modules in Nasal subdirectories to property tree simgear::PathList directories = nasalDir.children(simgear::Dir::TYPE_DIR+ simgear::Dir::NO_DOT_OR_DOTDOT, ""); diff --git a/src/Scripting/nasal-props.cxx b/src/Scripting/nasal-props.cxx index 6112144f2..2d1ff5fb0 100644 --- a/src/Scripting/nasal-props.cxx +++ b/src/Scripting/nasal-props.cxx @@ -33,7 +33,7 @@ static void propNodeGhostDestroy(void* ghost) naGhostType PropNodeGhostType = { propNodeGhostDestroy, "prop" }; -static naRef propNodeGhostCreate(naContext c, SGPropertyNode* n) +naRef propNodeGhostCreate(naContext c, SGPropertyNode* n) { if(!n) return naNil(); SGPropertyNode_ptr* ghost = new SGPropertyNode_ptr(n);