Bye bye XML, hello Lua

posted in I am a duck
Published February 22, 2011
Advertisement
A few nights of coding again gets me in a situation where I have the exact same output from my engine but I'm in a far better place! I completed the transition from having an XML file representing a scene to just exposing all of the scene creation calls to Lua and creating a scene in script. It was surprisingly more painful than I expected since there are so many different classes that needed to be bound to Lua. It was all fairly straightforward but it was a case where you're making a bunch of code changes and you don't really see if you've succeeded until you've got them all in place. It can make for some interesting debugging but lucky for me everything worked out smoothly.

Going with creating a scene in a script doesn't give me any kind of perf gains or fancy new features but it does make iteration faster and easier moving forward. I no longer have to worry about updating my XML schema every time I want to add a new component. I still need to bind the new component to Lua but that's a far quicker task. This work also had the side effect of getting me to do a little bit of refactoring as well. My XML loading code was doing some work that should have been placed elsewhere so now it is cleaned up and hopefully a bit more straight forward.

Thanks go out to Jason Z who had the suggestion of going with a script over XML in an earlier journal post.

Here's what an example script file looks like right now. Not really sexy but it is functional and fairly readable as well:

-- Lighting Objects
Scene:SetAmbient(0.2, 0.2, 0.2, 1.0)

Light1 = CLight:new()
Light1:SetName("Light1")
Light1:SetDirection(0.408248,-0.816497,0.408248)
Light1:SetDiffuse(0.0,0.8,0.0,1.0)
Light1:SetSpecular(1.0,1.0,1.0,1.0)
Scene:AddLight(Light1)

Light2 = CLight:new()
Light2:SetName("Light2")
Light2:SetDirection(0.408248,-0.816497,-0.408248)
Light2:SetDiffuse(0.8,0.0,0.0,1.0)
Light2:SetSpecular(1.0,1.0,1.0,1.0)
Scene:AddLight(Light2)

-- Camera
Camera = CCamera:new()
Camera:SetPosition(6.0,3.0,5.0)
Camera:SetLookAt(2.0,0.0,5.0)
Camera:SetUp(0.0,1.0,0.0)
Camera:SetView(45.0,0.1,20.0)
Scene:SetCurrentCamera(Camera)

------------- Game Objects

-- General Input Handler
Object1 = CGameObject:new()
Object1:SetName("General")
Object1:SetEnabled(true)

Script1 = Scene:RequestScript("../../data/HelloWorld.lua")

InputListen1 = CInputListener:new()
InputListen1:SetScript(Script1)
Object1:SetInputListener(InputListen1)

Scene:AddObject(Object1)

-- Duck Model Object
Object2 = CGameObject:new()
Object2:SetName("Duck")
Object2:SetEnabled(true)

-- Create Positionable
Positionable1 = CPositionable:new()
Positionable1:SetPosition(2.0,0.0,5.0)
Positionable1:SetRotation(0.0,0.0,0.0)
Positionable1:SetScale(1.0,1.0,1.0)
Object2:SetPositionable(Positionable1)

-- Load Resources
Material1 = Scene:RequestMaterial("Metal",64.0,1.0,1.0,1.0,1.0)
Texture1 = Scene:RequestTexture("../../data/duckCM.tga")
Texture2 = Scene:RequestTexture("../../data/hello2.tga")
Shader1 =
Scene:RequestShader("MVPLight","../../data/StandardMVP.v.glsl","../../data/Lighting.f.glsl")
Mesh1 = Scene:RequestMesh("../../data/duck.dae")
Mesh1:SetMaterial(Material1)

-- Create Renderable
Renderable1 = CRenderable:new()
Renderable1:SetTexture(0,Texture1)
Renderable1:SetTexture(1,Texture2)
Renderable1:SetShader(Shader1)
Renderable1:SetMesh(Mesh1)
Renderable1:SetWireFrame(false)

Object2:SetRenderable(Renderable1)
Scene:AddObject(Object2)

-- Box Model
Object3 = CGameObject:new()
Object3:SetName("Box")
Object3:SetEnabled(true)

-- Create Positionable
Positionable2 = CPositionable:new()
Positionable2:SetPosition(-2.0,0.0,5.0)
Positionable2:SetRotation(0.0,0.0,0.0)
Positionable2:SetScale(1.0,1.0,1.0)
Object3:SetPositionable(Positionable2)

-- Load Resources
Material2 = Scene:RequestMaterial("Metal",64.0,1.0,1.0,1.0,1.0)
Texture3 = Scene:RequestTexture("../../data/test.png")
Texture4 = Scene:RequestTexture("../../data/hello2.tga")
Shader2 =
Scene:RequestShader("MVPLight","../../data/StandardMVP.v.glsl","../../data/Lighting.f.glsl")
Mesh2 = Scene:RequestMesh("../../data/test.x")
Mesh2:SetMaterial(Material2)

-- Create Renderable
Renderable2 = CRenderable:new()
Renderable2:SetTexture(0,Texture3)
Renderable2:SetTexture(1,Texture4)
Renderable2:SetShader(Shader2)
Renderable2:SetMesh(Mesh2)
Renderable2:SetWireFrame(false)

Object3:SetRenderable(Renderable2)
Scene:AddObject(Object3)

-- Overlay Test Object
Object4 = CGameObject:new()
Object4:SetName("Overlay")
Object4:SetEnabled(true)

-- Create Positionable
Positionable3 = CPositionable:new()
Positionable3:SetPosition(0.0,0.0,0.0)
Positionable3:SetRotation(0.0,0.0,0.0)
Positionable3:SetScale(1.0,1.0,1.0)
Object4:SetPositionable(Positionable3)

