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 |
|
---|---|---|---|
|
string |
Sets the type of context to create. The possibletypes are: |
|
|
Execute the calls directly in the renderer. This is the default. |
||
|
To write the interface calls to a stream, for later execution. The target for writing the stream must be specified in another argument. |
||
|
string |
The file to which the stream is to be output,
if the context type is |
|
|
string |
The format of the command stream to write. Possible formats are: |
|
|
Produces an nsi stream |
||
|
Produces a binary encoded nsi stream |
||
|
string |
The type of compression to apply to the written command stream. |
|
|
int |
Use |
|
|
pointer |
A function which is to be called by the renderer to report errors. The default handler will print messages to the console. |
|
|
pointer |
The |
|
|
string |
A list of procedural types that should be
executed immediately when a call to
NSIEvaluate() or a
procedural node is encountered and
|
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
aforementioed 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
type
¶
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 arraylength
as a part of the data type. The
data type is a tuple with this length when NSIArgIsArray
is set.
Note
If NSIArgIsArray
is not set, arraylength
is ignored.
The NSIArgIsArray
flag is neccessary to distinguish between
arguments that happen to be of length 1 (set in the count
member) and tuples that have a length of 1 (set in the
arraylength
member) for the resp. argument.
"foo" "int[1]" 1 [42] # The answer to the ultimate question – in an 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 values. Depending on type
,
count
and arraylength
settings.
Note
When data is an array, the actual number of elements in the array
is \(count\times arraylength\times n\). Where \(n\) is
specified implictly through the type
member in the table above.
For example, if the type is NSITypeColor
(3 values),
NSIArgIsArray
is set, arraylength
is 2 and count
is
4, data
is expected to contain 24 32-bit floating point
values (\(3\times2\times4\)).
The flags
member is a bit field with a number of constants used
to communicate more information about the argument:
|
to specify that the argument is an array type, as explained above. |
|
to specify that the argument has different values for every face of a geometric primitive, where this might be ambiguous. |
|
Specify that the argument has different values for every vertex of a geometric primitive, where this might be ambiguous. |
|
Specify that the argument is to be interpolated linearly instead of using some other, default method. |
Note
NSIArgPerFace
or NSIArgPerVertex
are 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.
1Create "subdiv" "mesh"
2SetAttribute "subdiv"
3 "nvertices" "int" 4 [ 4 4 4 4 ]
4 "P" "point" 9 [
5 0 0 0 1 0 0 2 0 0
6 0 1 0 1 1 0 2 1 0
7 0 2 0 1 2 0 2 2 2 ]
8 "P.indices" "int" 16 [
9 0 1 4 3 2 3 5 4 3 4 7 6 4 5 8 7 ]
10 "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
NSIBegin()
. See
context handling.handle
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
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
NSIBegin()
. See
context handling.handle
It accepts the following optional arguments:
Name |
Type |
Description/Values |
|
---|---|---|---|
|
int |
Specifies whether deletion is recursive. By
default, only the specified node is deleted.
If a value of
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 functions sets attributes on a previously 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 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
from_attr
to
to_attr
NSIConnect()
accepts additional optional arguments.
Name |
Type |
Description/Values |
---|---|---|
|
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. |
|
|
When connecting attribute nodes, indicates in which order the nodes should be considered when evaluating the value of an attribute. |
|
|
int (0) |
A connection with a strength greater than |
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:
1NSIDisconnect( 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 |
|
---|---|---|---|
|
string |
The type of file which will generate the interface calls. This can be one of: |
|
|
Read in an nsi
stream.
This requires either
|
||
|
Execute a Lua script, either from file or inline. See also how to evaluate a Lua script. |
||
|
Execute native compiled code in a loadable library. See dynamic library procedurals for an implementation example. |
||
|
string |
The file from which to read the interface stream. |
|
|
string |
A valid Lua script to execute
when |
|
|
pointer int |
These two arguments define a memory block that contains ɴsɪ commands to execute. |
|
|
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 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:
|
For general messages, such as may be produced by
|
|
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. |
|
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. |
|
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 of 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 |
|
---|---|---|---|
|
string |
Specifies the operation to be performed, which should be one of the following: |
|
|
This starts rendering the scene in the provided context. The render starts in parallel and the control flow is not blocked. |
||
|
Wait for a render to finish. |
||
|
For an interactive render, apply all the buffered calls to scene’s state. |
||
|
Suspends render in the provided context. |
||
|
Resumes a previously suspended render. |
||
|
Stops rendering in the provided context without destroying the scene. |
|
integer |
If set to |
|
integer |
If set to |
|
Specifies the frame number of this render. |
|
|
pointer |
A pointer to a user function that should be called on rendering status changes. This function must have no return value and accept a pointer argument, a ɴsɪ context argument and an integer argument: void StoppedCallback(
void* stoppedcallbackdata,
NSIContext_t ctx,
int status
)
The third argument is an integer which can take the following values:
|
|
pointer |
A pointer that will be passed back to the
|