Advanced Authoring - LabTALK - plug-in SDK

DVD-lab allows creating plug-ins in different programming languages. The compiled plug-ins have extension *.cplg and can be located in the folder Extras - Script. They will appear in the Plug-ins-Script tab of assets. The plug-in SDK calls directly the same commands that are used in lab-TALK therefore you need some knowledge how lab-TALK works. The major benefit of the compile cplg plug-in is speed.

A typical example is Fire plug-in:

The Fire plug-in started out as lab-TALK script, but due to the large number of pixel operations it was later translated to C++ and compiled to fire.cplg to speed it up.

Note: Plug-ins are run when dropped to Menu or Connection window.

SDK

A cplg plug-in is a normal windows dll (renamed with extension cplg).

Note: We will use c++ for all our plug-in example. But because of the simplicity of API, it can be done also in other languages.

There are just two API functions:

Command Parameters and Usage
PLUGINDLL_API char* PL_GetAbout(void) Returns description about the plug-in. It will appear if user double-clicks on the plug-in in assets.
PLUGINDLL_API void PL_RunScript(PLCallBack pCallback,HWND hWnd) Entry point that is called when plug-in is dropped on object. It gives your plug-in access to DVD-lab callback function and sends the hWnd of the main DVD-lab window.
DLL export definition
#define PLUGINDLL_API extern "C" __declspec(dllexport)

PLCallback definition

PLCallback is the main and only callback function that you call from the plug-in.
code Parameters and Usage
typedef void (*PLCallBack)
(char* sName,
_PLVariable *result,
_PLVariable *param1,
_PLVariable *param2,
_PLVariable *param3,
_PLVariable *param4);

sName - the name of the DVD-lab function (that is identical to the labTALK function.)
result - result of the function
param1 .. param4 - input parameters of function

PLVariable definition

Object commands gives acces to a specific object in a menu (therefore menu number is always one of the parameter).

Command Parameters and Usage
struct _PLVariable
{
int m_nVariableType;
float m_fValue;
int m_nValue;
char* m_sValue;
};

m_nVariableType - type of variable, can be one of the:
  • #define typeVariableInt 0
  • #define typeVariableFloat 1
  • #define typeVariableString 2

depending on the type, the m_fValue, m_nValue or m_sValue are used

Example

Here is example how to access the labTALK function ObjectGetCurSel(nMenu)

Listing 1

int nMenu = 1;

_PLVariable param1;
param1.m_nVariableType = typeVariableInt;
param1.m_nValue = nMenu;
param1.m_sValue = NULL;


_PLVariable ParamResult;

pCallback("ObjectGetCurSel",&ParamResult,&param1,NULL,NULL,NULL);

int objectcount = ParamResult.m_nValue;

All labTALK functions can be accessed this way. Only the type and number of input parameters vary from function to function.

Helper functions

Since the code of our plugin would get messy if we call all functions as in Listing 1, we can create a helper functions. A most common function is one that has all parameters integer and also return integer.

Listing 2

int CALLSCRIPT(char* sName, int nParam1=0, int nParam2 = 0, int nParam3 =0, int nParam4 = 0 );

int CALLSCRIPT(char* sName, int nParam1, int nParam2, int nParam3, int nParam4 )
{

_PLVariable param1;
param1.m_nVariableType = typeVariableInt;
param1.m_nValue = nParam1;
param1.m_sValue = NULL;

_PLVariable param2;
param2.m_nVariableType = typeVariableInt;
param2.m_nValue = nParam2;
param2.m_sValue = NULL;

_PLVariable param3;
param3.m_nVariableType = typeVariableInt;
param3.m_nValue = nParam3;
param3.m_sValue = NULL;

_PLVariable param4;
param4.m_nVariableType = typeVariableInt;
param4.m_nValue = nParam4;
param4.m_sValue = NULL;

_PLVariable ParamResult;

m_pCallback(sName,&ParamResult,&param1,&param2,&param3,&param4);

return ParamResult.m_nValue;
}

Having defined this function we can then substitute the Listing 1 with:

int objectcount = CALLSCRIPT("ObjectGetCurSel",nMenu)

We can also define directly the ObjectGetCurSel to even more simplify entering the commands. We will get:

