lua binding-early version download

Edit: An early version is ready for download. Pls post your suggetions.
http://www.artminusart.com/downloads/ofLua-test.zip

Edit2: Please look at the bottom of this page for a modified version download provided by Otherside.

Hello All,
I have asked this same question in a lua forum and got no answer. So sorry if it is cross posting.
I am trying to wrap a c++ class from openframeworks using swig. This is a part from the oftexture.

  
class ofTexture {  
  
   public :  
        
      ofTexture();  
      ~ofTexture();  
           
      void allocate(int w, int h, int internalGlDataType);     
      void clear();  
      void loadData(unsigned char * data, int w, int h, int glDataType);........};  

I have got it wrapped by including the whole header file in the swig … .i file.
I have some functions working now in lua.
The lua script file looks something like this

  
  
texColor=Example.ofTexture()--create a texture  
  
   w=250  
   h=200  
  
        colorPixels={}--create an array   
texColor:allocate(w,h,6407)--allocate the texture  
  
----------------fill the table array  
 for i=0,w do  
    for j=0,h do  
      colorPixels[(j*w+i)*3 + 0] = i   -- r  
      colorPixels[(j*w+i)*3 + 1] = j   -- g  
      colorPixels[(j*w+i)*3 + 2] = 0 -- b  
    end  
 end  
--------------  
  
texColor:loadData(colorPixels, w,h,6407 );--GL_RGB  

The loadData function won’t take a table array for unsigned char*. What am I doing wrong?
How do I use a table to pass a char* value as a function argument. Is it necessary? Or how do I do it? Please point me in the right direction.Thank you.
The following code is from the swig wrapper.

  
static int _wrap_ofTexture_loadData(lua_State* L) {  
  int SWIG_arg = -1;  
  ofTexture *arg1 = (ofTexture *) 0 ;  
  unsigned char *arg2 = (unsigned char *) 0 ;  
  int arg3 ;  
  int arg4 ;  
  int arg5 ;  
  
  if(!lua_isuserdata(L,1)) SWIG_fail_arg(1);  
  if(!lua_isuserdata(L,2)) SWIG_fail_arg(2);  
  if(!lua_isnumber(L,3)) SWIG_fail_arg(3);  
  if(!lua_isnumber(L,4)) SWIG_fail_arg(4);  
  if(!lua_isnumber(L,5)) SWIG_fail_arg(5);  
  arg1=(ofTexture *)SWIG_MustGetPtr(L,1,SWIGTYPE_p_ofTexture,0,1,"ofTexture_loadData");  
  arg2=(unsigned char *)SWIG_MustGetPtr(L,2,SWIGTYPE_p_unsigned_char,0,2,"ofTexture_loadData");  
  arg3 = (int)lua_tonumber(L, 3);  
  arg4 = (int)lua_tonumber(L, 4);  
  arg5 = (int)lua_tonumber(L, 5);  
  (arg1)->loadData(arg2,arg3,arg4,arg5);  
  SWIG_arg=0;  
  
  return SWIG_arg;  
  
fail:  
  lua_error(L);  
  return SWIG_arg;  
}  

Thanks again
Sajith

Hi,
Nice to see someone making Lua bindings to OF. The problem is how SWIG is interpreting the function signature of Texture::loadData. The argument “data” is an unsigned char * and is this translated by SWIG as a userdata whereas you’re trying to give it a table. These are 2 completely different things.

I personally have never liked SWIG and how it does bindings. It’s difficult to be elegant when things are automatically generated. I’ve made many bindings to C++ classes for Lua over the years and have done them all by hand because the mapping from C++ to Lua can vary depending on the meaning of the function being called. Sometimes I change what possible arguments are or collapse functionality from several functions in C++ into 1 Lua function. I would strongly recommend thinking carefully about how you want to expose C++ to Lua (answering the questions, what is the interface?) to make things as simple as possible on the Lua side. For instance, you shouldn’t have to know that 6407 is GL_RGB.

From your post, it sounds like you’re fairly new to Lua. You should get your hands on a copy of the Programming in Lua book. It’s really good. Also, if you’re going to be passing around OpenGL enums, get some OpenGL Lua bindings so that instead of saying 6407 in Lua, you say GL.RGB as in:

  
  
