   [Lua][LuaBind] Trouble with binding classes and methods
  Hey GameDev.  I've been implementing Lua for a game project, and I decided I wanted to try and use LuaBind to avoid having to write wrappers for everything I wanted to expose to script from C++.  After finally getting everything to link successfully, I hit a snag when I try to expose a very basic class or method to lua.  The strange thing is that I can get luabind to build fine in console examples like this that I found browsing tutorials and examples:Console cpp:#include "lua_test.h"using namespace luabind;//classes pasted from headersclass NumberPrinter {public:NumberPrinter(int number) :  m_number(number) {}  void print()   {  cout << m_number << endl;  }private:int m_number;};class A{private:int a_;public:A() : a_(0) {}int get_a() const { return a_; }void set_a(int a) { a_ = a; }};void sayHello(int i) {cout << "hello " << i <<endl;}void retrieveData(A& a) {cout << "retrieved " << a.get_a() << endl;}int main ( int argc, char *argv[] ){/* initialize Lua */LI = lua_open(); if (NULL == LI){printf("Error Initializing LUA!\n");return -1;}// load Lua base librariesluaL_openlibs( LI );//load in luabindopen( LI );// Export our class with LuaBind//separate definitions with commasmodule(LI) [class_<NumberPrinter>("NumberPrinter").def(constructor<int>()).def("print", &NumberPrinter::print),class_<A>("A").def(constructor<>()).property("a", &A::get_a, &A::set_a),def("sayHello",&sayHello),def("retrieveData",&retrieveData)];The above works perfectly.  However, in my own solution I'm trying to expose a method called BuildSpriteObj in the class 'Renderer2D' so that I can script out my sprite  data.  I've tried exposing just the method, and also the whole class.  Here's what I'm trying to build:Snippet from GUIDemo solution:#include "ScriptTranslator.h"#include "Renderer2D.h"#include "SpriteObj.h"using namespace luabind;//method implementations for script translator class//initializes lua object and librariesvoid ScriptTranslator::Init(lua_State* LI){//call LUA/* initialize Lua */LI = lua_open();if (NULL == LI){//throw exception}/* load Lua base libraries */luaL_openlibs( LI );//load in luabindopen( LI );//define luabind scopes and methods/classes registeredmodule( LI ) //module is global scope[//bind spriteobj class so we can call buildspriteobjclass_<Renderer2D>("Renderer2D").def(constructor<>()).def("BuildSpriteObj", &Renderer2D::BuildSpriteObj)/*class_<SpriteObj>("SpriteObj").def(constructor<>()).def("Init",&SpriteObj::Init)*///def("BuildSpriteObj", &Renderer2D::BuildSpriteObj)];}Compiler Error when I attempt to expose the whole class:Error2error C2660: 'luabind::detail::overload_rep::overload_rep' : function does not take 2 argumentsc:\documents and settings\administrator\desktop\gui demo\directx_template\references\luabind\include\luabind\class.hpp1215Compiler Error when I attempt to expose only one method:Error2error C2660: 'luabind::detail::free_functions::overload_rep::overload_rep' : function does not take 2 argumentsc:\documents and settings\administrator\desktop\gui demo\directx_template\references\luabind\include\luabind\function.hpp227I've read over the (rather inadequate) documentation on the LuaBind site and I've browsed around for threads but nothing really turned up to explain this.  I've looked into the method that breaks in the source files but it appeared fine, and I didn't want to start changing things within the luabind headers.  I figure it's either in the way I've done the constructors, or some kind of screw-up in the binding code that I don't see.  Has anyone seen this problem or have any idea what I'm doing wrong?  Any and all input is greatly appreciated, thanks!Renderer2D Class Header:#pragma once#include <d3d9.h>#include <d3dx9.h>#include "cDLL_Node.h"#include "cdll_list.h"#include "ScriptTranslator.h"#pragma comment(lib, "d3d9.lib")#pragma comment(lib, "d3dx9.lib")//forward declarations for contents of SpriteObjstruct SpriteTexture;class SpriteObj;class Renderer2D{//attributespublic://linked lists of 2d stuff on screencDLL_List<SpriteTexture>SpriteTextures;cDLL_List<SpriteObj>SpriteObjs;//cDLL_List<GuiObj>GuiObjs;//cDLL_List<TextObj>TextObjects;//D3D sprite object pointerID3DXSprite*m_pD3DSprite;IDirect3DDevice9*m_pD3DDevice;//fontLPD3DXFONTtextFont;Renderer2D();~Renderer2D();//behaviors//initvoid Init(IDirect3DDevice9*m_pD3DDevice); //initialize lists i guess, and load gui objects//factory method that gets a filename, pass back a pointer to the finished picture, load picture//create sprite object, keep track of object to be deleted later//rendervoid Render();//directx class will tell 2d renderer to render, //this method will contain loops that go through the lists to render everything//clear - clears the prototypes being usedvoid Clear();//shutdown - shutdown D3Dspriteobjectvoid Shutdown();//returns pointer to SpriteTexture when given the name of the picture filenameSpriteTexture* GetSpriteTexturePointer(wstring picfilename);//this method is intended to be called from script, in order to build up SpriteObj prototypesvoid BuildSpriteObj(float positionx, float positiony, float rotation,float scaleX, float scaleY, int dirRot, int trans, int red, int green, int blue, wstring picfilename );};
  You probably need to redefine LUABIND_MAX_ARITY to something larger than the default (which is 10), since your function takes 11 parameters.   ;Quote:Original post by dw9You probably need to redefine LUABIND_MAX_ARITY to something larger than the default (which is 10), since your function takes 11 parameters.Yes, that has to be the problem, thanks!  Would you happen to know if/where I can redefine that value without recompiling the static libraries?  In the hpps that are in the includes I use don't seem to be able to see the definition of that variable, although its referenced quite a bit in them.EDIT - I found the definition, it's done in the LuaBind 'config.hpp' file that's found in the includes. (for anyone else that might encounter this problem).Upon changing the definition however (LUABIND_MAX_ARITY was 10 and I increased it to 15), I got back 600+ compiler errors related to the boost libraries 'tuples::tuple - too many template arguments'.  I figure I have to change another define within boost that somehow correlates to the number of parameters I can pass through the template, but I'm still looking.  Anyone know what it's about?[Edited by - nerael on May 1, 2009 8:49:36 PM];  Changing the max number of support arguments is more trouble than it's worth, why not pack those arguments into a struct and pass that instead. Luabind allows you to create bindings for simple structs in a snap and it wouldn't change your API that much.Good Luck!-ddn   ;  Going along with ddn3's (good) suggestion, I'd also remind you that you can easily bind certain overloads of a function with luabind, so you don't necessarily have to change your engine at all.Simply provide another version of the function that takes a struct of info (or multiple structs... your r g b values would be a good starting place), bind that version (and it's structs) to luabind, and have that version call your original 11 parameter version.I've had to do this in a couple of situations with luabind, and I actually find myself using the "luabind version" in C++ faily often.   ;  Thank you everyone for your constructive input!  I'll pack some structs together and see if I have better luck with the binding process over the next few days of development, along with utilizing some overloads where necessary.  I came close to scrapping LuaBind and just writing my own wrappers in frustration today, haha.  Hopefully I'll have some better luck with binding utilizing these suggestions. =D   ;  I've implemented these suggestions and it builds fine now! =D  Now the only problem is to figure out how I can get these method calls to use the same instance of the object when it's called in script so it adds these sprites to the linked list in C++.   ;  Okay, so although my solution builds, I am having a real hard time trying to figure out how to get LuaBind to actually execute these C++ methods.  Right now I just build to an empty screen, which means that my script file isn't executing properly (no sprites are being constructed).  I know that there's no problem in my rendering code, because I can hardcode a sprite in by passing parameters to the BuildSpriteObj method manually in C++.Ideally what I need to be able to do in this example, is to call a static method that builds the SpriteObj from the script file, so that in the Lua file I can just say StaticBuildSpriteObj(param,param,param... etc.);.  Is this possible, or am I going to have to do it another way?  As it stands I have the static method declared and passed to Lua as a non-member function, and I've tried figuring out how to use a copy of the Renderer2D class within Lua, but I can't get it back to C, and I figured out that I'd much rather use a static method if at all possible.LUA Script File:--R2D = Renderer2D();--does this R2D object need to be declared? --we're trying to use a singleton instance copy of the Renderer2D class--can i use this instance for the purpose of holding the whole 2d renderer? or can i pass this back to c?--can i instead pass the instance of the c class to lua so they use the same one?--create a table that will hold all variables needed for a health display--it will eventually be a spriteobjHealthDisplay =  {positionx=  200.0,positiony=  400.0,scalex=  0.8,scaley=  0.8,rot=  0.0,transp=  255,red=  255,green=  255,blue=  255,filepath=  "healthbar.png"};--pack a struct with the argb values so it can be passed in the static build function-- can we pass a typeless table into this thing as a struct?--colors = ARGBValues(HealthDisplay.transp,HealthDisplay.red,HealthDisplay.green,HealthDisplay.blue);--load the health display data into a spriteobj--will luabind actually make this static function avaliable?StaticBuildSpriteObj(HealthDisplay.positionx,HealthDisplay.positiony,HealthDisplay.scalex,HealthDisplay.scaley,HealthDisplay.rot,ARGBValues(HealthDisplay.transp,HealthDisplay.red,HealthDisplay.green,HealthDisplay.blue),HealthDisplay.filepath);Updated Renderer2D.h//Renderer2D.h//Seraph Project#pragma once#include <d3d9.h>#include <d3dx9.h>#include "cDLL_Node.h"#include "cdll_list.h"#include "ScriptTranslator.h"#pragma comment(lib, "d3d9.lib")#pragma comment(lib, "d3dx9.lib")//forward declarations neededstruct SpriteTexture;struct ARGBValues;class SpriteObj;class Renderer2D{//attributespublic:static Renderer2D* instance;//linked lists of 2d stuff on screencDLL_List<SpriteTexture>SpriteTextures;cDLL_List<SpriteObj>SpriteObjs;//cDLL_List<GuiObj>GuiObjs;//cDLL_List<TextObj>TextObjects;//D3D sprite object pointerID3DXSprite*m_pD3DSprite;IDirect3DDevice9*m_pD3DDevice;//fontLPD3DXFONTtextFont;Renderer2D();~Renderer2D();//behaviors//initvoid Init(IDirect3DDevice9*m_pD3DDevice); //initialize lists i guess, and load gui objects//factory method that gets a filename, pass back a pointer to the finished picture, load picture//create sprite object, keep track of object to be deleted later//rendervoid Render();//directx class will tell 2d renderer to render, //this method will contain loops that go through the lists to render everything//clear - clears the prototypes being usedvoid Clear();//shutdown - shutdown D3Dspriteobjectvoid Shutdown();//returns pointer to SpriteTexture when given the name of the picture filenameSpriteTexture* GetSpriteTexturePointer(string picfilename);//this method is intended to be called from script, in order to build up SpriteObj prototypesvoid BuildSpriteObj(float positionx, float positiony, float rotation,float scaleX, float scaleY,ARGBValues colors, string picfilename );static void StaticBuildSpriteObj(float positionx, float positiony, float rotation,float scaleX, float scaleY,ARGBValues colors, string picfilename);static Renderer2D* GetInstance();};Updated Renderer2D.cpp//Renderer2D.cpp//Seraph Project#include "Renderer2D.h"#include "SpriteObj.h"//#include "DirectX.h"//required for singleton instanceRenderer2D* Renderer2D::instance = NULL;//blank constructorRenderer2D::Renderer2D(){}Renderer2D::~Renderer2D(){}void Renderer2D::Init(IDirect3DDevice9*m_pD3DDevice){//remember to initialize linked lists here//get the directx pointer object so we can build a SpriteObjD3DXCreateSprite(m_pD3DDevice, &m_pD3DSprite);//this makes the pointer contained in the r2d class point to the same device that the DirectX class hasthis->m_pD3DDevice = m_pD3DDevice;}void Renderer2D::Render(){// get position and button status of mouse cursor// calculate mouse cursor's effects on windows / send messages// render all windows//remember somewhere we need to start the d3d sprite object//go through list of prototypes that we already haveSpriteObj* temp;//tells SpriteTextures we're starting a new searchSpriteObjs.RestartIteration();//grabs the next node in the list and makes sure its not null//when the list meets the end, it will return nullfor(temp=SpriteObjs.IterateNext(); temp != NULL; temp=SpriteObjs.IterateNext()){temp->Render(m_pD3DSprite);}// render mouse// flip to screen}void Renderer2D::Shutdown(){//remember to shutdown linked lists//pass true if asked for bool}void Renderer2D::Clear(){//wipes out everything from the screen, but keeping com objects//used when shutting down and reinitializing linked lists}SpriteTexture* Renderer2D::GetSpriteTexturePointer( string picfilename ){//go through list of prototypes that we already haveSpriteTexture* temp;//tells spritetextures we're starting a new searchSpriteTextures.RestartIteration();//grabs the next node in the list and makes sure its not null//when the list meets the end, it will return nullfor(temp=SpriteTextures.IterateNext(); temp != NULL; temp=SpriteTextures.IterateNext()){//if we have one with the same picfilename, we return the pointer to that oneif(temp->picfilename == picfilename){return temp;}}//otherwise, get it from the file and add to prototype listtemp = new SpriteTexture();temp->picfilename = picfilename;//load sprite textures//the picfile name only works in these arguments if its a regular string, and we call the magical c_str methodHRESULT HR = D3DXCreateTextureFromFileEx(m_pD3DDevice, picfilename.c_str(), 0, 0, 0, 0,D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT,D3DCOLOR_XRGB(255,0,255), //KEY COLOR (magenta)&temp->ImageInfo, 0, &temp->m_pD3DTexture);//add temp to list of prototypesSpriteTextures.InsertNode(temp,true);return temp;}void Renderer2D::BuildSpriteObj(float positionx, float positiony, float rotation,  float scaleX, float scaleY, ARGBValues colors, string picfilename ){//builds a new spriteobjSpriteObj* temp = new SpriteObj( NULL, positionx,  positiony,  rotation,scaleX,  scaleY,  colors);//when setting parameters, we need to call the getspritetexturepointertemp->m_pSpriteTexture = GetSpriteTexturePointer(picfilename);//needs to add it to the list of spritobjsSpriteObjs.InsertNode(temp,true);}void Renderer2D::StaticBuildSpriteObj( float positionx, float positiony, float rotation, float scaleX, float scaleY,ARGBValues colors, string picfilename ){GetInstance()->BuildSpriteObj( positionx,  positiony,  rotation,  scaleX,  scaleY, colors,  picfilename);}//returns a pointer to the r2d instanceRenderer2D* Renderer2D::GetInstance(){if(instance){return instance;}instance = new Renderer2D();}From Updated ScriptTranslator.cpp:void ScriptTranslator::Init(lua_State* LI){//call LUA/* initialize Lua */LI = lua_open();if (NULL == LI){//throw exception}/* load Lua base libraries */luaL_openlibs( LI );//load in luabindopen( LI );//define luabind scopes and methods/classes registeredmodule( LI ) //module is global scope[//bind spriteobj class so we can call buildspriteobjclass_<Renderer2D>("Renderer2D").def(constructor<>()).def("BuildSpriteObj", &Renderer2D::BuildSpriteObj),def("StaticBuildSpriteObj", &Renderer2D::StaticBuildSpriteObj),//pack arguments into structs so luabind has less to passclass_<ARGBValues>("ARGBValues").def(constructor<int,int,int,int>())/*class_<SpriteObj>("SpriteObj").def(constructor<>()).def("Init",&SpriteObj::Init)*///def("BuildSpriteObj", &Renderer2D::BuildSpriteObj)];//attempt to pass the instance of the R2D object to lua as a global //luabind::globals(LI)["R2D"] = &CDirectX::R2D;}