Get Adobe Flash player

Luna with a slight twist.

an image

This is the version of Luna that I use for binding Lua to my applications.

To use this, follow the instructions on the LunaFour document page.

Formatting is ugly - because less than, greater than and ampersand are html, I decided to display this using xmp tags so that you can copy/paste.

The Code:

#pragma once extern "C"{ #include "Lua/lua.h" #include "Lua/lauxlib.h" #include "Lua/lualib.h" } #include <string.h> // For strlen template < class T > class Luna { public: struct PropertyType { const char *name; int (T::*getter) (lua_State *); int (T::*setter) (lua_State *); }; struct FunctionType { const char *name; int (T::*func) (lua_State *); }; /* @ check Arguments: * L - Lua State * narg - Position to check Description: Retrieves a wrapped class from the arguments passed to the func, specified by narg (position). This func will raise an exception if the argument is not of the correct type. */ static T* check(lua_State * L, int narg) { T** obj = static_cast <T **>(luaL_checkudata(L, narg, T::className)); if (!obj) return nullptr; // lightcheck returns nullptr if not found. return *obj; // pointer to T object } /* @ lightcheck Arguments: * L - Lua State * narg - Position to check Description: Retrieves a wrapped class from the arguments passed to the func, specified by narg (position). This func will return nullptr if the argument is not of the correct type. Useful for supporting multiple types of arguments passed to the func */ static T* lightcheck(lua_State * L, int narg) { T** obj = static_cast <T **>(luaL_testudata(L, narg, T::className)); if (!obj) return nullptr; // lightcheck returns nullptr if not found. return *obj; // pointer to T object } /* @ Register Arguments: * L - Lua State * namespac - Namespace to load into Description: Registers your class with Lua. Leave namespac "" if you want to load it into the global space. */ // REGISTER CLASS AS A GLOBAL TABLE static void Register(lua_State * L, const char *namespac = NULL) { if (namespac && strlen(namespac)) { lua_getglobal(L, namespac); if (lua_isnil(L, -1)) // Create namespace if not present { lua_newtable(L); lua_pushvalue(L, -1); // Duplicate table pointer since setglobal pops the value lua_setglobal(L, namespac); } lua_pushcfunction(L, &Luna < T >::constructor); lua_setfield(L, -2, T::className); lua_pop(L, 1); } else { lua_pushcfunction(L, &Luna < T >::constructor); lua_setglobal(L, T::className); } luaL_newmetatable(L, T::className); int metatable = lua_gettop(L); lua_pushstring(L, "__gc"); lua_pushcfunction(L, &Luna < T >::gc_obj); lua_settable(L, metatable); lua_pushstring(L, "__tostring"); lua_pushcfunction(L, &Luna < T >::to_string); lua_settable(L, metatable); lua_pushstring(L, "__eq"); // To be able to compare two Luna objects (not natively possible with full userdata) lua_pushcfunction(L, &Luna < T >::equals); lua_settable(L, metatable); lua_pushstring(L, "__index"); lua_pushcfunction(L, &Luna < T >::property_getter); lua_settable(L, metatable); lua_pushstring(L, "__newindex"); lua_pushcfunction(L, &Luna < T >::property_setter); lua_settable(L, metatable); for (int i = 0; T::properties[i].name; i++) { // Register some properties in it lua_pushstring(L, T::properties[i].name); // Having some string associated with them lua_pushnumber(L, i); // And a number indexing which property it is lua_settable(L, metatable); } for (int i = 0; T::methods[i].name; i++) { lua_pushstring(L, T::methods[i].name); // Register some functions in it lua_pushnumber(L, i | (1 << 8)); // Add a number indexing which func it is lua_settable(L, metatable); // } } /* @ constructor (internal) Arguments: * L - Lua State */ static int constructor(lua_State * L) { T* ap = new T(L); T** a = static_cast<T**>(lua_newuserdata(L, sizeof(T *))); // Push value = userdata *a = ap; luaL_getmetatable(L, T::className); // Fetch global metatable T::classname lua_setmetatable(L, -2); return 1; } /* @ createNew Arguments: * L - Lua State T* - Instance to push Description: Loads an instance of the class into the Lua stack, and provides you a pointer so you can modify it. */ static void push(lua_State * L, T* instance) { T **a = (T **)lua_newuserdata(L, sizeof(T *)); // Create userdata *a = instance; luaL_getmetatable(L, T::className); lua_setmetatable(L, -2); } /* @ property_getter (internal) Arguments: * L - Lua State */ static int property_getter(lua_State * L) { lua_getmetatable(L, 1); // Look up the index of a name lua_pushvalue(L, 2); // Push the name lua_rawget(L, -2); // Get the index if (lua_isnumber(L, -1)) { // Check if we got a valid index int _index = lua_tonumber(L, -1); T** obj = static_cast<T**>(lua_touserdata(L, 1)); lua_pushvalue(L, 3); if (_index & (1 << 8)) // A func { lua_pushnumber(L, _index ^ (1 << 8)); // Push the right func index lua_pushlightuserdata(L, obj); lua_pushcclosure(L, &Luna < T >::function_dispatch, 2); return 1; // Return a func } lua_pop(L, 2); // Pop metatable and _index lua_remove(L, 1); // Remove userdata lua_remove(L, 1); // Remove [key] return ((*obj)->*(T::properties[_index].getter)) (L); } return 1; } /* @ property_setter (internal) Arguments: * L - Lua State */ static int property_setter(lua_State * L) { lua_getmetatable(L, 1); // Look up the index from name lua_pushvalue(L, 2); // lua_rawget(L, -2); // if (lua_isnumber(L, -1)) // Check if we got a valid index { int _index = lua_tonumber(L, -1); T** obj = static_cast<T**>(lua_touserdata(L, 1)); if (!obj || !*obj) { luaL_error(L, "Internal error, no object given!"); return 0; } if (_index >> 8) // Try to set a func { char c[128]; sprintf(c, "Trying to set the method [%s] of class [%s]", (*obj)->T::methods[_index ^ (1 << 8)].name, T::className); luaL_error(L, c); return 0; } lua_pop(L, 2); // Pop metatable and _index lua_remove(L, 1); // Remove userdata lua_remove(L, 1); // Remove [key] return ((*obj)->*(T::properties[_index].setter)) (L); } return 0; } /* @ function_dispatch (internal) Arguments: * L - Lua State */ static int function_dispatch(lua_State * L) { int i = (int)lua_tonumber(L, lua_upvalueindex(1)); T** obj = static_cast < T ** >(lua_touserdata(L, lua_upvalueindex(2))); return ((*obj)->*(T::methods[i].func)) (L); } /* @ gc_obj (internal) Arguments: * L - Lua State */ static int gc_obj(lua_State * L) { T** obj = static_cast < T ** >(lua_touserdata(L, -1)); T* instance = *obj; if ((*obj)->isPrecious) return 0; if (obj && *obj) delete(*obj); return 0; } static int to_string(lua_State* L) { T** obj = static_cast<T**>(lua_touserdata(L, -1)); if (obj) lua_pushfstring(L, "%s (%p)", T::className, (void*)*obj); else lua_pushstring(L, "Empty object"); return 1; } /* * Method which compares two Luna objects. * The full userdatas (as opposed to light userdata) can't be natively compared one to other, we have to had this to do it. */ static int equals(lua_State* L) { T** obj1 = static_cast<T**>(lua_touserdata(L, -1)); T** obj2 = static_cast<T**>(lua_touserdata(L, 1)); lua_pushboolean(L, *obj1 == *obj2); return 1; } };
Donations Gratefully Accepted

