20,741
edits
Line 52: | Line 52: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
/ | #include <Main/globals.hxx> | ||
#include <Main/util.hxx> | |||
#include < | |||
// $FG_SRC/Scripting/NasalTest.cxx | |||
// $FG_SRC/Scripting/ | |||
#include <simgear/nasal/cppbind/from_nasal.hxx> | #include <simgear/nasal/cppbind/from_nasal.hxx> | ||
Line 73: | Line 64: | ||
//the struct we want to expose to Nasal (could also be a class obviously) | //the struct we want to expose to Nasal (could also be a class obviously) | ||
struct Test { | struct Test { | ||
int | int value; | ||
void hello() { | void hello() { | ||
std::cout << "Hello World from CppBind!\ | std::cout << "Hello World from CppBind!\nValue is:" << value ; | ||
} | } | ||
void setValue(const int val) {value=val;} | |||
int getValue() const {return value;} | |||
}; | }; | ||
// cppbind manages all objects as shared pointers | // cppbind manages all objects as shared pointers | ||
// use boost::shared_ptr or SGReferenced objects | |||
// typically, you'll want to provide two helper | |||
// functions for each of your classes | |||
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 when passing them between C++ <-> Nasal | ||
naRef to_nasal_helper(naContext c, Test * | // this will be used whenever you want to turn a C++ object into a Nasal Ghost | ||
naRef to_nasal_helper(naContext c, Test *obj) | |||
{ | { | ||
Test_ptr ptr( | Test_ptr ptr(obj); // set up a smart pointer wrapping obj | ||
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 | ||
} | } | ||
// and this will be used whenever you want to turn a Nasal Ghost | |||
// into a C++ object | |||
Test* | Test* | ||
from_nasal_helper(naContext c, naRef ref, const Test*) | from_nasal_helper(naContext c, naRef ref, const Test*) | ||
Line 99: | Line 100: | ||
// create a new Test object and returns it to Nasal | |||
// | // as a naRef, wrapped in an naGhost | ||
/ | // | ||
static naRef f_newtest(const nasal::CallContext& ctx) | static naRef f_newtest(const nasal::CallContext& ctx) | ||
{ | { | ||
Test* t = new Test(); | Test* t = new Test(); | ||
// do some initial state setup | // we can do some initial state setup now | ||
t-> | t->value=100; | ||
// and now return the new object to Nasal | // and now return the new object to Nasal | ||
return ctx.to_nasal( t ); | return ctx.to_nasal( t ); // NOTE: this only calls to_nasal - the to_nasal_helper we provided above is internally used | ||
} | } | ||
Line 122: | Line 115: | ||
// 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() | ||
// | |||
// to call the code, add this to FGNasalSys::init(): | |||
/* | |||
if( !NasalDemo::isInit() ) | |||
initNasalDemo(_globals, _context); | |||
*/ | |||
naRef initNasalDemo(naRef globals, naContext c) | 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, so make sure to use the ::isInit() check in FGNasalSys::init() | ||
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) | .method("hello", &Test::hello) // add a method to the ghost and map it to the method in the struct/class | ||
.member("value", &Test::getValue, &Test::setValue); | |||
// 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"); // this is the namespace we'll see and use in Nasal | ||
// add an allocator to the test namespace for creating new test objects | // add an allocator to the test namespace for creating new test objects | ||
// which will be accessible as test.new() | |||
test.set("new", &f_newtest); | 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 simply return naNil() here, it's discarded anyways | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |