The technology behind InstaMAT is also available as C++ SDK. This means that you can integrate our technology into your app or native pipeline to dynamically execute Atoms and Elements.
There is no difference between the InstaMAT C++ SDK that is available to our customers and partners and what we're using internally to build our own applications and integrations.
This means that with the InstaMAT C++ SDK you will be able to leverage InstaMAT's powerful processing technology in the same way that the creators are doing it!
The InstaMAT C++ SDK is only distributed upon request. If you would like to request access to the SDK, please create a support request within the InstaMAT License Management Web App.
We are thrilled that you want to integrate our SDK into your product. If you have any questions or need code-level support, please don't hesitate to get in touch with us through the Abstract Community. Integrating our SDK is a straightforward and fun task. There are no external dependencies on heavyweight runtimes like .NET and great care has been taken to create a modern and clean API with little in your way to creating complex optimizations.
InstaMAT SDK for Windows has been built using Visual Studio 2022 on Windows 10 and requires the installation of the Visual C++ Redistributables for Visual Studio 2022. If you have already installed Visual Studio 2022 or later on your workstation, the installation of the Visual Studio 2022 redistributables is not necessary.
InstaMAT SDK for macOS has been built using Xcode 14.3 on macOS Ventura.
The InstaMAT SDK is a 64-bit dynamically linked library that is loaded and linked into your application during runtime.
Before integrating the InstaMAT SDK into your technology, it is important to ensure that your workstation is setup to run the InstaMAT SDK. The best way to do this is by building and running one of the bundled sample projects.
The InstaMAT SDK Sample Application included in the distribution demonstrates several core tasks to integrate the InstaMAT SDK into your application. The following topics are covered by this sample project:
The application uses C++11 and compiles on both PC Windows and macOS.
To generate the platform-specific project files, CMake 3.5 or higher is required.
There are no dependencies to building the InstaMAT sample project besides the InstaMAT SDK itself.
Make sure to copy the InstaMAT SDK binaries into the working directory of the compiled InstaMAT SDK Sample Application.
To generate the Visual Studio project files, open a command-line in the InstaMATSDKSample
directory and execute the following commands:
mkdir build
cd build
cmake -G "Visual Studio 17 2022"
To generate the XCode project files on macOS, Visual Studio 17 2022
can be replaced with the installed XCode version in the command above.
Prior to compiling the InstaMAT SDK Sample Application, please review the tutorial-specific configuration at the top of the file InstaMATSDKSample.cpp
. The INSTAMAT_PATH
define is required by the sample application to locate the built-in MAT Library. If it is not setup correctly, the sample will not be able to execute. This could be set up as following:
#define INSTAMAT_PATH "C:\\Program Files\\InstaMAT Studio"
The first thing you have to do is to install our header files in a location that is accessible by your project. Once that is done you can include our C++ header files in your C++ source file:
#include "InstaMATAPI.h"
Once you have included our header you will be able to load the InstaMAT SDK's dynamic library.
If your project does not have its own DLL loading functions you can use the platform-agnostic macro the InstaMAT SDK provides. However, for these to work you will have to #include <Windows.h>
on Windows platforms or #include <dlfcn.h>
on macOS platforms.
To load the InstaMAT SDK with the InstaMAT DLL macros, add the following lines to the initialization of your application:
#if defined(WIN32)
INSTAMAT_DLHANDLE dllHandle = INSTAMAT_DLOPEN(TEXT(INSTAMAT_LIBRARY_NAME));
#else
INSTAMAT_DLHANDLE dllHandle = INSTAMAT_DLOPEN(INSTAMAT_LIBRARY_NAME);
#endif
InstaMAT::IInstaMAT *instaMAT = nullptr;
if (dllHandle != nullptr)
{
fprintf(stdout, "Loaded InstaLOD Library\n");
pfnGetInstaMAT pGetInstaMAT = (pfnGetInstaMAT)INSTAMAT_DLSYM(dllHandle, "GetInstaMAT");
if (!pGetInstaMAT(INSTAMAT_API_VERSION, &instaMAT))
{
fprintf(stderr, "ERROR: Failed to get InstaMAT SDK API. Invalid SDK version?\n");
return;
}
}
For more information on how to load the InstaMAT DLL, please refer to the function OpenInstaMATSDK
that is defined in the InstaMAT SDK Sample Application.
If you are using a custom build of the SDK with customized licensing, you can skip this step!
Before using any public methods of the InstaMAT API, you will have to initialize the licensing subsystems. Using the following code, you can initialize your SDK build:
if (!instaMAT->InitializeAuthorization("InstaMATSDK", nullptr))
{
fprintf(stderr, "ERROR: Failed to initialize authorization module:\n%s\n", instaMAT->GetAuthorizationInformation());
}
If you have already authorized your workstation, InstaMAT will automatically load the license from the OS shared preferences path.
On Windows the shared license path is C:\ProgramData\InstaMAT\
, and on macOS the path is /Users/Shared/InstaMAT/
.
Otherwise you can authorize your workstation using your license information from within your application:
if (!instaMAT->AuthorizeMachine("username", "password"))
{
fprintf(stderr, "ERROR: Failed to acquire license:\n%s\n", instaMAT->GetAuthorizationInformation());
return;
}
// output current license information to console
fprintf(stdout, "%s\n", instaMAT->GetAuthorizationInformation());
fprintf(stdout, "Is host authorized: %s\n", instaMAT->IsHostAuthorized() ? "YES" : "NO");
Once the license has been verified, the InstaMAT SDK can be initialized:
if (!instaMAT->Initialize(IInstaMAT::BackendTypeGPU, IInstaMAT::BackendFlagNoPlugins))
{
fprintf(stderr, "ERROR: Failed to initialize InstaMAT.\n");
}
The InstaMAT SDK is hardware-accelerated and executes code on the graphics card. If no GPU is available, e.g. on a virtual machine, a software backend implementation can be used on Windows as fallback.
It's recommended to always load the built-in MAT Library that contains many hundreds of useful nodes. The library can be loaded from the InstaMAT Studio installation directory by invoking IInstaMAT::LoadPackagesAtPath
:
#if defined(WIN32)
const char *const instaMATPath = "C:\\Program Files\\InstaMAT Studio\\Environment";
#elif defined(__APPLE__)
const char *const instaMATPath = "/Applications/InstaMAT Studio.app/Contents/Resources/Environment";
#endif
if (instaMAT->LoadPackagesAtPath(instaMATPath, /*persistentResources:*/ true, /*systemLibrary:*/true) == 0u)
{
fprintf(stderr, "ERROR: Failed to load the system library from '%s'.\n", instaMATPath);
}
User packages can be loaded into the library through the same functions as the system library itself:
IInstaMAT::LoadPackage
loads a package from the specified file path into the library.IInstaMAT::LoadPackagesAtPath
loads all packages from the specified directory into the library.If direct access to package objects is required, the function IInstaMAT::AllocPackageFromFile
can be used instead. The following code sample loads a package and logs information about all graphs in the package.
First load the package from the file system and verify if it has been loaded successfully:
const char *const kPackagePath = "InstaMAT SDK Sample.IMP";
IGraphPackage* const graphPackage = instaMAT->AllocPackageFromFile(kPackagePath, /*persistentResources:*/ true);
if (graphPackage == nullptr)
{
fprintf(stderr, "ERROR: Failed to load GraphPackage from path='%s'\n", kPackagePath);
return;
}
An array that contains all package objects can then be retrieved by invoking IInstaMAT::GetGraphObjectsInPackage
:
IGraphObject** graphObjects;
if (!instaMAT->GetGraphObjectsInPackage(*graphPackage, &graphObjects))
{
fprintf(stderr, "ERROR: Failed to iterate GraphObjects in package.\n");
return;
}
Finally, the package objects can be iterated. The method IGraphObject::AsGraph
can be used to convert a graph object to an IGraph
instance:
for (auto it = graphObjects; *it != nullptr; it++)
{
IGraphObject* const graphObject = *it;
if (IGraph* const graph = graphObject->AsGraph())
{
fprintf(stdout, "Graph: Type=%s Name=%s\n", graph->GetGraphTypeString(), graphObject->GetName(/*friendlyName:*/ true));
}
}
Both System Library and User Library graphs can be easily executed through the InstaMAT SDK. The following example illustrates how to render a graph without changing its parameters.
In Step 6, a graph is located by iterating over the objects in a package. Alternatively, after a package has been loaded into the library, its graphs can be accessed through the convenient function IInstaMAT::GetGraphByName
. Here, it is used to find the Voronoi
graph from the built-in library:
const char* const kTestGraphName = "Voronoi";
IGraph* const graph = instaMAT->GetGraphByName(kTestGraphName, 0u);
if (graph == nullptr)
{
fprintf(stderr, "ERROR: Failed to get graph with name='%s'\n", kTestGraphName);
}
After locating the graph, an instance of the IElementExecution
class needs to be allocated.
The
IElementExecution
is the session that allows executing a graph on the GPU. It interfaces with the GPU so it should only be used on the thread that was used to initialize the InstaMAT SDK.
The following code snippet sets up a unique pointer to ensure that the execution is always properly deallocated, no matter which code-path the application takes to exit:
std::unique_ptr<IElementExecution, std::function<void(IElementExecution*)>> execution(instaMAT->AllocElementExecution(), [instaMAT](IElementExecution* ptr) { instaMAT->DeallocElementExecution(ptr); });
if (execution == nullptr)
{
fprintf(stderr, "ERROR: Failed to allocate element execution\n");
}
Then, an instance of Voronoi
needs to be created by invoking IElementExecution::CreateInstance
. The following code creates a grayscale permutation of the graph by setting createGrayscalePermutation
to true:
const bool createGrayscalePermutation = true;
if (!execution->CreateInstance(*graph, createGrayscalePermutation ? ElementExecutionFlags::GrayscalePermutation : ElementExecutionFlags::None))
{
fprintf(stderr, "ERROR: Failed to instance graph in execution session with name='%s'\n", graph->AsObject()->GetName(/*friendlyName:*/ true));
}
After all required objects have been allocated, the execution of the Voronoi
can be configured. The following line instructs InstaMAT to execute the graph at a resolution of 1024x1024 pixels whilst using a 16bpp format:
execution->SetFormat(1024u, 1024u, ElementExecutionFormat::Normalized16);
A callback allows reporting progress during the execution. Additionally, the execution progress delegate can return false
to abort the execution as soon as possible.
const auto fnProgressDelegate = [](const IGraph& graph, const float progress) -> bool {
fprintf(stdout, " > Progress for %s : %.2f%%\n", graph.AsObject()->GetName(/*friendlyName:*/ true), progress * 100.0f);
return true;
};
if (!execution->Execute(fnProgressDelegate))
{
fprintf(stderr, "ERROR: Failed to execute graph in execution session with name='%s'\n", graph->AsObject()->GetName(/*friendlyName:*/ true));
}
After a graph has been executed, the resulting data outputs can be saved on disk. The following sample code extends the code from Step 7 with the export of the image outputs of the Voronoi
graph.
The output parameters of the graph instance can be iterated by invoking IGraph::GetParameterCount
:
for (uint32 outputParameterIndex = 0u; outputParameterIndex < execution->GetInstance()->GetParameterCount(IGraph::ParameterTypeOutput); outputParameterIndex++)
{
const IGraphVariable* const variable = execution->GetInstance()->GetParameterAtIndex(outputParameterIndex, IGraph::ParameterTypeOutput);
// NOTE: for instances in element graphs, all AtomImage* types get automatically converted to ElementImage* types
if (variable->GetVariableTypeValue() == IGraphVariable::TypeElementImage ||
variable->GetVariableTypeValue() == IGraphVariable::TypeElementImageGray)
{
if (IImageSampler* const imageSampler = execution->AllocImageSamplerForOutputParameter(*variable, variable->GetColorSpaceTypeValue() == IGraphVariable::ColorSpaceTypeSRGB))
{
const String outputName = graph->AsObject()->GetName(/*friendlyName:*/ true) + String(".") + variable->AsObject()->GetName(/*friendlyName:*/ true) + String(".png");
if (imageSampler->WritePNG(outputName.c_str(), /*bpp:*/ 16u, /*allowDithering:*/ false))
{
fprintf(stdout, "Wrote output image to path='%s'\n", outputName.c_str());
}
else
{
fprintf(stderr, "ERROR: Failed to write output image to path='%s'\n", outputName.c_str());
}
instaMAT->DeallocImageSampler(imageSampler);
}
}
}
You're now ready to explore the vast amount of features present in InstaMAT SDK. The following links provide further information and resources that help you on your journey with InstaMAT.