Basic Infrastructure

The backbone of writing plugins for Vish is the build system. There are altenative ways to achieve the same, but the primarily supported build system is based on standard GNU Make. Vish is structured highly modular into various components, each component residing in a folder within the Vish source tree. Note that there is no support to have multiple components within one folder, each folder needs to produce one unique output, for the mere reason to keep things simple. To create a new Vish component, start by creating a new folder in the vish source tree in an appropriate location. The vish/modules/ folder is a recommended place to get started, unless there are other reasons. So let’s start with creating a folder there for development:

cd vish/modules
mkdir MyStuff
cd MyStuff

The next step is to create a Makefile in this newly created directory, depending on the intended type of Vish component:

Vish Modules

A Vish module is a plugin providing objects to be loaded at runtime. The Makefile in this directory must define a variable VISH with the name of the binary plugin, which must be unique across all existing modules. For instance, we can call it MyStuff, expecting that no other Vish plugin uses the same name. The Makefile must further define the library dependencies to be used by Vish module, which is specified via the LIBS variable. Finally, it must include another file from its parent directory to inherit its properties, thus the following three lines:

VISH=MyStuff
LIBS=-lAnemonia -lGLvish -lplankton $(GL_LIBS) -lmemcore -lm $(OCEAN)
include $(VPATH)../GNUmakefile.rules

This Vish module has been specified to depend on OpenGL. Not every module will need this requirement and the library dependencies should always be minimal.

Once these three lines have been saved into a file named “Makefile”, it is ready to execute “make” in the same folder, and it will generate a yet empty plugin such as bin/arch-****-Debug/modules_MyStuff.vish whereby **** depends on the current platform used. A Vish plugin needs to be equipped with some init routine, which is automatically generated by the makefile by typing

make init.cpp

This will create such a .cpp file to be compiled and included in the plugin. We are not ready to place any C++ code in the same folder, it will be automatically picked up by the Makefile and compiled into the newly created plugin. For instance, get started with a copy of the simple Background demo or a simple geometry drawing a Quad.

Libraries

Libraries contain code that shall be shared among Vish modules. The Makefile in library directories must define a variable TARGET=MyGreatLib instead of VISH, e.g. in the most simple case:

TARGET=MyGreatLib
include $(VPATH)../GNUmakefile.rules

The makefile will automatically pick up all source code in the same directory. Setting the LIBS variable is optional to link this library with other libraries. The value of the TARGET variable is to be used for the LIBS reference in Vish modules or other libraries using this one. Libraries do not use a init.cpp file, but they must define export definitions for symbols. Such as automatically generated via

make winapi

which will create a file MyGreatLibDllApi.h which must be included in all header files, whereby the definition  MyGreatLib_API must be used on all exported class definitions.  For instance:

class  MyGreatLib_API MyFirstClass {};

Other than this, all common C++ coding practices apply.

Executables

Executables are tools that define their own binary to be run independently of the Vish binary but still make use of some Vish libraries, and possibly Vish plugins as well. This is useful to write command line tools or when intergrating Vish into some external application providing its own main() routine. A Makefile producing an executable has the same structure as a Makefile for libraries, but defines another target to call the “bin” target, it thus looks like this:

TARGET=MyExecutable
LIBS=-lmemcore
ThisIsMyBinary: bin
include $(VPATH)../GNUmakefile.rules

Executables are not common, so this case is mentioned here merely for completeness.

Types of Vish Objects

All Vish objects must be derived from the base class VObject. Depending on the required functionality, some base classes derived from VObject will be suitable. After defining a class for a new Vish Object, this class must be announced to the Vish system such that it can be instantiated and created at runtime. This is done via Creator objects, and the template classes VSink<>, VFilter<> and VSource<> provide this functionality. See the respective example code for detailed usage.

Rendering Objects

The rendering capability is optional in Vish, some objects may provide this capabilities, others don’t. There are different levels on how rendering is supported, currently via Raw OpenGL and via an Abstraction layer, the Anemonia API:

Using Raw OpenGL

For issuing raw OpenGL commands, objects need to be derived from the base class VGLRenderObject as defined in the GLVish library. Examples are provided via the Background demo or the geometry drawing a Quad. Within a derived VGLRenderObject, all OpenGL calls are available. Rendering is done via the virtual render() function which has access to a VGLRenderContext that is passed on each call. The render() function may read Vish input parameters and modify output parameters, but it must not modify the Vish object itself.

Using the Anemonia API

The Anemonia API is an abstraction layer hiding OpenGL via a more high level and type-safe interface providing some caching mechanisms based on modern OpenGL buffers. This functionality is implemented around so-called Render Anemones, which represent an atomic quantity for rendering. Basically a Render Anemone is an object that knows how to paint a set of points with attributes such as colors. This set of points may also be connected as lines or triangles, i.e. basic rendering primitives. The Render Anemone may furthermore be equipped with a shader and various parameters controlling OpenGL and the shader. In an efficient implementation, this Anemone object will be created only once, i.e. data are uploaded to the graphics card at this point only once, and then re-used, possibly with modifying parameters at each rendering call. There is support for directly connecting Vish input parameters to the rendering parameters of a Render Anemone. Further information to be found in the respective source code and its documentation.

Data Processing

Vish objects contain inputs, outputs, or both. The Vish Object’s update() function is called whenever some input has been changed while some output is requested. Note that this update() function will not be called until some output is requested.

Simple Types as Input / Output

Input parameters are created via the in<double> template, output with out<double>, input parameters that shall also be available as output will be defined as inout<double>. Other types as double can be used as well as long as certain template type trait classes have been defined for them. See the multiply int example for demonstration. Note that the syntax

inParameter << Context >> Value;

is used for reading input parameters, whereas

inParameter << Context << Value;

is used for writing parameter values. An object’s update() will be triggered whenever some input parameter has been modified. Note that it is possible for an object to modify its own input parameter as well, in which case it will be perpetually called again until it stops doing so. This is a possible way to implement self-updates.

Using FiberLib for Complex Data

The FiberLib is a C++ library for handling big, complex data using the concept of fiber bundles. It is an optional but powerful component in Vish. All code dependent on the FiberLib is contained in the fish/ subfolder, which stands for fiber-vish. The FiberLib supports out-of-core processing of bigger-than-RAM data, both on reading and writing, in a fashion similar to memory mapping. The data types supported are all kinds of spatio-temporal data as used in scientific computing and data visualization, covering uniform grids, unstructured and structured meshes, point clouds, particle trajectories, vector and tensor fields and much more. It is based on a query-like system of Grid objects that can be queried for their topological and geometrical properties. These Grid objects are the basic objects to deal with using the FiberLib. Each Grid object can be equipped with Field objects, some of them are arbitrarily user-defined, some of them define some intrinsic properties of these Grid objects. Together they form a system of “building blocks” that allow to describe a vast category of data types using the same, reusable components.

The Vish source code is structured as:

  • fish/fiber/ — the FiberLib, no dependency on Vish core routines. All code used here can be called as a library by executables
  • fish/pond/ — Vish objects making use of the FiberLib for data processing
  • fish/pond/eye — Vish objects performing rendering on data managed by theFiberLib

For instance a starting point to implement a new shader on a triangular surface as managed by the FiberLib can be found in fish/pond/eye/surfaces/DisplayFlatShadedTriangles.cpp