20,741
edits
m (→Objective) |
m (→Getting started: make it build) |
||
| Line 17: | Line 17: | ||
Open $FG_SRC/Scripting/CMakeLists.txt and add these entries to the SOURCES/HEADER section respectively: | Open $FG_SRC/Scripting/CMakeLists.txt and add these entries to the SOURCES/HEADER section respectively: | ||
* | * NasalDemo.cxx (SOURCES) | ||
* | * NasalDemo.hxx (HEADERS) | ||
Next, create the | Next, create the NasalDemo.cxx source file: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
// $FG_SRC/Scripting/ | // $FG_SRC/Scripting/NasalDemo.cxx | ||
#include <simgear/nasal/cppbind/from_nasal.hxx> | #include <simgear/nasal/cppbind/from_nasal.hxx> | ||
#include <simgear/nasal/cppbind/to_nasal.hxx> | #include <simgear/nasal/cppbind/to_nasal.hxx> | ||
| Line 29: | Line 29: | ||
#include <simgear/nasal/cppbind/Ghost.hxx> | #include <simgear/nasal/cppbind/Ghost.hxx> | ||
//the struct we want to expose to Nasal (could also be a class obviously) | |||
struct Test { | struct Test { | ||
int x,y,z; | int x,y,z; | ||
| Line 36: | Line 36: | ||
} | } | ||
}; | }; | ||
// cppbind manages all objects as shared pointers, use boost::shared_ptr or SGReferenced objects | // cppbind manages all objects as shared pointers, use boost::shared_ptr or SGReferenced objects | ||
typedef boost::shared_ptr<Test> Test_ptr; | typedef boost::shared_ptr<Test> Test_ptr; | ||
typedef nasal::Ghost< Test_ptr > NasalTest; | typedef nasal::Ghost< Test_ptr > NasalTest; | ||
// next, two helper functions that tell cppbind how to | // next, two helper functions that tell cppbind how to | ||
// convert our objects between C++ <-> Nasal | // convert our objects between C++ <-> Nasal | ||
naRef to_nasal_helper(naContext c, Test *src) | naRef to_nasal_helper(naContext c, Test *src) | ||
{ | { | ||
Test_ptr ptr(src); // set up a smart pointer wrapping src | |||
return NasalTest::create(c, ptr ); // return the smart pointer wrapped in a naGhost | return NasalTest::create(c, ptr ); // return the smart pointer wrapped in a naGhost | ||
} | } | ||
Test* | Test* | ||
from_nasal_helper(naContext c, naRef ref, const Test*) | from_nasal_helper(naContext c, naRef ref, const Test*) | ||
{ | { | ||
return (Test*) naGhost_ptr(ref); | |||
} | } | ||
// add this to FGNasalSys::init(): | // add this to FGNasalSys::init(): | ||
/* | /* | ||
extern | extern initNasalDemo(naRef globals, naContext c); // or add it to the header | ||
if( !NasalDemo::isInit() ) | |||
initNasalDemo(_globals, _context); | |||
*/ | */ | ||
static naRef f_newtest(const nasal::CallContext& ctx) | static naRef f_newtest(const nasal::CallContext& ctx) | ||
{ | { | ||
| Line 72: | Line 74: | ||
t->z = 300; | t->z = 300; | ||
// and now return the new object to Nasal | // and now return the new object to Nasal | ||
return ctx.to_nasal( | return ctx.to_nasal( t ); | ||
} | } | ||
// this will register our bindings in the Nasal engine | // this will register our bindings in the Nasal engine | ||
// it should be called at the end of $FG_SRC/Scripting/NasalSys.cxx::FGNasalSys::init() | // it should be called at the end of $FG_SRC/Scripting/NasalSys.cxx::FGNasalSys::init() | ||
naRef | naRef initNasalDemo(naRef globals, naContext c) | ||
{ | { | ||
// This only needs to be called once for each ghost | // This only needs to be called once for each ghost | ||
NasalTest::init("Test") // this is the ghost's symbol used in error messages/diagnostics (it is NOT the namespace/symbol used by nasal code!) | NasalTest::init("Test") // this is the ghost's symbol used in error messages/diagnostics (it is NOT the namespace/symbol used by nasal code!) | ||
.method("hello", &Test::hello); // add a method to the ghost and map it to the method in the struct/class | .method("hello", &Test::hello); // add a method to the ghost and map it to the method in the struct/class | ||
// set up a new namespace for our functions, named test | // set up a new namespace for our functions, named test | ||
nasal::Hash globals_module(globals, c), | nasal::Hash globals_module(globals, c), | ||
test = globals_module.createHash("test"); | test = globals_module.createHash("test"); | ||
// add an allocator to the test namespace for creating new test objects | // add an allocator to the test namespace for creating new test objects | ||
test.set("new", & | test.set("new", &f_newtest); | ||
return naNil(); //we already did all the namespace setup, so we can return naNil() here | return naNil(); //we already did all the namespace setup, so we can return naNil() here | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Testing the whole thing == | |||
Fire up the Nasal console, and run this: | Fire up the Nasal console, and run this: | ||
<syntaxhighlight lang="nasal"> | <syntaxhighlight lang="nasal"> | ||
# inspect the test namespace | # inspect the test namespace | ||
debug.dump( test ); | debug.dump( test ); | ||
# inspect the result of running our allocator function | # inspect the result of running our allocator function | ||
debug.dump( var t=test.new() ); | debug.dump( var t=test.new() ); | ||
# dump the x,y,z members to the console | # dump the x,y,z members to the console | ||
foreach(var e; ['x','y','z'] | foreach(var e; ['x','y','z']) | ||
print ( t[e] ); | |||
# run the hello method | # run the hello method | ||
var t = test.new(); | |||
t.hello(); | |||
</syntaxhighlight> | </syntaxhighlight> | ||