I've started a Patreon campaign to help pay site support costs. Donations are gratefully accepted and greatly appreciated.

Vegassparkyrich on Patreon
Highlights
  • Feb 1, 2014

    I've added a copy of the Torque 3D Documentation to my site. This was a move on my part to alleviate some frustration I was feeling related to being unable to update the Official Documentation with corrections or clarifications to the existing articles. The link is just down a bit from this sidebar item....

  • Mar 2, 2012

    The main menu buttons got a slight style tweak, making the active state more visible and the menu text more legible. This should be the last style adjustment and then it's just a matter of generating several pages of bogus content.
    Read more...

Torque 3D Reference
Torque 3D Online Documentation

This is not the "Official" Torque 3D documentation. This is my personal version. It will have some portions that are newer or have been edited for clarity, and it will have some portions that are very stale. I update the things that I am interested in or that I have seen many questions about on the forums. I will be adding things as I discover new ways to do this or that, or just because I think they're nifty.

Torque 3D Source Reference

Torque 3D 3.7
Torque 3D 3.8

This is a generated document, and as such may not be as helpful as one might hope. However, it is a complete class, namespace, file, and variable reference generated directly from the source and does contain inheritance diagrams (pretty helpful in their own right).

You can always contact richard@roostertailgames.com with corrections, updates, questions or requests, but be aware that I'm grumpy and don't always answer my email.

Contact Info
an image
Roostertail Games
Las Vegas, NV 89147
Email: service@roostertailgames.com
For Fun
A jumper cable walks into a bar. The 
bartender says, "I'll serve you, but don't 
start anything."