IRI SDK Examples
From IRIDAS Online Documentation
Contents |
Overview
This text discusses the C++ examples shipped with the IRI SDK. You can get the SDK by contacting us.
IRI can be used in two fundamental ways:
IRI Client
You implement an IRI Client when you want to connect to a running instance of an IRIDAS product such as FrameCycler. The first step is to establish a connection with a currently running application. You can do this by either using a known name ("localhost" for example), or by invoking the IRI Discover functionality to scan the network for running IRIDAS servers. You can then select the right server by querying its capabilities.
A typical scenerio for implementing an IRI Client is to connect to a running instance of FrameCycler, push a new timeline to it and control its playback.
IRI Server
In some cases you want to implement an IRI Server to offer services to other applications. All IRIDAS products are IRI Servers.
A typical scenario for implementing an IRI Server is when you want to offer .Look exchange and rendering capabilities to SpeedGrade OnSet.
First Steps: IRI Client
When implementing an IRI Client, the first step is to connect to an IRI Server such as FrameCycler. This is easiest, when you know the name or IP Address of the network node. If you want to connect to a locally running server, use Localhost as address. By default all IRIDAS products accept local IRI connections, but not connections from another computer. See this page for more information on these security settings.
In order to connect to a know IRI Server, you have to write code similar to this one:
SIrexIRemote* psRemote = psQueryRemoteInterface();
// Get an interface to the remote functionality
if (psRemote == NULL)
return false;
// Remote functionality not available (this should never happen)
// let's try to initiate the connection:
if (!psRemote->bConnect("localhost", 8800))
{
printf("Connection failed.\n\n");
return false;
}
// Now we have to wait until we are actually connected:
IRBOOL bConnected = IRFALSE;
int iTimeOut = 100;
while (iTimeOut-- > 0)
{
psRemote->GetStatus(&bConnected, NULL);
if (bConnected)
break;
Sleep(100);
}
if (!bConnected)
{
printf("Timeout connecting to localhost\n");
return false;
}
// Now we are connected
After the connection has succeeded, we can now control the server by sending commands to it:
psRemote->SendCommand("Remote.CommandLine", pszCommandLine);
psRemote->Disconnect();
return true;
First Steps: IRI Server
An IRI Server offers services to IRI clients. For this, an IRI server offers certain capabilities such as .Look exchange or timeline rendering.
At current time the following capability codes are defined:
IREX_CAPABILITY_PLAYBACK IREX_CAPABILITY_RENDERING IREX_CAPABILITY_LOOK_EXCHANGE
The capability flags are used by IRIDAS products to list the correct nodes in the network rendering or .Look dialogs.
In order to offer .Look exchange services, the following steps have to be implemented.
First, we have to get the look interface from the library. This interface will be used to manipulate .Look files that we receive.
Note that we have to provide the path to a valid license file ("license.irlc", the path to the IRIDAS Shaders directory ("Shaders") and the path to the directory containing the look-up-tables ("LUTs").
char szError[256];
szError[0] = 0;
SIrexILook* psLook = psQueryLookInterface("license.irlc", "Shaders", "LUTs", szError);
if (psLook == NULL)
{
printf("Could not initialize library: %s\n", szError);
return 0;
}
After the look library is initialized, you can now offer .Look exchange services using the remote interface:
#define PORT 8800
SIrexIRemote* psRemote = psQueryRemoteInterface();
if (psRemote == NULL)
return false;
// Remote functionality not available (this should never happen)
if (!psRemote->bListenOnPort(PORT,
LOCALHOST_ONLY,
IREX_CAPABILITY_LOOK_EXCHANGE,
"Name of Your Device"))
{
printf("Could not start listening on port %d\n", PORT);
return false;
}
printf("Listening for commands on port %d\n", PORT);
You should now enter in a loop that looks for new commands to be sent to you:
char szCommand[256];
szCommand[0] = 0;
char* pszBuffer = new char [256];
IRUINT nBufferSize = 256;
while (true)
{
IRUINT nSize = nBufferSize;
IRBOOL bSuccess = psRemote->bReceiveCommand(szCommand, pszBuffer, &nSize);
if (!bSuccess && nSize > 0)
{
//buffer too small
delete [] pszBuffer;
pszBuffer = new char [nSize];
nBufferSize = nSize;
bSuccess = psRemote->bReceiveCommand(szCommand, pszBuffer, &nSize);
}
if (bSuccess)
{
// Handle commands
}
}
There are now two commands that you have to react on:
- RemoteIntegration.RequestReferenceFrame
- RemoteIntegration.SetLook
RequestReferenceFrame
When you receive this command, you should return a reference frame (the current picture on your device) to the client. You do that by sending the UNC path to a valid image file back to the client (on other platforms, use the SMB:// syntax - the format is automatically translated for each platform).
printf("Received command %s\n", szCommand);
if (stricmp(szCommand, "RemoteIntegration.RequestReferenceFrame") == 0)
{
printf("Sending response with location (path)\n");
psRemote->SendCommand("RemoteIntegration.ReferenceFramePath", "\\\\MACHINE\\Snapshot\\Path.jpg");
}
Note: It is also a good idea to send back the .Look that was applied to the reference frame in case the user has altered it in your server/device. The following code assumes that you have set the internal .Look buffer of the psLook interface using psLook->bLookFromString. See the SDK examples (Server) for complete details.
psLook->bGetLookString(pszLookBuffer, 0, 0, &nSize);
psRemote->SendCommand("RemoteIntegration.SetLook", pszLookBuffer);
SetLook
A client sends this command to change the .Look file on your device. Please note - in IRI Look Exchange communication the LUT part of a .Look file is stripped out to save transmission time. Only the XML meta data part of the .Look file is sent. The pxLook interface allows you to render a LUT from the meta data to whatever format you require.
if (stricmp(szCommand, "RemoteIntegration.SetLook") == 0)
{
printf("Setting .Look: ");
if (psLook->bLookFromString(pszBuffer))
{
// We have now created an internal .Look from the received command
printf("Success\nRendering LUT...\n");
WriteLUT(psLook, "test.cube");
}
else
printf("Failed to create .Look from command\n");
}
Note that the WriteLUT function is something that you have to write to render your particular LUT format. Here's an example:
void WriteCube(SIrexILook* ps, const char* pszFileName)
{
printf("Rendering 3D LUT\n");
// Let's render a 16 x 16 x 16 float LUT
float* pfLUT = new float [16 * 16 * 16 * 3];
// We ask the pxLook interface for a 16 note LUT
ps->ReadLook3DLUT(16, pfLUT, "");
printf("Writing .cube file\n");
FILE* pfFile = fopen(pszFileName, "w");
fprintf(pfFile,
"LUT_3D_SIZE 16\n"
"DOMAIN_MIN 0 0 0\n"
"DOMAIN_MAX 1 1 1\n");
for (int i = 0; i < 16 * 16 * 16; i++)
fprintf(pfFile, "%g %g %g\n", pfLUT[i * 3], pfLUT[i * 3 + 1], pfLUT[i * 3 + 2]);
fclose(pfFile);
}
More Information
For more information, please see the SDK example files.
