Communications in VC are implemented through message routing. Messages can be sent to or received from external applications through UDP protocol, they can be routed from one scene node to one or more other nodes, or they can be received from user interactions. Responses to events are described into scripts attached to nodes in the scene graph.
The received events are processed on a First In First Out basis whatever their source. They are stored in an output event queue that is flushed at each frame rate by dispatching the events to the target scene nodes or external applications. Emitted events are processed on the same basis and stored in an input event queue. To reduce the overhead due to event routing, received and emitted events are controlled as follows:
In case of redundant event emission (events corresponding to the same command with different numerical parameters) only the last received event is emitted.
In case of sonic properties updates (emitted coordinates of objects with sonic properties for sound spatialization), thresholds are defined in the configuration file (see environment node), and updates are reported if the difference of value since the last update exceeds this threshold.
The routing of events to external applications through UDP is controlled by a maximal delay time. If an event cannot be sent within this delay, it is thrown away. Duplicate OSC incoming messages are removed in order to process only the latest message with a given ID. (Duplicate removal can be avoided by modifying the OSC_duplicate_removal attribute of the udp_local_server element or by prefixing OSC addresses with an '_' character.)
Figure 2-6 shows the data flow for event processing. Events received in the input queue are processed by an interpreter. For each event and for each target node, the script of the corresponding node is retrieved. If the script contains a command triggered by the message carried by the event, the command is executed by the interpreter. If the command triggers output events, they are stored in the output queue. If the triggering event is controlled by a node state and an operator, the corresponding action(s) are only performed if the comparison between the node state and the expected state is true.
Output events are issued by the interpreter if the action triggers events, or by the browser in the case of automatic updates of objects that are not rendered by the browser (for instance sonic objects). The router is in charge of dispatching these events to their targets. Events for internal scene nodes are added to the input queue, events for external applications are sent to the UDP ports of the corresponding applications.
Input events that are received from the router (see above), from user interactions, or from external applications through UDP communications are causal events. In addition to these events, scripts can also contain scheduled events that are triggered at predefined times. Scheduled events can be used to modify the appearance of a scene in an animation film.
Any node in a scene graph can contain a script: a list of commands made of the following three components:
The trigger is either a date description for actions triggered by scheduled events, or a message string for actions triggered by causal events. In addition, a trigger can contain the ID of an internal state that controls the receptivity of the internal node to this event.
The action is a modification of the target node parameters, or the triggering of an output event bound to one or more target node(s) or to an external application.
The target is the identifier of the node(s) to which the action(s) applies. The target can be any node in a scene including the environment node.
Scripts can also be associated with schedules: completion scripts that are executed once when the schedule terminates, and update scripts that are executed at each frame in which the schedule is active. In both scripts, commands do not have triggers because their activation does not rely on the reception of external events.
The following script is made of three commands. The first one is triggered if the node receives a message volumeh. In this case, the action performed is set_node_attribute_value, a modification the x, y, and z values of the scale transformation expected to be found on the node named hvscale cylinder #1. The second command is triggered by a key stroke. Since key events are not directed towards a specific node, all the commands triggered by key events are relocated at the root node during a preprocessing of the scene graph. The associated action sends a message start rotate to the node named moving cylinder #0. The third command is scheduled at time 7 and sends a UDP message. A target udp_host is specified for this command: a UDP server defined in the configuration file (see environment node). For instance, interactive control modules such as PureData or MaxMSP can be target hosts if a UDP server is defined in these applications. The fourth and fifth commands are both triggered by the message click. These actions are only executed if the node is in the state A_ongoing. The fourth action modifies the sonic properties of the target node, and the fifth command modifies the internal state of the target node.
<script id="script_metro"> <command> <trigger type="message_event" value="volumeh" /> <action> <set_node_attribute_value operator="="> <transformation x="2.0" y="2.0" z="2.0" /> </set_node_attribute_value> <target type="single_node" value="#hvscale cylinder #1" /> </action> </command> <command> <trigger type="keystroke" value="C" /> <action> <send_message value="start rotate" /> <target type="single_node" value="#moving cylinder #0" /> </action> </command> <command> <trigger type="time_limit" value="7" /> <action> <send_message_udp value="source 0 level 100" /> <target type="single_host" value="spatializer" /> </action> </command> <command> <trigger type="message_event" value="click" state="A" bool_operator="==" /> <action> <set_sound_attribute_value operator="="> <sound begin="now" end="100000" /> </set_sound_attribute_value> <set_internal_state value="A_ongoing" /> <target type="single_node" value="#sphere 1" /> </action> </command> </script>