texColor:loadData(colorPixels, w,h,GL.RGB);  
  

I can post some example code how how to do this kind of stuff as well as a good opengl Lua module if you’re interested.

Thanks for the reply.

My real problem is that I can’t pass an array from lua to c++. Do I have to write a function to iterate over all the elements from the table; something like a modified version of this.

  
char* getfield (const char *key,lua_State* L)  
 {  
       char* result;  
  
      lua_pushstring(L, key);  
      lua_gettable(L, -2);  
     if (!lua_isstring(L, -1))  
      cout<<"Wrong type in table. Please give a string.";  
      result =(char*)lua_tostring(L, -1); //* MAX_Page;  
      lua_pop(L, 1);  /* remove number */  
      return result;  
    }  

But if I use a function like this I will have to iterate over the table to get all the values from the luatable.Won’t that make it slow? And I have to know the the table name in advance. Is there any other direct way to pass an array? Can you post a piece of code wrapping the oftexture using an unsigned char* array? I agree with you about wrapping without using tools like swig.
Please bear with me because I am an artist and not a pro programmer.
I used 6407 for GL_RGB because this is just test code. Ofcourse we can use something like this (from the luagl).

  
  
static const gl_str_value gl_str[] = {  
   { "VERSION_1_1"                     , 1 },  
   { "ACCUM"                           , 0x0100 },  
   { "LOAD"                            , 0x0101 },  
   { "RETURN"                          , 0x0102 },  
   { "MULT"                            , 0x0103 },  

Thank you
Sajith

Here’s a utility function I use for grabbing data from a table and putting into a buffer in C++:

  
  
template <typename T>  
static void tableToData(T *data, lua_State *L, int idx)  
{  
	int size = lua_objlen(L, idx);  
	for(int i=1; i <= size; i++) {  
		lua_rawgeti(L, idx, i);  
		*data++ = (T)lua_tonumber(L, -1);  
	}  
	lua_pop(L, size);  
}  
  

The thing to be most careful of is the difference between C++ and Lua arrays. in C++ the start index is 0. In Lua, it’s 1.

And yes, if you have to go through a table like this frequently, it will be slow. That is the nature of languages such as Lua, Python, Ruby, JS, etc. It’s not such a big deal to do this kind of thing in the script on startup, but for speed critical operations, you should do this kind of element-by-element data processing in C++ and figure out some higher-level abstraction that you can control from the scripting language.

An example would be to create some sort of expression object where you could write math equations and have C++ fill a buffer with the results. You would do the maths in Lua but the calculations in C++. That’s not a trivial task, but it’s also no super hard since Lua gives metamethods for math operations which userdata can hook into.

As for bindings to OF, I don’t have any. I just have bindings to my own OpenGL code. For textures, I don’t set data for them directly. I have a Matrix class that handles data buffers and pass Matrix objects to Texture to set its buffers. Like so:

  
  
local ctx = "Texture Test"  
local tex = Texture(ctx)  
local mat = Matrix(3, "char", 20, 20)  
  
for j=0, 19 do  
for i=0, 19 do  
    mat:setcell(i, j, {i, j, i*j*0.5})  
end  
end  
  
tex:frommatrix(mat)  
  

Thanks otherside
I will use the lua_rawgeti as you have suggested. It seems that the lua_objlen
function is not in lua5.0.2. include files.
I will compile lua 513 and post the results soon.
Sajith

Got it working. I have tried this code from the texture. And it is working except for the mouse movement. For now when the mouse moves glut is reinitialized and more windows are created with this code. Will post once I get it working properly.
Now what I have done is to call the lua setup function from simpleApp setup, lua update from simpleApp update etc. and planning to set the mouse positions as lua global and bind Glenums.In the next stage OF.ofTexture() will be like Of.Texture().
I think I should also use the testApp setup etc rather than simpleApp functions. The script is run from the main file.
Please suggest a better possible design.

Thanks

  
  
function Setup()  
  
   texGray=OF.ofTexture()  
   texColor=OF.ofTexture()  
   texColorAlpha=OF.ofTexture()  
   w=250  
   h=200  
   colorPixels={}  
   grayPixels={}  
   colorAlphaPixels={}  
  
  texGray:allocate(w,h,6409)--GL_LUMINANCE  
 texColor:allocate(w,h,6407)--GL_RGB  
 texColorAlpha:allocate(w,h,6408)--GL_RGBA  
  
--fill the table arrays with  values  
  for i=0,w*h do  
	grayPixels[i]=OF.ofRandomuf()*255  
  end  
----------------  
 for i=0,w do  
    for j=0,h do  
		colorPixels[(j*w+i)*3 + 0] = i;	-- r  
		colorPixels[(j*w+i)*3 + 1] = j;	-- g  
		colorPixels[(j*w+i)*3 + 2] = 0; -- b  
    end  
 end  
--------------  
for i=0,w do  
 for j=0,h do  
    colorAlphaPixels[(j*w+i)*4 + 0] = 255;--r  
	colorAlphaPixels[(j*w+i)*4 + 1] = 133;--g  
	colorAlphaPixels[(j*w+i)*4 + 2] = 200; --b  
	colorAlphaPixels[(j*w+i)*4 + 3] = i; --alpha  
 end  
end  
 ---------------  
  
 	texGray:loadData("grayPixels", w,h,6409 )-- GL_LUMINANCE  
	texColor:loadData("colorPixels", w,h,6407 );--GL_RGB  
	texColorAlpha:loadData("colorAlphaPixels", w,h,6408)--GL_RGBA  
  
   print ("setup OK")  
end  
----------------------------------------------------------------  
----------------------------------------------------------------  
function Update()  
  OF.ofBackground(255,255,0)  
  for i=0,w-1 do  
    for j=0,h-1 do  
  
       grayPixels[j*w+i] =OF.ofRandomuf()*255  
  
    end  
 end  
texGray:loadData("grayPixels", w,h,6409)  
print("update OK")  
end  
----------------------------------------------------------------  
function Draw()  
OF.ofSetColor(16777215)  
texGray:draw(100,100,w,h);  
texColor:draw(350,300,w,h);  
OF.ofEnableAlphaBlending();  
texColorAlpha:draw(250,200,w,h);  
OF.ofDisableAlphaBlending();  
print("draw ok")  
end  
  
----------------------------------------------------------------  
----------------------------------------------------------------  
function MouseMoved()  
  
--x is not available for now  
--problem. When mouse is moved glut creates another window.  
number=200  
pct=number/OF.ofGetWidth()  
print(pct)  
 print("mouse moved")  
 for i=0,w-1 do  
   for j=0,h-1 do  
   	 colorPixels[(j*w+i)*3 + 0] = i;	-- r  
	 colorPixels[(j*w+i)*3 + 1] = j;	--g  
	 colorPixels[(j*w+i)*3 + 2] = pct*255 -- b  
   end  
  end  
  
end  
----------------------------------------------------------------  
  
OF.ofSetupOpenGL(640,480,0)  
test=OF.simpleApp()  
OF.ofRunApp(test)  
  

Why would GLUT create another window in the mouse callback?? I think you should set the mouse function to something like

  
  
function Mouse(event, btn, x, y)  
  
end  
  

where event is something like “up”, “down”, “drag” and btn is “left”, “right”, etc.

wes

Now the texture example is working ok. I will try to work out the function parameters of mousemove as suggested by otherside. For now, the mouseX and Y can be obtained as globals.I have an early version of ofLua ready for download. Will upload within some days after cleaning,in the meantime I will try to port the other examples too. Now all the Glenums are also ready to use with minor modification, eg.GL_LUMINANCE will be used as GL.LUMINANCE. The code for the texture example looks like this now.

  
  
  
function Setup()  
print "Welcome to ofLua"  
print(of.VERSION)  
  
   texGray=of.Texture()  
   texColor=of.Texture()  
   texColorAlpha=of.Texture()  
		w=250  
		h=200  
		colorPixels={}  
          
		grayPixels={}  
		colorAlphaPixels={}  
  
texGray:allocate(w,h,GL.LUMINANCE)  
texColor:allocate(w,h,GL.RGB)  
texColorAlpha:allocate(w,h,GL.RGBA)  
  
--fill the table arrays with  values  
  for i=0,w*h do  
	grayPixels[i]=of.Randomuf()*255  
  end  
----------------  
 for i=0,w do  
    for j=0,h do  
		colorPixels[(j*w+i)*3 + 0] = i;	-- r  
		colorPixels[(j*w+i)*3 + 1] = j;	-- g  
		colorPixels[(j*w+i)*3 + 2] = 0; -- b  
    end  
 end  
--------------  
for i=0,w do  
 for j=0,h do  
    colorAlphaPixels[(j*w+i)*4 + 0] = 255;--r  
	colorAlphaPixels[(j*w+i)*4 + 1] = 133;--g  
	colorAlphaPixels[(j*w+i)*4 + 2] = 200; --b  
	colorAlphaPixels[(j*w+i)*4 + 3] = i; --alpha  
 end  
end  
 ---------------  
  
 	texGray:loadData("grayPixels", w,h,GL.LUMINANCE)  
	texColor:loadData("colorPixels", w,h,GL.RGB )  
	texColorAlpha:loadData("colorAlphaPixels", w,h,GL.RGBA)  
  
   --print ("setup OK")  
end  
----------------------------------------------------------------  
----------------------------------------------------------------  
  
function Update()  
  
of.Background(255,255,0)  
  
 for i=0,w-1 do  
    for j=0,h-1 do  
  
       grayPixels[j*w+i] =of.Randomuf()*255  
  
    end  
 end  
texGray:loadData("grayPixels", w,h,GL.LUMINANCE)  
--print("update OK")  
end  
----------------------------------------------------------------  
function Draw()  
f=15  
of.SetColor((f*f)*(f*f)*(f*f))         --0xffffff  
texGray:draw(100,100,w,h);  
texColor:draw(350,300,w,h);  
of.EnableAlphaBlending();  
texColorAlpha:draw(250,200,w,h);  
of.DisableAlphaBlending();  
--print("draw ok")  
  
end  
----------------------------------------------------------------  
function MouseMoved()  
  
pct=mouseX/of.GetWidth()  
 for i=0,w-1 do  
   for j=0,h-1 do  
   	 colorPixels[(j*w+i)*3 + 0] = i;	-- r  
	 colorPixels[(j*w+i)*3 + 1] = j;	--g  
	 colorPixels[(j*w+i)*3 + 2] = pct*255 -- b  
   end  
  end  
  texColor:loadData("colorPixels", w,h,GL.RGB);  
--print("mousemove OK")  
end  
----------------------------------------------------------------  
  
----------------------------------------------------------------  
--Now Everything is called from here.  
  
of.SetupOpenGL(640,480,of.WINDOW)  
test=of.simpleApp()  
of.RunApp(test)  
  
  

Hi Sajith,
I made a binding to ofTexture using my Udata C++ wrapper and module functions. Here’s a link: http://www.mat.ucsb.edu/~whsmith/luaOfBindings.zip

One thing though, I haven’t tested them. I also left out the loadData function since you seem to have that covered. I was wondering if you could post your ofLua project so I could test out the bindings.

thanks!

Pls download and test an early version of ofLua. Remember that the code is not stable. Error checking is not done. Please post your sugetions ,modifications and improvements .Source code and a windows binary is included.
http://www.artminusart.com/downloads/ofLua-test.zip
Edit:No need to use the testapp.cpp and h included in the zip. It will be straightforward to compile the files. Just add the files and the required lua libs. I am using lua 5.0.2, lua5.1.3 is supposed to resolve the incompatibilities soon, then I will switch over. Anyway I think you only have to modify one or two lines. Be careful to use the new ofTexture.cpp and h. Will change it to a derived class in the next stage.

Sajith

Cheers Sajith. I’ll take a look and get back to you.

Opengl commands are integrated now. So it is now possible to port the advanced graphics example. I will post the new download within some days.
Sajith

I’ve taken your ofLua project and heavily modified it to make it follow a more standard Lua model for bindings. I also added my extensions to the LuaGL module which contain the opengl enums and functions. I did a similar thing for OF, adding the enums as something like of.LEFT_BUTTON or of.IMAGE_GRAYSCALE.

I did have to add one OSX specific thing to get the path of the app so I could load scripts and modules relative to the app.

http://www.mat.ucsb.edu/~whsmith/ofLua.zip

:slight_smile: >Nice. Will download and look into the code. As I said, as an artist and self taught programmer, I have limitations. So I am sure your additions will make it better.
Sajith

Cool. I’d love to see this ofLua project get fleshed out over time. The thing I know that could use some work is the userdata template class. It has some issues when you start getting into complicated inheritance hierarchies and callbacks.

The way I would go about binding OF to Lua is to take the names of OF classes like ofImage and make it a module with an Image userdata like of.Image. Same with enums and constants as mentioned in my earlier post. I’ll leave this up to you though how it goes from here since it’s really your project and you had quite a good start :slight_smile: . I’m going to go back to lurking now.

Also, I just noticed there was a dump copy-and-paste bug on my part in luaOf.cpp:

at line 36, it should be:

  
  
of_enum_Reg of_enums[] = {  
	{"LEFT_BUTTON", GLUT_LEFT_BUTTON},  
	{"MIDDLE_BUTTON", GLUT_MIDDLE_BUTTON},  
	{"RIGHT_BUTTON", GLUT_RIGHT_BUTTON},  
	  
	{"IMAGE_GRAYSCALE", OF_IMAGE_GRAYSCALE},  
	{"IMAGE_COLOR", OF_IMAGE_COLOR},  
	{"IMAGE_COLOR_ALPHA", OF_IMAGE_COLOR_ALPHA},  
	  
	{"WINDOW", OF_WINDOW},  
	{"FULLSCREEN", OF_FULLSCREEN},  
	{"GAME_MODE", OF_GAME_MODE},  
	{0, 0}  
};  
  
  
int of_SetupOpenGL(lua_State *L)  
{  
	int w = (int)(lua_isnumber(L, 1) ? lua_tonumber(L, 1) : 1024);  
	int h = (int)(lua_isnumber(L, 2) ? lua_tonumber(L, 2) : 768);  
	int screenMode = (int)(lua_isnumber(L, 3) ? lua_tonumber(L, 3) : OF_WINDOW);  
	  
	ofSetupOpenGL(w, h, screenMode);  
	return 0;  
}  

:smiley: Oh,No. It is your project too. If you are inclined please feel free to elaborate the project. I only want to remain a part of the project and will contribute as much as I can.
And just for clarification. What is the advantage of using your template class over lunar.Me too would like to remove the swig binding, because it is difficult to edit the file even though it is easier to bind.
Sajith

It has been a long time since I looked at lunar so I can’t say much about it. I’ve been working on a revamped userdata today and yesterday that distinguishes between methods and attributes (attributes being things like dimension or type and accessible via table syntax as opposed to method syntax).

In doing this, I was contemplating what is the difference between automatic bindings and hand-made bindings and I think it comes down to subtlety a refinement. Automatic bindings are great for doing many many bindings. They are also a direct translation from lower-level code to higher-level scripting environments. Hand-made bindings on the other hand embed a concept about how this transition should take place. Often they are more or less a direct translation, but there are key points where there is a transformation of interface and in my opinion this is what makes good bindings. When working in a scripting language, I want to work at a certain level of abstractness and to have all of the things the language is bringing together in terms of library bindings to flow well with that mode of working.

So, to answer your question in a kind of roundabout way, I think my userdata template makes a good compromise between generalizing as much as possible without sacrificing so much to automation that the subtleties of the transformation of interface are lost. Hopefully this makes sense. This has been my experience over the past few years dabbling in this stuff.The more well thought out and coherent the bindings are, the more efficiently one can compose and focus on content, which is the real goal.

Will this work with lua5.1.3?
from LuaGl:

LUAGL_API int luaopen_opengl (lua_State *L) {
luaL_openlib(L, “gl”, gllib, 0);

Hope to use the template to bind the full of.

That works in the basic case. If you look at luaOf.cpp you can see how I do it with my userdata template. I have a few extra things in the lib table to handle caching of C++ instances, which is useful in certain cases where the same userdata might get push into Lua several times.

I think the best thing to do is experiment and get a feel for how things work.