Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Lua

Kigs Framework Introduction (7/8) - Lua Binding

2.09/5 (3 votes)
1 Mar 2023MIT8 min read 13K  
A multi purpose, cross-platform, free and Open Source C++ framework. Lua Binding feature
In this article, we will detail how Lua can access Kigs framework features (CoreModifiable attributes / methods ...) and how Kigs framework can access Lua features.

Image 1

Table of Contents

Introduction

In this article, we will see how to enhance the Kigs framework, and particularly CoreModifiable classes with Lua. 

Lua (5.3.5) programming language is embedded in the framework here:

With minor changes for Universal Windows Platform build.

The same directory also contains LuaIntf: A binding between C++11 and Lua language:

To learn more about Lua, look here: https://www.lua.org.

Bound Framework Classes and Methods 

Here is the list of bound classes and their accessible methods from Lua:

  • CoreModifiable:

    • name(): Return instance name
    • addItem(CMSP item): Add a CoreModifiable instance smart pointer (CMSP) to another (see CoreModifiable article)
    • removeItem(CMSP item): Remove an instance smart pointer (CMSP) from another (see CoreModifiable article)
    • aggregateWith(CMSP item): Aggregate a CoreModifiable instance smart pointer (CMSP) to another (see CoreModifiable article)
    • removeAggregateWith(CMSP item): Remove an aggregate (see CoreModifiable article)
    • parents(): Get parents list
    • childs() or items(): Get children list
    • getSonsByType(type): Get list of children of given type
    • getSonsByName(name): Get list of children with given name
    • init(): Call CoreModifiable Init
    • uid(): Get instance unique id
    • type(): Get instance exact type
    • isSubType(type): Check if instance is of the given type
    • addAttribute(val): Add a dynamic attribute of the type of the given val (bool, float, string or vector)
    • onEvent(method_name or Lua function,notification_name): Add an observer on notification_name to call method_name or directly Lua function.
    • getByPath(path): Search an instance by path
    • importAsSon(filename): Import the given file and add CoreModifiable tree to calling CoreModifiable instance
    • emit(signal_name): Emit a signal with given name
  • CMSP :

    • get() : get CoreModifiable instance pointed by the smart pointer
  • v2f, v3f and v4f : 2D, 3D or 4D vectors

    • Dot(v1,v2): static method, return dot product of v1 and v2
    • Cross(v1,v2): static method, return cross product of v1 and v2 (not available on v4f)
    • Norm(v1): static method, return norm of v1
    • NormSquare(v1): static method, return squared norm of v1
    • normalize(): normalize vector
    • normalized(): return a copy of the normalized vector
    • copy(): return a copy of the vector
    • members can be accessed with .x, .y, .z (for v3f and v4f), .w (for v4f)
    • vector standard operation : * + - / are also available
  • mat3x4: 3 x 4 matrix (3D transform matrix)

    • setRotationX(angle): Set current matrix to be a X axis rotation matrix of given angle
    • setRotationY(angle): Set current matrix to be a Y axis rotation matrix of given angle
    • setRotationZ(angle): Set current matrix to be a Z axis rotation matrix of given angle
    • preRotateX(angle): Pre rotate current matrix around X axis with given angle
    • preRotateY(angle): Pre rotate current matrix around Y axis with given angle
    • preRotateZ(angle): Pre rotate current matrix around Z axis with given angle
    • postRotateX(angle): Post rotate current matrix around X axis with given angle
    • postRotateY(angle): Post rotate current matrix around Y axis with given angle
    • postRotateZ(angle): Post rotate current matrix around Z axis with given angle
    • setScale(sx,sy,sz): Set current matrix to be a scale matrix with given scale on each axis
    • preScale(sx,sy,sz): Pre scale current matrix with given scale on each axis
    • postScale(sx,sy,sz): Post scale current matrix with given scale on each axis
    • setTranslation(v): Set current matrix to be a translation matrix of given v3f vector
    • preTranslate(v): Pre translate current matrix with given v3f vector
    • postTranslate(v): Post translate current matrix with given v3f vector
    • setRotationXYZ(aX,aY,aZ): Set current matrix to be a rotation matrix with angles aX, aY, aZ. Rotations are applied in order X, then Y, then Z
    • setRotationZYX(aX,aY,aZ): Set current matrix to be a rotation matrix with angles aX, aY, aZ. Rotations are applied in order Z, then Y, then X
    • preRotateXYZ(aX,aY,aZ): Pre rotate current matrix (Rotations are applied in order X, then Y, then Z)
    • preRotateZYX(aX,aY,aZ): Pre rotate current matrix (Rotations are applied in order Z, then Y, then X)
    • postRotateXYZ(aX,aY,aZ): Post rotate current matrix (Rotations are applied in order X, then Y, then Z)
    • postRotateZYX(aX,aY,aZ): Post rotate current matrix (Rotations are applied in order Z, then Y, then X)
    • setIdentity(): Set matrix to identity
    • setNull(): Set each matrix member to 0
    • isIdentity(): Return true if the matrix is identity
    • transformPoint(v): Transform given v3f vector as a point with the current matrix (apply translation)
    • transformPoints(list_of_v): Transform each v3f vector in the given list as a point with current matrix (apply translation)
    • transformVector(v): Transform given v3f vector with current matrix (translation is not applied)
    • transformVectors(list_of_v): Transform each v3f vector in the given list with current matrix (translation is not applied)
    • copy(): Return a copy of the current matrix
  • core:

    • ByName(name): Returns the list of CoreModifiable with the given name
    • ByType(type): Returns the list of CoreModifiable with the given type
    • GetFirstInstanceByName(name): Returns the first CoreModifiable found with the given name
    • GetModule(name): Returns the module (CoreModifiable) with the given name
    • PostNotification(name,sender,data): Post notification with the given name. sender and data are optional CoreModifiable parameters
    • AddAutoUpdate(instance): Add given CoreModifiable instance to auto-update mechanism
    • RemoveAutoUpdate(instance): Remove given CoreModifiable instance from auto-update mechanism
    • SID(string): Return KigsID (unsigned int) for the given string
    • Connect(sender,signal,receiver,slot): Connect CoreModifiable sender's signal to CoreModifiable receiver's slot
    • Disconnect(sender,signal,receiver,slot): Disconnect CoreModifiable sender's signal to CoreModifiable receiver's slot
    • Import(filename): Import filename as CoreModifiable tree and returns CMSP root

