set im1 [im_read tiger.jpg] set im2 [im_read football.jpg] im_scale! im1 0.3 im_trans! im1 200 50 set out [im_overlay $im1 $im2] im_write $out out.jpgRivl uses a demand-driven evaluation model. Commands such as im_trans and im_scale do not perform their operations when they are called. Rather, the operations are stored in a data structure, a directed acyclic graph, to be performed later. For example, the first five lines of the program above generates a graph that looks like:
In the graph, nodes represent signal operations and edges represent
signals. For example, the edge following the scale
node
represents a signal that has been read from tiger.jpg
and
scaled down. Throughout the Rivl C interface and this document, the
terms "signal" and "edge" are used interchangeably.
A node has zero or more input signals and exactly one output signal. A node with zero inputs is called a leaf node and its output signal is called a leaf signal. The descendents and ancestors of a signal refer to the subgraphs to its left and right, respectively.
Commands such as im_read, im_scale, im_trans, and im_overlay are
called node commands. A node command adds a new node and a new
outgoing signal to the graph. The node contains information which
allows data to be computed later. The signal is given a unique name,
like rivl_im5
, which is returned to Tcl. If and when
rivl_im5
is passed back to C in another command, a hash
table lookup is used to find its signal.
Commands such as im_write and im_display are called content commands. A content command computes the data in some region of a signal and then acts on the data - by writing it to a file, displaying it, returning its sum, etc. Rivl computes a signal's data by propagating data up from the signal's descendents, starting with the leaf nodes. As the data passes through the graph, each node transforms it.
typedef struct { Rivl_Node fromNode; Rivl_Signal *inputs; int inputCount; } Rivl_Signal;The fromNode field points to the node to the left of the signal. The inputs field points to an array of input signals, where inputCount gives the number of inputs.
Note that there is currently no way to determine the ancestors (the subgraph to the right) of a given signal or node. This may change in the near future.
typedef struct { Rivl_NodeClass classInfo; void *data; } Rivl_Node;Nodes are object-oriented in a limited sense. The classInfo field points to a Rivl_NodeClass structure containing information pertaining to all nodes of a class. The data field points to an optional structure containing data that differentiates a node from other instances of its class. Each node class decides whether its instances will make use of the data pointer and what kind of structure it will point to. For example,
scale
nodes are differentiated by how much to
scale, so the data field in every scale
node points to a
structure containing x and y scale factors. However, dup
nodes do not use the data field since their behavior is completely
defined by their class.A class is usually associated with one or more node commands that add a new node of that class to the graph. See node commands, below.
Note that there is currently no way to determine the input or output signals of a given node. The graph connectivity information is only maintained in the signal type.
It is difficult to describe exactly how to add a new node command
here. The best way to learn is by example.
RIVL/doc/examples/node.c
contains a complete,
well-documented example of a module that adds a node command. In
addition, RIVL/nodes.c
contains code for all the built-in
nodes in Rivl.
All of the Rivl commands necessary for building node commands should be documented in the manual pages.
im_write
) or return a value based on
the data (like sig_hash
).
Once again, the best way to get started with content commands is to
look at examples. RIVL/doc/examples/content.c
contains a
well-documented example of a content command. You can also examine the
source code for built-in Rivl content commands, such as Sig_HashCmd
(in misc.c
) and Im_FillPhotosCmd
(in tkutil.c
).
All of the Rivl commands necessary for building content commands should be documented in the manual pages.
ppm.c
and mjpgc.c
in the Rivl source code.