The C API
This section describes the C implementation of the ɴsɪ, as provided in the nsi.h file. This will also be a reference for the interface in other languages as all concepts are the same.
#define NSI_VERSION 1
The NSI_VERSION macro exists in case there is a need at some point to break source compatibility of the C interface.
#define NSI_SCENE_ROOT ".root"
The NSI_SCENE_ROOT macro defines the handle of the root node.
#define NSI_ALL_NODES ".all"
The NSI_ALL_NODES macro defines a special handle to refer to all nodes in some contexts, such as removing connections.
#define NSI_ALL_ATTRIBUTES ".all"
The NSI_ALL_ATTRIBUTES macro defines a special handle to refer to all attributes in some contexts, such as removing connections.
Context Handling
NSIContext_t NSIBegin(
int n_params,
const NSIParam_t *args
)
void NSIEnd(
NSIContext_t ctx
)
These two functions control creation and destruction of a ɴsɪ context, identified by a handle of type NSIContext_t.
A context must be given explicitly when calling all other functions of the interface. Contexts may be used in multiple threads at once. The NSIContext_t is a convenience typedef and is defined as:
typedef int NSIContext_t;
If NSIBegin fails for some reason, it returns NSI_BAD_CONTEXT which is defined in nsi.h:
#define NSI_BAD_CONTEXT ((NSIContext_t)0)
Optional arguments may be given to NSIBegin() to control the creation of the context:
| Name | Type | Description/Values |
|---|---|---|
type | string | Sets the type of context to create. The possible types are: |
render — Execute the calls directly in the renderer. This is the default. | ||
apistream — To write the interface calls to a stream, for later execution. The target for writing the stream must be specified in another argument. | ||
streamfilename | string | The file to which the stream is to be output, if the context type is apistream. Specify stdout to write to standard output and stderr to write to standard error. |
streamformat | string | The format of the command stream to write. Possible formats are: |
nsi — Produces an ɴsɪ stream. | ||
binarynsi — Produces a binary encoded ɴsɪ stream. | ||
autonsi — Automatically selects the best format. | ||
stream.compression | string | The type of compression to apply to the written command stream. |
streampathreplacement | int | Use 0 to disable replacement of path prefixes by references to environment variables which begin with NSI_PATH_ in an ɴsɪ stream. This should generally be left enabled to ease creation of files which can be moved between systems. |
separateprocess | int | When set to 1, the render will be executed in a separate process. |
errorhandler | pointer | A function which is to be called by the renderer to report errors. The default handler will print messages to the console. |
errorhandler.data | pointer | The userdata argument of the error reporting function. |
executeprocedurals | string | A list of procedural types that should be executed immediately when a call to NSIEvaluate() or a procedural node is encountered and NSIBegin()’s output type is apistream. This will replace any matching call to NSIEvaluate() with the results of the procedural’s execution. |
Arguments vs. Attributes
Arguments are what a user specifies when calling a function of the API. Each function takes extra, optional arguments.
Attributes are properties of nodes and are only set through the aforementioned optional arguments using the NSISetAttribute() and NSISetAttributeAtTime() functions.
Optional Arguments
Any API call can take extra arguments. These are always optional. What this means the call can do work without the user specifying these arguments.
Nodes are special as they have mandatory extra attributes that are set after the node is created inside the API but which must be set before the geometry or concept the node represents can actually be created in the scene.
These attributes are passed as extra arguments to the NSISetAttribute() and NSISetAttributeAtTime() functions.
[!NOTE] Nodes can also take extra arguments when they are created. These optional arguments are only meant to add information needed to create the node that a particular implementation may need.
As of this writing there is no implementation that has any such optional arguments on the
NSICreate()function. The possibility to specify them is solely there to make the API future proof.
[!CAUTION] Nodes do not have optional arguments for now. An optional argument on a node is not the same as an attribute on a node.
Attributes — Describe the Node’s Specifics
Attributes are only for nodes. They must be set using the NSISetAttribute() or NSISetAttributeAtTime() functions.
They can not be set on the node when it is created with the NSICreate() function.
[!CAUTION] Only nodes have attributes. They are sent to the API via optional arguments on the API’s attribute functions.
Passing Optional Arguments
struct NSIParam_t
{
const char *name;
const void *data;
int type;
int arraylength;
size_t count;
int flags;
};
This structure is used to pass variable argument lists through the C interface. Most functions accept an array of the structure in a args argument along with its length in a n_params argument.
The meaning of these two arguments will not be documented for every function. Instead, each function will document the arguments which can be given in the array.
name
: A C string which gives the argument’s name.
type
: Identifies the argument’s type, using one of the following constants:
| Constant | Description |
|---|---|
NSITypeFloat | Single 32-bit floating point value. |
NSITypeDouble | Single 64-bit floating point value. |
NSITypeInteger | Single 32-bit integer value. |
NSITypeString | String value, given as a pointer to a C string. |
NSITypeColor | Color, given as three 32-bit floating point values. |
NSITypePoint | Point, given as three 32-bit floating point values. |
NSITypeVector | Vector, given as three 32-bit floating point values. |
NSITypeNormal | Normal vector, given as three 32-bit floating point values. |
NSITypeMatrix | Transformation matrix, in row-major order, given as 16 32-bit floating point values. |
NSITypeDoubleMatrix | Transformation matrix, in row-major order, given as 16 64-bit floating point values. |
NSITypePointer | C pointer. |
Tuple types are specified by setting the bit defined by the NSIArgIsArray constant in the flags member and the length of the tuple in the arraylength member.
[!TIP] It helps to view
arraylengthas a part of the data type. The data type is a tuple with this length whenNSIArgIsArrayis set.
[!NOTE] If
NSIArgIsArrayis not set,arraylengthis ignored.The
NSIArgIsArrayflag is necessary to distinguish between arguments that happen to be of length 1 (set in thecountmember) and tuples that have a length of 1 (set in thearraylengthmember) for the resp. argument."foo" "int[1]" 1 [42] # The answer to the ultimate question – in a (single) tuple "bar" "int" 1 13 # My favorite Friday
The count member gives the number of data items given as the value of the argument.
The data member is a pointer to the data for the argument. This is a pointer to a single value or a number of values. Depending on type, count and arraylength settings.
[!NOTE] When data is an array, the actual number of elements in the array is count × arraylength × n. Where n is specified implicitly through the
typemember in the table above.For example, if the type is
NSITypeColor(3 values),NSIArgIsArrayis set,arraylengthis 2 andcountis 4,datais expected to contain 24 32-bit floating point values (3×2×4).
The flags member is a bit field with a number of constants used to communicate more information about the argument:
| Flag | Description |
|---|---|
NSIArgIsArray | To specify that the argument is an array type, as explained above. |
NSIArgPerFace | To specify that the argument has different values for every face of a geometric primitive, where this might be ambiguous. |
NSIArgPerVertex | Specify that the argument has different values for every vertex of a geometric primitive, where this might be ambiguous. |
NSIArgInterpolateLinear | Specify that the argument is to be interpolated linearly instead of using some other, default method. |
[!NOTE]
NSIArgPerFaceorNSIArgPerVertexare only strictly needed in rare circumstances when a geometric primitive’s number of vertices matches the number of faces. The most simple case is a tetrahedral mesh which has exactly four vertices and also four faces.
Indirect lookup of arguments is achieved by giving an integer argument of the same name, with the .indices suffix added. This is read to know which values of the other argument to use.
Create "subdiv" "mesh"
SetAttribute "subdiv"
"nvertices" "int" 4 [ 4 4 4 4 ]
"P" "point" 9 [
0 0 0 1 0 0 2 0 0
0 1 0 1 1 0 2 1 0
0 2 0 1 2 0 2 2 2 ]
"P.indices" "int" 16 [
0 1 4 3 2 3 5 4 3 4 7 6 4 5 8 7 ]
"subdivision.scheme" "string" 1 "catmull-clark"
Node Creation
void NSICreate(
NSIContext_t context,
NSIHandle_t handle,
const char *type,
int n_params,
const NSIParam_t *args
)
This function is used to create a new node. Its arguments are:
context
: The context returned by NSIBegin(). See context handling.
handle
: A node handle. This string will uniquely identify the node in the scene.
If the supplied handle matches an existing node, the function does nothing if all other arguments match the call which created that node. Otherwise, it emits an error. Note that handles need only be unique within a given interface context. It is acceptable to reuse the same handle inside different contexts. The NSIHandle_t typedef is defined in nsi.h:
typedef const char* NSIHandle_t;
type
: The type of node to create.
n_params, args
: This pair describes a list of optional arguments. The NSIParam_t type is described in this section.
[!CAUTION] There are no optional arguments defined as of now.
void NSIDelete(
NSIContext_t ctx,
NSIHandle_t handle,
int n_params,
const NSIParam_t *args
)
This function deletes a node from the scene. All connections to and from the node are also deleted. Note that it is not possible to delete the root or the global node. Its arguments are:
context
: The context returned by NSIBegin(). See context handling.
handle
: A node handle. It identifies the node to be deleted.
It accepts the following optional arguments:
| Name | Type | Description/Values |
|---|---|---|
recursive | int | Specifies whether deletion is recursive. By default, only the specified node is deleted. If a value of 1 is given, then nodes which connect to the specified node are recursively removed unless they also have connections which do not eventually lead to the specified node, or their connection to the deleted node was created with a strength greater than 0. This allows, for example, deletion of an entire shader network in a single call. |
Setting Attributes
void NSISetAttribute(
NSIContext_t ctx,
NSIHandle_t object,
int n_params,
const NSIParam_t *args
)
This function sets attributes on a previously created node. All optional arguments of the function become attributes of the node.
On a shader node, this function is used to set the implicitly defined shader arguments.
Setting an attribute using this function replaces any value previously set by NSISetAttribute() or NSISetAttributeAtTime(). To reset an attribute to its default value, use NSIDeleteAttribute().
void NSISetAttributeAtTime(
NSIContext_t ctx,
NSIHandle_t object,
double time,
int n_params,
const NSIParam_t *args
)
This function sets time-varying attributes (i.e. motion blurred). The time argument specifies at which time the attribute is being defined.
It is not required to set time-varying attributes in any particular order. In most uses, attributes that are motion blurred must have the same specification throughout the time range.
A notable exception is the P attribute on particles which can be of different size for each time step because of appearing or disappearing particles. Setting an attribute using this function replaces any value previously set by NSISetAttribute().
void NSIDeleteAttribute(
NSIContext_t ctx,
NSIHandle_t object,
const char *name
)
This function deletes any attribute with a name which matches the name argument on the specified object. There is no way to delete an attribute only for a specific time value.
Deleting an attribute resets it to its default value.
For example, after deleting the transformationmatrix attribute on a transform node, the transform will be an identity. Deleting a previously set attribute on a shader node will default to whatever is declared inside the shader.
Making Connections
void NSIConnect(
NSIContext_t ctx,
NSIHandle_t from,
const char *from_attr,
NSIHandle_t to,
const char *to_attr,
int n_params,
const NSIParam_t *args
)
void NSIDisconnect(
NSIContext_t ctx,
NSIHandle_t from,
const char *from_attr,
NSIHandle_t to,
const char *to_attr
)
These two functions respectively create or remove a connection between two elements. It is not an error to create a connection which already exists or to remove a connection which does not exist but the nodes on which the connection is performed must exist. The arguments are:
from
: The handle of the node from which the connection is made.
from_attr
: The name of the attribute from which the connection is made. If this is an empty string then the connection is made from the node instead of from a specific attribute of the node.
to
: The handle of the node to which the connection is made.
to_attr
: The name of the attribute to which the connection is made. If this is an empty string then the connection is made to the node instead of to a specific attribute of the node.
NSIConnect() accepts additional optional arguments.
| Name | Type | Description/Values |
|---|---|---|
value | This can be used to change the value of a node’s attribute in some contexts. Refer to guidelines on inter-object visibility for more information about the utility of this parameter. | |
priority | When connecting attribute nodes, indicates in which order the nodes should be considered when evaluating the value of an attribute. | |
strength | int (0) | A connection with a strength greater than 0 will block the progression of a recursive NSIDelete. |
Severing Connections
With NSIDisconnect(), the handle for either node may be the special value .all. This will remove all connections which match the other three arguments. For example, to disconnect everything from the scene’s root:
NSIDisconnect( NSI_ALL_NODES, "", NSI_SCENE_ROOT, "objects" );
Evaluating Procedurals
void NSIEvaluate(
NSIContext_t ctx,
int n_params,
const NSIParam_t *args
)
This function includes a block of interface calls from an external source into the current scene. It blends together the concepts of a straight file include, commonly known as an archive, with that of procedural include which is traditionally a compiled executable. Both are really the same idea expressed in a different language (note that for delayed procedural evaluation one should use the procedural node).
The ɴsɪ adds a third option which sits in-between — Lua scripts. They are much more powerful than a simple included file yet they are also much easier to generate as they do not require compilation. It is, for example, very realistic to export a whole new script for every frame of an animation. It could also be done for every character in a frame. This gives great flexibility in how components of a scene are put together.
The ability to load ɴsɪ commands straight from memory is also provided.
The optional arguments accepted by this function are:
| Name | Type | Description/Values |
|---|---|---|
type | string | The type of file which will generate the interface calls. This can be one of: |
apistream — Read in an ɴsɪ stream. This requires either filename or buffer/size arguments to be specified too. | ||
lua — Execute a Lua script, either from file or inline. See also how to evaluate a Lua script. | ||
dynamiclibrary — Execute native compiled code in a loadable library. See dynamic library procedurals for an implementation example. | ||
filename | string | The file from which to read the interface stream. |
script | string | A valid Lua script to execute when type is set to lua. |
buffer / size | pointer / int | These two arguments define a memory block that contains ɴsɪ commands to execute. |
backgroundload | int | If this is nonzero, the object may be loaded in a separate thread, at some later time. This requires that further interface calls not directly reference objects defined in the included file. The only guarantee is that the file will be loaded before rendering begins. |
Error Reporting
enum NSIErrorLevel
{
NSIErrMessage = 0,
NSIErrInfo = 1,
NSIErrWarning = 2,
NSIErrError = 3
}
typedef void (*NSIErrorHandler_t)(
void *userdata, int level, int code, const char *message
)
This defines the type of the error handler callback given to the NSIBegin() function. When it is called, the level argument is one of the values defined by the NSIErrorLevel enum. The code argument is a numeric identifier for the error message, or 0 when irrelevant. The message argument is the text of the message.
The text of the message will not contain the numeric identifier nor any reference to the error level. It is usually desirable for the error handler to present these values together with the message. The identifier exists to provide easy filtering of messages.
The intended meaning of the error levels is as follows:
| Level | Description |
|---|---|
NSIErrMessage | For general messages, such as may be produced by printf() in shaders. The default error handler will print this type of messages without an eol terminator as it’s the duty of the caller to format the message. |
NSIErrInfo | For messages which give specific information. These might simply inform about the state of the renderer, files being read, settings being used and so on. |
NSIErrWarning | For messages warning about potential problems. These will generally not prevent producing images and may not require any corrective action. They can be seen as suggestions of what to look into if the output is broken but no actual error is produced. |
NSIErrError | For error messages. These are for problems which will usually break the output and need to be fixed. |
Rendering
void NSIRenderControl(
NSIContext_t ctx,
int n_params,
const NSIParam_t *args
)
This function is the only control function of the API. It is responsible for starting, suspending and stopping the render. It also allows for synchronizing the render with interactive calls that might have been issued. The function accepts:
| Name | Type | Description/Values |
|---|---|---|
action | string | Specifies the operation to be performed, which should be one of the following: |
start — This starts rendering the scene in the provided context. The render starts in parallel and the control flow is not blocked. | ||
wait — Wait for a render to finish. | ||
synchronize — For an interactive render, apply all the buffered calls to scene’s state. | ||
suspend — Suspends render in the provided context. | ||
resume — Resumes a previously suspended render. | ||
stop — Stops rendering in the provided context without destroying the scene. |
NSIRenderControl() accepts the following optional arguments:
| Name | Type | Description/Values |
|---|---|---|
progressive | integer | If set to 1, render the image in a progressive fashion. |
interactive | integer | If set to 1, the renderer will accept commands to edit scene’s state while rendering. The difference with a normal render is that the render task will not exit even if rendering is finished. Interactive renders are by definition progressive. |
frame | Specifies the frame number of this render. | |
stoppedcallback | pointer | A pointer to a user function that should be called on rendering status changes. The function signature is: |
void StoppedCallback(
void* stoppedcallbackdata,
NSIContext_t ctx,
int status
)
The status argument can take the following values:
NSIRenderCompletedindicates that rendering has completed normally.NSIRenderAbortedindicates that rendering was interrupted before completion.NSIRenderSynchronizedindicates that an interactive render has produced an image which reflects all changes to the scene.NSIRenderRestartedindicates that an interactive render has received new changes to the scene and no longer has an up to date image.
| Name | Type | Description/Values |
|---|---|---|
stoppedcallbackdata | pointer | A pointer that will be passed back to the stoppedcallback function. |