Accessing Kigs Framework from Lua

On Lua side, generic functionalities of the framework are available:

Lua
-- create an UIImage instance named logo (get a smart pointer)
local logoSP = CoreModifiable("logo","UIImage")
local logo=logoSP:get()
-- set CoreModifiable attributes directly
logo.Texture = "KigsHD.png"
logo.Dock = {0.5,0.5}
logo.Anchor = {0.5,0.5}
logo.Priority = 10
-- and init logo
logo:init()

CoreModifiable attributes are accessed directly by their name preceded by a dot '.'.

Lua
local rotate = logo.RotationAngle
rotate = rotate + 0.1
logo.RotationAngle = rotate

Bound methods or CoreModifiable methods are accessed the classic Lua way with a ':' ( except for static methods, were '.' should be used ) :

Lua
-- call CoreModifiable method "HelloFromLua" defined on target object 
target:HelloFromLua()

Accessing Lua from Kigs Framework

Executing Lua Code

It's possible to just execute some Lua code from a file in C++ :

C++
auto lua = KigsCore::GetModule<LuaKigsBindModule>();
bool result=lua->ExecuteLuaFile("myCode.lua");

Or to execute some code when importing an XML file by adding a "Lua" item to an instance:

XML
<Lua N="someCode">
-- code is executed when XML file is imported
   local panel=core.GetFirstInstanceByName("panel")
   panel.Color={1.0,0.0,0.0}
</Lua>

or:

XML
<Lua N="someCode" V="#someCode.lua"/>

Add Lua Method to an Instance

In XML, it's also possible to add a Lua function (as a CoreModifiable method) to a CoreModifiable instance:

XML
<Lua N="Click">
   -- here self is the current CoreModifiable
   return function(self)
      local currentColor=self.Color
      self.Color={1.0-currentColor.x,0.0,0.0}
   end
</Lua>

LuaBehaviour Class

The LuaBehaviour class is used to add functionalities to an instance using the Lua language.

Serialization

The easy way to do it is to add this kind of item directly in XML to the targeted instance:

XML
<Inst N="testLua" T="LuaBehaviour" Aggregate="true">
	<Attr N="Script" V="#test.lua"/>
</Inst>

The LuaBehaviour must be added as an aggregate to its parent instance.

Here, the "Script" attribute value is "#test.lua". The starting '#' indicates a filename to load. So here, the "test.lua" file is loaded (if found) and its content is interpreted as Lua.

The code can also be embedded in the XML file as CDATA:

XML
<Inst N="testLua" T="LuaBehaviour" Aggregate="true">
   <Attr N="Script">
   <![CDATA[
local Sample7Script = {} 
Sample7Script.logo=0

function Sample7Script:init()
  local logoSP = CoreModifiable("logo","UIImage")
  self.logo=logoSP:get()
  self.logo.Texture = "KigsHD.png"
  self.logo.Dock = {0.5,0.5}
  self.logo.Anchor = {0.5,0.5}
  self.logo.Priority = 10
	
  self.target:addItem(logoSP)

  self.logo:init()
end

return Sample7Script
  ]]>
  </Attr>
</Inst>

In C++ Code

Of course, LuaBehaviour instance can be created using framework code, the "classic" way :

C++
CMSP behaviour = KigsCore::GetInstanceOf("behaviour", "LuaBehaviour");
behaviour->setValue("Script", "#ScriptOnApp.lua");
// aggregate LuaBehaviour with this
aggregateWith(behaviour);
behaviour->Init();

