Running the Examples
From the bin directory, you can simply type "lua 01.HelloWorld.lua" without quotes to run the first example. Under linux you will need to specifically run the IrrLua lua interpreter. To do that type "./lua 01.HelloWorld.lua" from the bin directory. (If you use "lua" under linux, it will most likely run your installed lua interpreter, and that interpreter isn't linked against the correct libraries for IrrLua to work. )
You may also wish to run the examples interactively. To do so, run the interpreter without specifying a file to run. Then, once in the interpreter, you can use the 'dofile' command to run the examples, e.g. dofile("01.HelloWorld.lua").
To run Example 14, the wxWidgets example, you will need to run the example using the wxLua interpreter.
For Windows, once you have wxLua extracted, copy the wxLua.exe,
wxLua.DLL, wxmsw254_stc_vc_wxLua.dll, wxmsw254_vc_wxLua.dll to the
IrrLua bin directory. Then, you can run the wxLua.exe interpreter, open
the 14.wxWindow.lua example and run it using the wxLua debugger. The
wxLua stuff hasn't been tested on linux yet.
(*note* I've also noticed that wxLua has some bugs! When exiting,
you may need to kill any wxLua.exe processes in the process list.)
Developing with IrrLua
First and foremost, to use IrrLua in lua, you use the 'require' keyword.
-- load IrrLua into the interpreter using dynamic loading
IrrLua is ment to be a Lua binding for Irrlicht. As such it
follows Irrlicht's design as much as possible, eg. IrrLua's namespaces
are held in the table 'irr'. Things like irr::s32 and irr::f32 are all
numbers from the Lua point of view, char *, wchar * are lua strings,
arrays become tables, etc.
require "IrrLua"
Most of the standard object types like vector3d have also been implemented. To create a new object you would do:
Such types also follow the normal lua garbage collection rules and do not need to be specifically deleted.
-- create new vector3d
local myvector1 = irr.core.vector3d(1,2,3)
-- create 'uninitialized' vector3d
local myvector2 = irr.core.vector3d()
-- assign values to member variables
myvector2.X = 1
myvector2.Y = 2
myvector2.Z = 3
-- multiply vectors (invokes the c++ vector multiply overload)
local myvector3 = myvector1 * myvector2
-- call a function (if you are new to lua, note the colon when
-- calling functions of objects, and a period for accessing member variables)
myvector1 = myvector1:crossProduct(myvector2)
Using Irrlicht enums
Irrlicht's enum values are placed in the namespace where the enum
resides when imported into IrrLua. For example, the C++ variable
irr::video::E_DRIVER_TYPE::EDT_OPENGL becomes irr.video.EDT_OPENGL.
Note that the enum type name 'E_DRIVER_TYPE' is not a part of the Lua
definition.
Dealing with Inheritence
Some Irrlicht mechanisms such as the GUI callback mechanism only
provide a base class like IGUIElement to the callback. In C++, you
would cast the IGUIElement pointer to it's derived class and use the
derived pointer. Example:
s32 pos = ((IGUIScrollBar*) Caller)->getPos();
To do the same thing in IrrLua, you would do:
local pos = tolua.cast(Caller, "irr::gui::IGUIScrollBar"):getPos()
Creating new Irrlicht objects in Lua
IrrLua supports the creation of 'pure virtual' Irrlicht classes, which allows you to dynamically extend the Irrlicht engine at runtime using Lua.
The following functions are used to create new Irrlicht classes based on a Lua class:
function irr.createIEventReceiver(lua_class)
function irr.gui.createIGUIElement(type, environment, parent, id, rectangle, lua_class)
function irr.gui.createIGUISkin(lua_class)
function irr.scene.createIAnimatedMesh(lua_class)
function irr.scene.createIAnimatedMeshSceneNode(parent, manager, id, lua_class)
function irr.scene.createIMesh(lua_class)
function irr.scene.createIParticleAffector(lua_class)
function irr.scene.createIParticleEmitter(lua_class)
function irr.scene.createISceneNode(parent, manager, id, lua_class)
function irr.scene.createISceneNodeAnimator(lua_class)
function irr.scene.createISceneNodeAnimatorCollisionResponse(lua_class)
function irr.scene.createITriangleSelector(lua_class)
function irr.video.createIShaderConstantSetCallBack(lua_class)
Example:
-- Create our custom scene node in Lua CMySceneNode = {} function CMySceneNode:init() self.Box = irr.core.aabbox3d(-1,-1,-1,1,1,1) self.Vertices = { irr.video.S3DVertex(0,0,10, 1,1,0, irr.video.SColor(255,0,255,255), 0, 1), irr.video.S3DVertex(10,0,-10, 1,0,0, irr.video.SColor(255,255,0,255), 1, 1), irr.video.S3DVertex(0,20,0, 0,1,1, irr.video.SColor(255,255,255,0), 1, 0), irr.video.S3DVertex(-10,0,-10, 0,0,1, irr.video.SColor(255,0,255,0), 0, 0) } self.Material = irr.video.SMaterial() self..Material.Wireframe = false self..Material.Lighting = false self..Box:reset(self.Vertices[1].Pos) for i=2,4 do self.Box:addInternalPoint(self.Vertices[i].Pos) end return self end function CMySceneNode:OnPreRender() if self:isVisible() then self.SceneManager:registerNodeForRendering(self) end end -- You must implement render() (required) function CMySceneNode:render() local indices = {0,2,3, 2,1,3, 1,0,3, 2,0,1} local driver = self.SceneManager:getVideoDriver() driver:setMaterial(self.Material) driver:setTransform(irr.video.ETS_WORLD, self:getAbsoluteTransformation()) driver:drawIndexedTriangleList(self.Vertices, indices) end -- You must implement getBoundingBox() (required) function CMySceneNode:getBoundingBox() return self.Box end function CMySceneNode:getMaterialCount() return 1 end function CMySceneNode:getMaterial(i) return self.Material end ... local myNode = irr.scene.createISceneNode(smgr:getRootSceneNode(), smgr, -1, CMySceneNode) -- myNode now acts as an Irrlicht ISceneNode object and has members such as -- self.SceneManager that represent the protected member variables of class ISceneNode. -- call constructor like init function myNode:init()When using the 'create*' functions to create new objects, it's important to note that the returned object is a 'deep copy' of the original table. You may need to setup access to the original table depending on your class design. The CDemo.lua and CDemo.CMainMenu.lua files both have examples of dealing with variable access this way. If they had proper init() functions in their design it wouldn't be a problem and the 'owner' variable wouldn't be needed, but since those files were adapted from the C++ files it was necessary to make some Lua adaptions.
-- example event layout
-- key input
Event =
{
EventType = SEvent.EventType,
KeyInput =
{
Char = Event.KeyInput.Char,
Key = Event.KeyInput.Key,
PressedDown = Event.KeyInput.PressedDown,
Control = Event.KeyInput.Control,
Shift = Event.KeyInput.Shift
}
}
-- gui event
Event =
{
EventType = event.EventType,
GUIEvent =
{
Caller = Event.GUIEvent.Caller,
EventType = Event.GUIEvent.EventType
}
}
-- mouse input event
Event =
{
EventType = Event.EventType,
MouseInput =
{
X = Event.MouseInput.X,
Y = Event.MouseInput.Y,
Wheel = Event.MouseInput.Wheel,
Event = Event.MouseInput.Event,
}
}
-- log text event
Event =
{
EventType = Event.EventType,
LogEvent =
{
Text = Event.LogEvent.Text,
Level = Event.LogEvent.Level
}
}
-- user event
Event =
{
EventType = Event.EventType,
UserEvent =
{
UserData1 = Event.UserEvent.UserData1,
UserData2 = Event.UserEvent.UserData2,
UserData3 = Event.UserEvent.UserData3
}
}
-- example handler
MyEventReceiver = {}
function MyEventReceiver:OnEvent(Event)
if Event.EventType == irr.EET_KEY_INPUT_EVENT then
if node and not Event.KeyInput.PressedDown then
local v = node:getPosition()
if Event.KeyInput.Key == irr.KEY_KEY_W then
v.Y = v.Y + 2
node:setPosition(v)
return true
end
if Event.KeyInput.Key == irr.KEY_KEY_S then
v.Y = v.Y - 2
node:setPosition(v)
return true
end
end
end
end
return false
end
using namespace irr;
using namespace irr::core;
using namespace irr::scene;
...
A simple way to get around this is to define short-cuts:
vector3d = irr.core.vector3d
local myVector = vector3d(1,2,3) -- use new, shorter name for function
function using_namespace(t)
for i,v in pairs(t) do
_G[i] = _G[i] or v -- don't overwrite existing variables
end
end
-- example
require "IrrLua"
using_namespace(irr.core)
local v = vector3d(1,3,3)
print(v.X, v.Y, v.Z) -- 1 2 3
Using scripts with Irrlicht IReadFile (New on IrrLua >= 0.7)
irr.io.dofile(IReadFile)
Using irr.io.dofile over the built-in lua dofile allows you to load and run scripts that were loaded using Irrlicht's file system objects.
device = irr.createDevice()
zipArchive = device:getFileSystem():addZipFileArchive("mypackage.zip") -- load mypackage.zip into irrlicht's file system
readfile = device:getFileSystem():createAndOpenFile("myscript.lua") -- load myscript.lua out of mypackage.zip
irr.io.dofile(readfile) -- run the script 'myscript.lua'