Dive 3 Reference Document
Web site: <http://www.sics.se/dive/manual/callbacks.html>
Olof Hagsand - <olof@sics.se>
The Swedish Institute of Computer Science
Stockholm, September, 1995
1. Introduction
This document describes the Dive functional callback interface. The Dive callback interface enables applications and modules to register interest in system events by supplying a user defined function. As the event occurs, the user supplied function is invoked.
This document is intended for designers making integrated Dive applications in C or C++, using the Dive functional interface and linking with the Dive libraries. It describes Dive system events, how to register Dive callbacks, and how the user-defined functions are invoked.
Alternative approaches include to design the application in the file
format [2] and Dive/Tcl behaviour interface [3], or the Dive Client
Interface (DCI) [4].
2. Events types
The callback interface is coupled tightly to Dive system events. A Dive event is something that occurs in the system at a specific time. If a callback is registered with an event, the callback is called when the event occurs. Currently, the following Dive events are defined:
Below, the classifications of Dive events into sub-types will be
given. Sub-types offer a way to specify (filter) events more
specifically. Not all events are classified into sub-types.
3. Registering callbacks
Callbacks can be registered by the following functions:
http://www.sics.se/dive/manual/cref.c.html#callback_register http://www.sics.se/dive/manual/cref.c.html#callback_register_filter
The following functions are only called at the origin (sender) of an event and receivers, respectively:
http://www.sics.se/dive/manual/cref.c.html#callback_register_sender
http://www.sics.se/dive/manual/cref.c.html#callback_register_receiver
3.1 Event filtering
Callbacks can be filtered, so that they are only called in specific situations. In particular, a callback can be made only for a specific object, or a specific event sub-type, by calling the following function:
void *callback_register_filter(dive_event_type event_type,
void(*fn)(), int type, objid_t *id,
char *str, unsigned int flags, void *arg)
The sub-type and matching string argument specified in the filtering
have different semantics for the different callbacks. See Section 4
for the meaning of the sub-type for each case.
3.2 Unregistering callbacks
There are two ways of deregistering callbacks, one using the callback function, and one using the return value (cookie) of the registering function:
http://www.sics.se/dive/manual/cref.c.html#callback_unregister
http://www.sics.se/dive/manual/cref.c.html#callback_deregister
4. Callback functions
This section describes the associated callback functions and their
arguments.
4.1 General arguments
Some arguments occur in many callback functions and have the same meaning:
Called when a new entity has been created. The callback function has the following arguments:
objid_t *id, objid_t *origin, void *arg
Note that being "new" means that it is created in the local database, it may previously have existed in other peers or worlds.
"id" can not be used to filter events since the identifier cannot be
known in advance. The mask versions of entity types (eg. N_POLY_MASK,
DIVE_OBJ_MASK) may be used in any combination as the "type" field in
filtering commands. The matching string is ignored.
4.3 Event ENTITY_CHANGE_EVENT
Called when an entity has been updated in some way except in the ways covered by the other callbacks. The callback function has the following arguments:
objid_t *id, objid_t *origin, void *arg
where "id" is the entity that has changed, "from" is the source of the event, and "arg" is a user supplied argument.
The identifier and entity type may be used in filtering commands. The
matching string is ignored.
4.4 Event ENTITY_REMOVE_EVENT
Called when an entity is removed from the local database. The callback is delivered before it is actually deleted in order to enable processing of the entity. The callback function has the following arguments:
objid_t *id, objid_t *origin, void *arg
Note that "removing" means removing an entity from the local database. This may cause some confudion. Suppose for example that an entity is moved from one world to another. The entity is then removed only in those peers that does not have the new world.
The identifier and entity type may be used in filtering commands. The
matching string is ignored.
4.5 Event ENTITY_MESSAGE_EVENT
Called when a process has sent a user defined message to an entity. The callback function has the following arguments:
objid_t *id, objid_t *origin, char *name, int type, struct prop_link *msg_list, void *arg
where "id" is the entity that receives the event, "origin" is the actor that sent the event, "name" and "type" may be used for dispatching. Typically, "name" identifies a module while "type" identifies a module specific entry. The content of the message is contained as a property list in "msg_list".
In filtering commands, "id", "type" and "name" arguments may be used
to match with id, type and str matchings, respectively.
4.6 Event ENTITY_RPC_EVENT
Called when a process has sent a user defined message to an entity. The callback function has the following arguments:
objid_t *id, objid_t *origin, char *name, int type,
struct prop_link *msg_list, struct prop_link **reply_list, void *arg
where "id" is the entity that receives the event, "origin" is the actor that sent the event, "name" and "type" may be used for dispatching. Typically, "name" identifies a module while "type" identifies a module specific entry. The content of the message is contained as a property list in "msg_list". Answers to the message is made by assigning properties to "reply_list" and returning from the callback. Note that the process requesting for an RPC only waits for the first answer to come back, other answers are discarded.
As for ENTITY_MESSAGE_EVENT, filtering commands can be made to match against
"id", "type" and "name".
4.7 Event ENTITY_PROP_EVENT
A property has changed in an entity. The callback function has the following arguments:
objid_t *id, objid_t *origin, char *name, int type, void *arg
where "id" is the identifier of the entity with the changed property, "origin" is the identifier of the actor that changed the property, "name" is the name of the property, "type" is how the property has changed and "arg" is a user supplied argument.
The property change type can have one of the following values:
The id, type and matching string in filtering commands can be used to
match against the "id", "type" and "name" arguments.
4.8 Event ENTITY_FLAG_EVENT
A shared flag field in an entity has changed. The callback function has the following arguments:
objid_t *id, objid_t *origin, unsigned int mask, void *arg
wheer "mask" is a bitvector that indicates which flags have (not the new) value.
The "id" may be used in filtering commands, and "mask" may be used to
indicate which flags are of interest. The matching string is ignored.
4.9 Event ENTITY_ADD_SUB_EVENT
An entity has been moved from one place in an hierarchy to another. The callback function has the following arguments:
objid_t *id, objid_t *oldsuper, objid_t *newsuper,
objid_t *origin, void *arg
where "id" is the identifier of the inserted entity, "oldsuper" the identifier of the old parent, and "newsuper" the identifier of the new parent. Both parents should be a divenode (ie. a world or a dive_obj).
Note: In the new entity model, worlds are also entities, so almost all objects are placed as a sub in a hierarchy. However, when actors are moved from one world to another, the ACTOR_MIGRATE_EVENT occurs instead.
The identifier and the type of entity of the inserted entity may be
used in filtering commands. The matching string is ignored.
4.10 Event ACTOR_MIGRATE_EVENT
An actor changes world and also transfers its associated objects to new world. The callback function has the following arguments:
objid_t *id, objid_t *wid0, objid_t *wid1, char *name, void *arg
where "wid0" is the identifier of the old world, "wid1" the identifier of the new world and "name" is the name of the new world.
The callback will be delivered to both the old and new world. If the new world is not present in the peer, then "remove" callbacks will also be delivered (see ENTITY_REMOVE_EVENT).
Apart from "id", there is no way to filter this callback with type or
matching string.
4.11 Event DIVEOBJ_COORD_EVENT
The geometrics or kinematics of a dive_obj has changed. It can be a translation, rotation or a combination. It can also be a change in velocity, acceleration or angular velocity. The callback function has the following arguments:
objid_t *id, objid_t *origin, point_t *pt0, divetime *time, void *arg
where "pt0" is the old position of the object in local coordinates
before the transformation. "pt0" is only defined if the
transformation function was "interpolated", such as distr_transform.
Apart from "id", there is no way to filter this callback with a type
or matching string.
4.12 Event DIVEOBJ_VELOCITY_EVENT
The angular or directional velocity of a dive object has changed. The callback function has the following arguments:
objid_t *id, point_t *old_dirV, point_t *old_angV, divetime *old_Tstamp
where "old_dirV" is the object's old directional velocity, "old_angV" is the
old angular velocity and "old_Tstamp" is the time when these velocities where
set.
4.13 Event DIVEOBJ_SCALE_EVENT
The scaling of a dive_obj has changed. The callback function has the following arguments:
objid_t *id, point_t *ratio, void *arg
where "ratio" are the x, y and z factors of the new (relative) scaling.
Apart from "id", there is no way to filter this callback with a type
or matching string.
4.14 Event DIVEOBJ_MATERIAL_EVENT
The material of a dive_obj has changed in some way. A dive_node can be associated with a vector of materials that can be accessed by material-indexes. The callback function has the following arguments:
objid_t *id, objid_t *origin, void *arg
Apart from "id", there is no way to filter this callback with a type
or matching string.
4.15 Event PROCESS_NOTIFY_EVENT
A system information message has been generated. This message may be displayed by a browser or interface, it has no system meaning. Typically, notifications are: "The file foo has been read", etc. The callback function has the following arguments:
char *message, void *arg
This callback can not be filtered in any way, neither with type, id
nor matching string.
4.16 Event INTERACTION_SIGNAL
The callback function has the following arguments:
objid_t *id, interaction_type_t type, objid_t *origin,
objid_t *src_id, point_t *pt, objid_t *viewid,
divetime *time, void *arg
where "id" is the identifier of the object that registered the callback (possibly NULL), "viewid" is the view where the actual interaction occured, "type" is the sub-type of the interaction, "origin" is the actor that caused the interaction, "src_id" is the object that was used to select the object (eg a hand), "pt" is the point in world coordinates where the interaction occurred (eg on the surface of the interacted object, if any), and "time" is the time when the event was generated (for instance the time of a mouse button press).
The two types of interactions that are currently supported by the system are to select and to grab objects. A selection corresponds to a single click in many windowing systems, while grabbing is to take the object and hold it for a while (drag-and-drop).
When a selection of an object is made (typically by pointing at and pressing a button) a DIVE_IA_SELECT signal is sent. On succesful deselection (eg. the button is released while still pointing at the same object) a DIVE_IA_DESELECT is sent and the "pt" argument contains the position where the button was released, otherwise DIVE_IA_DESELECT_FAIL is sent and the "pt" argument is a NULL pointer.
When an actor tries to grab an object (typically by pointing and pressing another button), it either suceeds holds the object and sends a DIVE_IA_GRASP signal, or fails and sends a DIVE_IA_GRASP_FAIL signal. An actor can fail to grasp an object if the object is not modifiable, or is a sub-object of the object that grabs it. When the object is released, the actor sends a DIVE_IA_GRAP_RELEASE signal.
Thus, the classification of interactions is:
The "id" and "type" arguments may be used in filtering commands, type
Collisions can be seen as a binary relation over entities changing over time. A pair of entities ar either in a collided state (eg, their volumes intersect) or they are not. The collision signals are used to indicate a change of this state. The callback function has the following arguments:
objid_t *id, objid_t *id2, collision_type_t type,
divetime *time, void *arg
where "id" and "id2" are the two colliding (or non colliding) objects, "type" is the sub-type as defined below, and "time" is the time of collision. Note that two collision signals may be delivered, one with "id2" as its first and "id" as its second argument.
Collision signals are typically emitted by collision managers or servers. In Dive 3 there is a default collision server that works by checking only for collisions between objects with the "obj_collison" flag set. However, this default server can be replaced by an application specific module.
The classification of collisions is:
If an identifier is given as a filtering command, both the callback
will be delivered if either id or id2 match. The "type" argument may also
be used.
4.18 Event WORLD_SERVER_EVENT
The process is currently "server" for world. Being server means that it is the only process that performs certain actions. The callback can be used to identify a unique process of a world. The callback function has the following arguments:
objid_t *id, divebool on, void *arg
where "id" is the identifier of the world that the process is server of.
The "id" may be used as filtering command.
4.18 Event IMAGE_EVENT
A new image has been generated. Images are typically texture or video frames that are captured via a frame grabber card and distributed within the system. Each image belongs to a stream, identified by a name. The stream name can be used as a texture name which makes it possible to achieve dynamic textures since each new image in the stream will replace the old.
The callback function has the following arguments:
char *name, char *format, void *image, void *arg
objid_t *id, divebool on, void *arg
where 'name' is the stream name, 'format' is the image format and 'image'
points to the actual image data.
5. Examples
5.1 Event filtering: selection
Suppose you want to call function fn() when someone has selected an entity with identifier id1. That is, sent an INTERACTION_SIGNAL of type DIVE_IA_SELECT. In this case, you register fn with the following call:
callback_register_filter(INTERACTION_SIGNAL, fn, DIVE_IA_SELECT,
id1, NULL, CALLBACK_ALL, NULL)
The user defined function "fn" should look like:
void fn(objid_t *id, interaction_type_t type, objid_t *origin,
objid_t *src_id, point_t *pt, void *arg)
Suppose you want to call function fn() when a new entity has been created in your local database. In particular, only dive_objects and lines are of interest. In this case, you register fn with the following call:
callback_register_filter(ENTITY_NEW_EVENT, fn,
(DIVE_OBJ_MASK | LINE_MASK), NULL, NULL,
CALLBACK_ALL, NULL)
The user defined function "fn" should look like:
void fn(objid_t *id, objid_t *origin, void *arg)
When actors change worlds, the event sequence can be slightly confusing. An example may clarify the sequence of callbacks. For simplicity, "change" callbacks and callbacks for the actor's associated objects have been omitted.
As an example, suppose actor "A" changes world from W0 to W1 and that there are three peers P, P0, P1 and P2. "A" belongs to P and all events stem from P. P is initially connected to W0, then connects to W1 and disconnects from W0. P0 is connected to W0, P1 is connected to W1 and P2 to both W0 and W1.
The following callbacks occur at the different peers:
[1] C Carlsson and O Hagsand, "Dive - A Platform for Multi-User Virtual Environments", "Computers and Graphics", 17(6), 1993
[2] Dive 3.0 file format interface, 1995
[3] E. Frécon and O. Hagsand, The DIVE/TCL Behaviour Interface, Dive 3
Reference Document, 1995, available at
<http://www.sics.se/dive/manual/tcl-behaviour.html>.
[4] E. Frécon and O. Hagsand, "The Dive Client Interface", Dive 3
Reference Document, 1995, available at
<http://www.sics.se/dive/manual/dci.html>