Skip to content

Integration in C or Cpp

Loic Royer edited this page May 29, 2015 · 4 revisions

C/C++ integration

The C/C++ bindings ClearVolume offers should (in theory) work on Windows, Linux and OS X. Until now, they have been tested on Windows and OS X.

How to get the ClearVolume & C/C++ bindings (easy way)

If you don't want to build ClearVolume and its C/C++ bindings yourself, you can use instead our ready-to-use binaries. Keep in mind that ClearVolume is actively developed and improved practically on a daily basis. So the latest features and bug fixes are unlikely to be available in the pre-built package found here

If instead you feel more ambitious, you can build the project using Gradle and CMake:

How to build and test the ClearVolume native library:

First make sure to satisfy all requirements listed in the main project page and in the README.md file found in src/cpp.

  • Go to ClearVolume’s project folder root and run build.bat (Windows) or ./build.sh (Linux and OSX).

  • This will populate the folder ./build/cvlib

  • you can now test-drive the bindings by running either the Example_Simple.

Library files overview:

The native library consist of the following files:

  1. include/cvlib.h - header file for the library that lists all functions
  2. src/cvlib.c - source code of the library,
  3. libclearvolume.so, libclearvolume.dylib or clearvolume.dll (depending on your operating system) - the dynamically loadable library that contains the C/C++ bindings code
  4. src/*.cpp - example source code for the bindings you can build upon.

Typically you only really need your own C/C++ code, the library, and ClearVolume’s JAR files. By default, ClearVolume checks the jars subdirectory of the program you are currently running for the required JAR files and complains if something is missing.

API concepts:

The ClearVolume C/C++ API allows to create in-process renderers as well as remote servers for remote viewing. Created renderers and servers are identified by means of arbitrary integers that are provided by the API user at creation time. All functions require an id to so as to know to which renderer or server they apply.

Test program:

An example is worth hundreds of words. In the self-explanatory example below an in-process ClearVolume renderer together with a server for remote viewing are created. Then 500 stacks (volumes in ClearVolume parlance) are filled with synthetic data and are sent to both the in-process renderer and server. Functions defined in cvlib.h allow to set the current metadata used for the next volume sent. See the functions header cvlib.h for more advanced features such as channel filtering and time-shifting.

#!CPP
	// First we initialize the library and provide the location of the ClearVolume jar file.
	// the JVM location is determined automatically using the JAVA_HOME env var.
	int lReturnCode = begincvlib(".\\ClearVolume.jar");
	if(lReturnCode!=0) 
	{
		cout << "Begin failed, return code=" << lReturnCode;
		return lReturnCode;
	}

	cout << "Starting in-process and server ClearVolume\n";

	int lRendererID = 1;
	int lServerID = 2;

	// Creates an in-process renderer:
	if(createRenderer(lRendererID,512, 512, 1, 512, 512)!=0)
		cout << "ERROR while creating renderer \n";

	// Creates a network server:
	if(createServer(lServerID)!=0)
		cout << "ERROR while creating server \n";

	// Sets the voxel dimensions in real units for in-process renderer
	if(setVoxelDimensionsInRealUnits(lRendererID,1,1,1)!=0)
		cout << "ERROR while setting dimensions in real units(um)) \n";

	// Sets the voxel dimensions in real units for in-process server
	if(setVoxelDimensionsInRealUnits(lServerID,  1,1,1)!=0)
		cout << "ERROR while setting dimensions in real units(um)) \n";

	// Information on volume sizes:
	int channel = 0;
	int width = 512;
	int height = width+1;
	int depth = width+3;
	size_t length =width*height*depth;
	char* buffer = new char[length];

	// We will repeatedly send 500 volumes:
	for(int i=0; i<500; i++)
	{
		// for demo purposes we say that the 'acquisition' periode is 100 ms: 
		double timeins = 0.1*i;

		// We set the current index and time for both in-process renderer and server:
		if(setVolumeIndexAndTime(lRendererID,i,timeins)!=0)
			cout << "ERROR while setting volume index and time in seconds (renderer)\n";
		if(setVolumeIndexAndTime(lServerID,  i,timeins)!=0)
			cout << "ERROR while setting volume index and time in seconds (server)\n";

		// We fill in the buffer with some data:
		for(int z=0; z<depth; z++)
			for(int y=0; y<height; y++)
				for(int x=0; x<width; x++)
					buffer[x+width*y+width*height*z]=(char)((char)i^(char)x^(char)y^(char)z);

		//We send the data to both the in-process renderer and server.
		cout << "send volume i=" << i << " on channel " << channel << "\n";
		if(send8bitUINTVolumeDataToSink(lRendererID,channel,buffer,length,width,height,depth)!=0)
			cout << "ERROR while sending volume! (renderer)\n";
		if(send8bitUINTVolumeDataToSink(lServerID,  channel,buffer,length,width,height,depth)!=0)
			cout << "ERROR while sending volume! (server)\n";
	}

	// we destroy both renderer and server
	if(destroyRenderer(lRendererID)!=0)
		cout << "ERROR while destroying renderer \n";
	if(destroyServer(lServerID)!=0)
		cout << "ERROR while destroying server \n";

	// closes the library
	endcvlib();