Logo IrrLua Screenshots FAQ Docs Downloads License

Using IrrLua

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
require "IrrLua"

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.

Most of the standard object types like vector3d have also been implemented. To create a new object you would do:

-- 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)

Such types also follow the normal lua garbage collection rules and do not need to be specifically deleted.

Irrlicht Classes currently supported or partially supported in IrrLua:

function irr.createDevice
function irr.createDeviceEx

class irr.IEventReceiver
class irr.ILogger
class irr.IOSOperator
class irr.ITimer
class irr.IUnknown
class irr.SIrrlichtCreationParameters
class irr.SKeyMap

class irr.core.aabox3d
class irr.core.dimension2d
class irr.core.line3d
class irr.core.matrix4
class irr.core.plane3d
class irr.core.position2d
class irr.core.quaternion
class irr.core.rect
class irr.core.triangle3d
class irr.core.vector2d
class irr.core.vector3d

class irr.gui.ICursorControl
class irr.gui.IGUIButton
class irr.gui.IGUICheckBox
class irr.gui.IGUIComboBox
class irr.gui.IGUIContextMenu
class irr.gui.IGUIEditBox
class irr.gui.IGUIElement
class irr.gui.IGUIEnvironment
class irr.gui.IGUIFileOpenDialog
class irr.gui.IGUIFont
class irr.gui.IGUIImage
class irr.gui.IGUIInOutFader
class irr.gui.IGUIListBox
class irr.gui.IGUIMeshViewer
class irr.gui.IGUIScrollBar
class irr.gui.IGUISkin
class irr.gui.IGUIStaticText
class irr.gui.IGUITab
class irr.gui.IGUITabControl
class irr.gui.IGUIToolBar
class irr.gui.IGUIWindow

class irr.io.IFileSystem
class irr.io.IXMLReader
class irr.io.IXMLWriter

class irr.scene.IAnimatedMesh
class irr.scene.IAnimatedMeshMD2
class irr.scene.IAnimatedMeshMS3D
class irr.scene.IAnimatedMeshSceneNode
class irr.scene.IAnimatedMeshX
class irr.scene.IBillboardSceneNode
class irr.scene.ICameraSceneNode
class irr.scene.IDummyTransformationSceneNode
class irr.scene.ILightSceneNode
class irr.scene.IMesh
class irr.scene.IMeshBuffer
class irr.scene.IMeshCache
class irr.scene.IMeshLoader
class irr.scene.IMeshManipulator
class irr.scene.IParticleAffector
class irr.scene.IParticleEmitter
class irr.scene.IParticleSystemSceneNode
class irr.scene.IQ3LevelMesh
class irr.scene.ISceneCollisionManager
class irr.scene.ISceneManager
class irr.scene.ISceneNode
class irr.scene.ISceneNodeAnimator
class irr.scene.ISceneNodeAnimatorCollisionResponse
class irr.scene.IShadowVolumeSceneNode
class irr.scene.ITerrainSceneNode
class irr.scene.ITextSceneNode
class irr.scene.ITriangleSelector
class irr.scene.SAnimatedMesh
class irr.scene.SMesh
class irr.scene.SMeshBuffer
class irr.scene.SMeshBufferLightMap
class irr.scene.SMeshBufferTangents
class irr.scene.SParticle
class irr.scene.SViewFrustrum

class irr.video.IGPUProgrammingServices
class irr.video.IImage
class irr.video.IImageLoader
class irr.video.IMaterialRenderer
class irr.video.IMaterialRendererServices
class irr.video.IShaderConstantSetCallBack
class irr.video.ITexture
class irr.video.IVideoDriver
class irr.video.IVideoModeList
class irr.video.S3DVertex
class irr.video.S3DVertex2TCoords
class irr.video.S3DVertexTangents
class irr.video.SColor
class irr.video.SColorf
class irr.video.SExposedVideoData
class irr.video.SLight
class irr.video.Material


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.


Performance Considerations

Irrlicht objects created in Lua via the 'create*' functions can incur significant runtime overhead depending on the object created. It is recommended to use sound judgement when implementing such objects in real world situations. As an example, the shader callback mechanism, although functional, is not very efficient. There are simply too many calls going back and forth between lua and C++ for it to be efficient. The granularity is too small in this case. In a real world situtation, it would be best to implement things like shader callbacks and new scene node types in C++ instead of Lua. The mechanisms are provided more for completeness than real-world usage.


Using IEventReceiver (Please note this has changed from previous releases! )

To use events, you create a lua class that defines your event receiver, and then call irr.createIEventReceiver(lua_class), similar to creating a custom scene node as described above.

As of IrrLua 0.8, the old IrrLua event mechanism has been removed. You must use OnEvent(Event) as you would in Irrlicht.

The 'Event' parameter is a table which holds the event information.


-- 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


How do I use namespaces in Lua like I do C++?

In C++, you may see this code used often:
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


The above code may be undesirable, however as you have to create a short-cut for each function you want to use. In Lua, packages are held in tables, and all variables are held in the globals table "_G". To emulate the 'using namespace' functionality, you can use this 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)


IrrLua has the utility function:
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.

Example:

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' 


DirectX and Lua 5.1

Lua + DirectX9 is broken by default

DirectX by default clobbers the FPU during DirectX calls. When using IrrLua with DirectX, you will need to patch irrlicht 1.0 and add 'D3DCREATE_FPU_PRESERVE' to the creation flags for the device. As Irrlicht does not support changing these flags be default, IrrLua contains a patched version of Irrlicht.DLL that sets this flag. If you are using IrrLua with a custom build of Irrlicht, you will need to set this flag if you want to use DirectX.

Links

IrrLua API
IrrLua Examples
Lua Tutorials
Programming in Lua (free online book)
Lua 5.1 Reference
Lua syntax highlighting and intellisense for Visual Studio



•  Copyright © 2005,2006 Josh Turpen.   •