Lua Side Syntax

Behaviour Code

Lua code must have the following form:

Lua
-- you can call it whatever you want
local behaviourObjectName = { var1 = 0; var2 = "two" } 

-- Insert methods here
function behaviourObjectName:doSomething(param1)
	self.var1 = param1
end

return behaviourObjectName 

The methods "init()", "update(current_time)", "destroy()", "addItem(other)", "removeItem(other)" are called automatically when aggregate is initialized, update...

Adding a CoreModifiable Lua method directly in Lua is possible using WRAP_METHODS table in the object declaration:

Lua
-- reset is wrapped so C++ can call directly the reset method on target object
local Sample7Script = { logo=0; startingTime=0; WRAP_METHODS = {"reset"}; }

-- the reset method 
function Sample7Script:reset(current_time)
   self.startingTime = current_time
end

Or directly by adding a Lua function to the target object in init function:

Lua
function Sample7Script:init()
   -- add reset function to target  
   self.target.reset = function (current_time)
	self.startingTime = current_time
   end
end

So on the C++ side, the Lua reset method can be called like another CoreModifiable method:

C++
// instance is the object aggregated with LuaBehaviour 
instance->SimpleCall("reset",GetApplicationTimer()->GetTime());

Accessing CoreModifiable Instance from LuaBehaviour

LuaBehaviour functions can use self.target to access the CoreModifiable instance aggregated to LuaBehaviour:

Lua
-- create an UIImage instance named logo (get a smart pointer)
local logoSP = CoreModifiable("logo","UIImage")
-- then add logo (smart pointer) to target
self.target:addItem(logoSP)

LuaImporter Class

It's also possible to import CoreModifiable trees created in Lua using LuaImporter class.

In XML, add the following item to import "scene.lua" file and add it in the current XML hierarchy:

XML
<Inst N="lua" T="LuaImporter">
   <Attr N="Script" V="scene.lua"/>
</Inst>

The syntax of a Lua file aimed at import looks like that:

Lua
local result = 
{
   item("itemName1", "itemType1", {attributeName1=0,... }).items(
      item("itemName2", "itemType2", { attributeName1=true, ... } ),
      item("itemName3", "itemType3", { attributeName1=32, ... } ),
      ...
   )
}
return result

"item" keyword creates a CoreModifiable instance. The first two parameters are instance name and instance type, then the list of attributes to initialize with given values.

To add sons to an item, use the ".items" keyword.

In the previous example, itemName2 and itemName3 are sons of itemName1.

As it's Lua code, it's possible to define functions and call them as helpers to create objects with the same type or initialize attributes:

Lua
local specialNode3D = function(name)
	return item(name, "Node3D", {Show=false, IgnoreBBox=true, CollideMask=0}).items(
		item("nodepth", "RenderingCustomizer", {OverrideDepthTest=0, RenderPassMask=16})	
	)
end
local result = 
{
   specialNode3D("node1").items(
      specialNode3D("node2"),
      specialNode3D("node3")
   )
}
return result

It's also possible to import an item from another XML or Lua file:

Lua
local result = 
{
   item("itemName1", "itemType1", {Param1=-1, Param2=-1}).items(
      xml("item2FromXML", "item2.xml",{Param1 = 5}),
      lua("item3FromExternLua", "item3.lua"),
   )
}
return result

Or to reference an already loaded item with the "ref" keyword: 

Lua
 item("itemName1", "itemType1", {Param1=-1, Param2=-1}).items(
   ref("refName", "refType")
)

And finally, it's also possible to connect a signal and slot:

Lua
item("button", "UIButtonImage", {Priority=10, UpTexture="Up.png", 
      DownTexture="Down.png",Dock={0.9,0.1}}).items(
      connect("this","ClickUp" ,"../UIItem:panel","Click")
   )

And to add an instance to auto-update mechanism:

Lua
item("itemName1", "itemType1", {attributeName1=0,... }).items(core.AddAutoUpdate)

Find all the sample code from this wiki section in Sample7 project (browse the code).

Already Published in this Series

  1. Kigs Framework Introduction (1/8) - Overview
  2. Kigs Framework Introduction (2/8) - CoreModifiable
  3. Kigs Framework Introduction (3/8) - Attributes
  4. Kigs Framework Introduction (4/8) - Methods
  5. Kigs Framework Introduction (5/8) - CoreItem
  6. Kigs Framework Introduction (6/8) - Signal, Slot, Notification
  7. Kigs Framework Introduction (7/8) - Lua Binding
  8. Kigs Framework Introduction (8/8) - Data Driven Application

History

  • 5th March, 2020: Initial version
  • 17th June, 2020 : Added final article of the series
  • 1st March, 2023 : Article updated after framework refactory

License

This article, along with any associated source code and files, is licensed under The MIT License