#define ObjectGetCurSel(nMenu) (CALLSCRIPT("ObjectGetCurSel",nMenu))

int objectcount = ObjectGetCurSel(nMenu);

This way we can define all labTALK functions that we need. Of course some labTALK functions require string as input parameter so we would need to define another helper function that allow for this:

Listing 3

// another version of helper, second param is char

int CALLSCRIPT2(char* sName, int nParam1=0, char* chParam2 = NULL, int nParam3 =0, int nParam4 = 0 );

int CALLSCRIPT2(char* sName, int nParam1, char* chParam2, int nParam3, int nParam4 )
{
_PLVariable param1;
param1.m_nVariableType = typeVariableInt;
param1.m_nValue = nParam1;
param1.m_sValue = NULL;

_PLVariable param2;
param2.m_nVariableType = typeVariableString;
param2.m_nValue = 0;
strcpy(param2.m_sValue,chParam2);

_PLVariable param3;
param3.m_nVariableType = typeVariableInt;
param3.m_nValue = nParam3;
param3.m_sValue = NULL;

_PLVariable param4;
param4.m_nVariableType = typeVariableInt;
param4.m_nValue = nParam4;
param4.m_sValue = NULL;

_PLVariable ParamResult;

m_pCallback(sName,&ParamResult,&param1,&param2,&param3,&param4);

return ParamResult.m_nValue;

}

This helper function can be used to define for example MenuAdd:

#define MenuAdd(bIsVmg,sName,bOpen) (CALLSCRIPT2("MenuAdd",bIsVmg,sName,bOpen))

This way you can define in your *.h file all functions in labTALK so they can be used in the exact same syntax as in labTALK script.

Get Image buffer

One "secret" command that is not described in Lab-TALK (because it has no meaning there)
ImgGetRGBABuffer returns the pointer to the RGBA buffer

Be careful what you writing to it, because you can crash DVD-lab if you write beyond the boundaries
The size of buffer is ImgGetWidth(imgNum)*ImgGetHeight(imgNum)*4

Note: The BYTE is defined as unsigned char.

Listing 4

#define ImgGetRGBABuffer(imgNum) (CALLSCRIPT("ImgGetRGBABuffer",imgNum))
#define ImgGetWidth(imgNum) (CALLSCRIPT("ImgGetWidth",imgNum))
#define ImgGetHeight(imgNum) (CALLSCRIPT("ImgGetHeight",imgNum))
#define ImgGrabObject(imgNum,nMenu,nObject) (CALLSCRIPT("ImgGrabObject",imgNum,nMenu,nObject))
#define ImgSetToObject(imgNum,nMenu,nObject) (CALLSCRIPT("ImgSetToObject",imgNum,nMenu,nObject))
#define MenuGetCurSel() (CALLSCRIPT("MenuGetCurSel"))
#define ObjectGetCurSel(nMenu) (CALLSCRIPT("ObjectGetCurSel",nMenu))

// get current menu and current object

int menu = MenuGetCurSel();
int object= ObjectGetCurSel(menu);

ImgGrabObject(1,menu,object);
// imgNum = temporary image buffer 1,2 or 3

BYTE* pBuffer = (BYTE*)ImgGetRGBABuffer(1);

if (pBuffer==NULL)
return;

int imgW = ImgGetWidth(1);
int imgH = ImgGetHeight(1);

for (y=0; y<imgH;y++)
{
for (x=0;x<imgW;x++)
{

BYTE r = pBuffer[y*imgW*4+x*4];
BYTE g = pBuffer[y*imgW*4+x*4+1];
BYTE b = pBuffer[y*imgW*4+x*4+2];
BYTE alpha = pBuffer[y*imgW*4+x*4+3];

// do something with it and then set it back to pBuffer
}
}

//put the buffer to object
ImgSetToObject(1,menu,object);

Full Example

Here is a short example in c++ that when dropped on menu object, it will make all colors negative.

See the source file for plugindll example.

plugindll.cpp
plugindll.h

After compiling it in VC++ the dll was renamed with *.cplg extension and moved to folder \Extras\Script\ in DVD-lab. Then it can be used as any other script.

Note: You can create asset thumbnail image for the plugin in 256 color bmp format, that has to have the same name (in our example: plugindll.bmp), be in the same folder and have dimensions 85x60