-- Load Resources
Texture5 = Scene:RequestTexture("../../data/hello1.tga")
Texture6 = Scene:RequestTexture("../../data/hello2.tga")
Shader3 =
Scene:RequestShader("Ortho","../../data/StandardMVP.v.glsl","../../data/NoLighting.f.glsl")
Quad1 = CQuad:new(0.0,0.0,1.0,1.0,0.0,0.0,1.0,1.0)

-- Create Renderable
Renderable3 = CRenderable:new()
Renderable3:SetTexture(0,Texture5)
Renderable3:SetTexture(1,Texture6)
Renderable3:SetShader(Shader3)
Renderable3:SetQuad(Quad1)
Renderable3:SetWireFrame(false)
Renderable3:SetOrthogonal(true)

Object4:SetRenderable(Renderable3)
Scene:AddObject(Object4)

0 likes 2 comments

Comments

JTippetts
Lua's table functionality can be pretty powerful in cases such as what you are going for here. I've found it useful to specify entities as tables of data that are consumed by a function to produce the objects in your game/scene. So, for instance, instead of the sequence

[color=#1C2837][size=2][color=#660066]Light2[/color][color=#000000] [/color][color=#666600]=[/color][color=#000000] [/color][color=#660066]CLight[/color][color=#666600]:[/color][color=#000088]new[/color][color=#666600]()[/color][color=#000000]
[/color][color=#660066]Light2[/color][color=#666600]:[/color][color=#660066]SetName[/color][color=#666600]([/color][color=#008800]"Light2"[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Light2[/color][color=#666600]:[/color][color=#660066]SetDirection[/color][color=#666600]([/color][color=#006666]0.408248[/color][color=#666600],-[/color][color=#006666]0.816497[/color][color=#666600],-[/color][color=#006666]0.408248[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Light2[/color][color=#666600]:[/color][color=#660066]SetDiffuse[/color][color=#666600]([/color][color=#006666]0.8[/color][color=#666600],[/color][color=#006666]0.0[/color][color=#666600],[/color][color=#006666]0.0[/color][color=#666600],[/color][color=#006666]1.0[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Light2[/color][color=#666600]:[/color][color=#660066]SetSpecular[/color][color=#666600]([/color][color=#006666]1.0[/color][color=#666600],[/color][color=#006666]1.0[/color][color=#666600],[/color][color=#006666]1.0[/color][color=#666600],[/color][color=#006666]1.0[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Scene[/color][color=#666600]:[/color][color=#660066]AddLight[/color][color=#666600]([/color][color=#660066]Light2[/color][color=#666600])[/color][color=#000000]

[/color][color=#666600]--[/color][color=#000000] [/color][color=#660066]Camera[/color][color=#000000]
[/color][color=#660066]Camera[/color][color=#000000] [/color][color=#666600]=[/color][color=#000000] [/color][color=#660066]CCamera[/color][color=#666600]:[/color][color=#000088]new[/color][color=#666600]()[/color][color=#000000]
[/color][color=#660066]Camera[/color][color=#666600]:[/color][color=#660066]SetPosition[/color][color=#666600]([/color][color=#006666]6.0[/color][color=#666600],[/color][color=#006666]3.0[/color][color=#666600],[/color][color=#006666]5.0[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Camera[/color][color=#666600]:[/color][color=#660066]SetLookAt[/color][color=#666600]([/color][color=#006666]2.0[/color][color=#666600],[/color][color=#006666]0.0[/color][color=#666600],[/color][color=#006666]5.0[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Camera[/color][color=#666600]:[/color][color=#660066]SetUp[/color][color=#666600]([/color][color=#006666]0.0[/color][color=#666600],[/color][color=#006666]1.0[/color][color=#666600],[/color][color=#006666]0.0[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Camera[/color][color=#666600]:[/color][color=#660066]SetView[/color][color=#666600]([/color][color=#006666]45.0[/color][color=#666600],[/color][color=#006666]0.1[/color][color=#666600],[/color][color=#006666]20.0[/color][color=#666600])[/color][color=#000000]
[/color][color=#660066]Scene[/color][color=#666600]:[/color][color=#660066]SetCurrentCamera[/color][color=#666600]([/color][color=#660066]Camera[/color][color=#666600])[/color][/size][/color]

I might set it up as:

[code]

scene=
{
{name="Light1", type=CLight, direction={0.408248, -0.816497, 0.408248}, diffuse={0,0.8,0,1}, specular={1,1,1,1},
{name="Camera", type=CCamera, position={6.0,3.0,5.0}, lookat={2.0,0.0,5.0}, up={0,1,0}, view={45,0.1,20}
}

[/code]

then write code to parse these types of table declarations, and create the appropriate object. This saves a LOT of typing, and provides conciseness and better human-readability. An entire scene or sub-scene can be grouped in a single table and parsed as a whole, and you can even nest descriptors for parent-child relationships.
February 23, 2011 03:07 AM
Jason Z
Another nice feature is that you can have your Lua code do some processing of its own before sending the object/scene data to C++. For example, if you add 10 texture files in a particular folder, you can use Lua to load them all up without having to change your code (assuming you have a specific texture folder).

The other really nice thing is that if you do some game loop logic in Lua, you can also have tables as objects and then dynamically set functions as the update function for the object. This also simplifies quite a few scenarios, and makes it almost like a plugin system. Its pretty cool :)
February 23, 2011 06:22 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement