How to Expose C++ Classes to Lua in Ultra Engine
I'm using the excellent sol2 library to interface C++ and Lua in the upcoming Turbo Game Engine. I've decided not to create an automatic header parser like I did for tolua++ in Leadwerks 4, for the following reasons:
- There are a lot of different options and special cases that would probably make a header parser a very involved task with me continually discovering new cases I have to account for.
- sol2 is really easy to use.
Each class I want available to Lua will have a static function the Lua virtual machine code can call when a new Lua state is created. The new_usertype method is able to expose a C++ class to Lua in a single command. At a minimum, the name of the class and the base class should be defined. This method can accept a lot of arguments, so I am going to break it up over several lines.
void Vec3::InitializeClass(sol::state* luastate) { //Class luastate->new_usertype<Vec3> ( //Name "Vec3", //Hierarchy sol::base_classes, sol::bases<Object>() ); }
We can export members to Lua very easily just by adding more arguments in the call to new_usertype:
//Members "x", &Vec3::x, "y", &Vec3::y, "z", &Vec3::z,
Metamethods are special operations like math operands. For example, adding these arguments into the method call will set all the metamethods we want to use.
//Metamethods sol::meta_function::to_string, &Vec3::ToString, sol::meta_function::index, [](Vec3& v, const int index) { if (index < 0 or index > 2) return 0.0f; return v[index]; }, sol::meta_function::new_index, [](Vec3& v, const int index, double x) { if (index < 0 or index > 2) return; v[index] = x; }, sol::meta_function::equal_to, &Vec3::operator==, sol::meta_function::less_than, &Vec3::operator<, sol::meta_function::subtraction, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator-), sol::meta_function::addition, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator+), sol::meta_function::division, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator/), sol::meta_function::multiplication, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator*), sol::meta_function::unary_minus, sol::resolve<Vec3()>(&Vec3::operator-), sol::meta_function::modulus, &Vec3::operator%,
And then finally the class methods we want to use can be exposed as follows:
//Methods "Length", &Vec3::Length, "Cross", &Vec3::Cross, "Normalize", &Vec3::Normalize, "Inverse", &Vec3::Inverse, "Distance", &Vec3::DistanceToPoint
In C++ you can not retrieve a pointer to a function, so we are going to create a quick Lambda expression and expose it as follows:
//Constructor luastate->set_function("Vec3", [](float x, float y, float z) {return Vec3(x, y, z); } );
This allows us to create a Vec3 object in Lua the same way we would with a constructor in C++.
Here is the complete Vec3 class initialization code, which makes Lua recognize the class, exposes the members, adds math operations, and exposes class methods:
void Vec3::InitializeClass(sol::state* luastate) { //Class luastate->new_usertype<Vec3> ( //Name "Vec3", //Hierarchy sol::base_classes, sol::bases<Object>(), //Members "x", &Vec3::x, "y", &Vec3::y, "z", &Vec3::z, "r", &Vec3::x, "g", &Vec3::y, "b", &Vec3::z, //Metamethods sol::meta_function::to_string, &Vec3::ToString, sol::meta_function::index, [](Vec3& v, const int index) { if (index < 0 or index > 2) return 0.0f; return v[index]; }, sol::meta_function::new_index, [](Vec3& v, const int index, double x) { if (index < 0 or index > 2) return; v[index] = x; }, sol::meta_function::equal_to, &Vec3::operator==, sol::meta_function::less_than, &Vec3::operator<, sol::meta_function::subtraction, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator-), sol::meta_function::addition, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator+), sol::meta_function::division, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator/), sol::meta_function::multiplication, sol::resolve<Vec3(const Vec3&)>(&Vec3::operator*), sol::meta_function::unary_minus, sol::resolve<Vec3()>(&Vec3::operator-), sol::meta_function::modulus, &Vec3::operator%, //Methods "Length", &Vec3::Length, "Cross", &Vec3::Cross, "Normalize", &Vec3::Normalize, "Inverse", &Vec3::Inverse, "Distance", &Vec3::DistanceToPoint ); //Constructor luastate->set_function("Vec3", [](float x, float y, float z) {return Vec3(x, y, z); } ); }
To add your own C++ classes to Lua in Turbo, you will create a similar function as above and call it at the start of the program.
- 1
8 Comments
Recommended Comments