||| O o Electro -
Electro is an application development environment designed for use on cluster-driven tiled displays, virtual reality systems, and desktop workstations. Electro is based on the MPI process model and is bound to the Lua programming language. With support for 3D graphics, 2D graphics, audio, networking, and input handling, Electro provides an easy-to-use scripting system for interactive applications spanning multiple hosts and a variety of displays.
This document details the functions and data types of the Electro API. A knowledge of the Lua Programming Language version 5.0 is prerequisite. Lua documentation and tutorials may be found at the official Lua site. A tutorial example of the use of the Electro API with Lua is included here.
Electro API function definitions appear here as follows:
Invoke function with arguments foo, and optionally bar, giving baz.
Deprecated functions may be removed in a future release. Deprecated function definitions appear here as follows:
Invoke oldfunction with arguments foo, and optionally bar, giving baz.
This document includes a number of Lua code examples. These examples are distinguished from the main text as follows:
This document also includes a number of paragraphs giving design rationale. These describe some of the trade-offs and design decisions made during the development of Electro. They are presented here in the hope that they will provide the reader with a more thorough understanding of the details of the implementation. Rationale paragraphs are distinguished from the main text as follows:
The implementation of Electro adheres to a number of closely-held design principles: simplicity, orthogonality, and efficiency.
Electro accepts the following command line arguments. All arguments with the extension .lua are taken to be Lua scripts to be executed in order. All unrecognized arguments are copied to a table in the Lua environment called E.arguments. This table is populated before any script is run, so all scripts are free to access arguments there.
Execute the named Lua script. This may be used to execute script files that lack the .lua extension.
Grab the mouse pointer. Normally, mouse motion events are only detected while the pointer is within the Electro window. This limits the useful range of mouse motion to the size of the window. When the mouse pointer is grabbed, an application can track mouse motion over unlimited distances. This is useful to applications that implement a pointer that spans a large tiled display.
Disable audio playback. Audio processing will appear to proceed normally, but the audio hardware will remain untouched. This is useful when running on hardware without audio support, or when running Electro along side an application that requires exclusive access to the audio hardware.
Log all console output to the named file.
Use the given TCP port as network console. The default is 0, and remote console access is disabled.
Use the given key value to access trackd tracker information. The default is 4126.
Use the given key value to access trackd controller information. The default is 4127.
Use the given trackd sensor index as head tracker. The position and orientation of this sensor will be applied to all cameras. The default is zero.
Process the given Hipparcos stellar catalog into an Electro galaxy file.
Process the given Tycho stellar catalog into an Electro galaxy file.
The Electro API is encapsulated in a Lua namespace “E”. The namespace specifier is omitted in this documentation, though it is included in the examples. Be sure to precede all Lua function and constant references with the “E” namespace specifier, or they will be reported as undefined.
E.set_background(0.0, 0.5, 1.0)
These are the major functional sections of the Electro API:
The core of any Electro application is the scene graph. The scene graph is a very common organizing scheme in 3D graphics, and examples of its use abound. Other scene graph libraries include Open Inventor, Blitz3D, Open Scene Graph, OpenSG, and many others. Users of other scene-graph-based libraries should find the Electro API unsurprising.
Scene graph functionality is organized into a small class hierarchy. The entity base class handles all of the common properties and behaviors of scene graph elements, most notably 3D transformation, and the parent-child relationships that hold a scene hierarchy together. The subclasses handle the specifics of controlling the view and lighting, drawing 3D and 2D geometry, etc. The class hierarchy is as follows:
Constructor functions instantiate scene graph objects.
Load an OBJ format 3D object and return an Electro object entity. This is the normal means of importing 3D geometry into an Electro application. It supports polygonal geometry in OBJ file format, including material files and texture maps. The OBJ export capabilities of Maya, Lightwave, Wings3D, and Milkshape are known to be compatible.
The Electro OBJ loader lacks support for free-form curve specification. This is actually due to the fact that the Electro renderer lacks the ability to render free-form curves. Any curve specifiers appearing in OBJ files will be silently ignored. If curves are required, tessellate them using your favorite 3D modeler.
Create a sprite entity using the given brush. A sprite consists of a single quadrilateral. The default size of the sprite object is equal to the size of the brush's image. Commonly, sprite objects are used as billboards in 3D scenes, or are displayed as 2D overlays using an orthogonal camera.
Create a string object using the current typeface and the given text. A string object is a polygonal model one unit in height. It sits in the XY-plane, with its lower-left corner at the origin.
Create a camera of the given type. To be visible in a scene, all entities must be descendants of a camera entity. Because of this, cameras are commonly left unparented and allowed to remain at the root. Here are the defined camera types:
An orthogonal camera uses an orthogonal projection. By default, the aperture of an orthogonal camera matches the total size of the current display, which is appropriate for pixel-correct 2D overlays.
A perspective camera uses a perspective projection. By default the aperture of a perspective camera is one unit high, with width determined by the aspect ratio of the total display.
A scene is allowed to include any number of cameras. One reasonable configuration is to include one perspective camera for the display of 3D objects, and one orthogonal camera for the display of 2D overlays.
Create a light source of the given type. To be illuminated, all entities must be descendants of a light entity. Conversely, entities which should appear unshaded and fully-bright should not descend from a light entity. Here are the defined light types:
A positional light provides a localized light from within the scene.
A directional light source provides a parallel light from infinitely far away. Light is directed along the vector from the position of a directional light source to the origin of the light's coordinate system (determined by any transformations defined by parent entities).
In the implementation, the only difference between positional and directional light sources is the value of the w component of the homogeneous position of the light. A positional light has w=1 and a directional light has w=0, thus the homogeneous position vector is finite or infinite in length, respectively.
Create a pivot entity. A pivot does nothing, but is useful as a grouping entity. As it has all the properties of an entity, including transformation and render flags, It provides a mechanism by which the transform hierarchy may be extended and controlled.
Load a galaxy definition from the named file and return a galaxy entity. A galaxy entity is a static 3D collection of particles, organized into a BSP structure for efficient rendering.
A galaxy object must have a brush with the examples/data/star.fp and examples/data/star.vp fragment and vertex programs applied to it to render correctly.
The galaxy object should be considered a hack. It has only a very specific use. It will probably be removed in a future revision of the Electro API, or possibly abstracted into a general particle system.
Duplicate the given entity. Cloning allows entities to be instanced within a scene graph. Cloning an entity is more efficient than recreating an entity from scratch, so cloning is often useful in circumstances where large numbers of similar entities are frequently created and destroyed.
Note, however, that a clone is a shallow copy of the original. A clone has all of the attributes of a distinct entity, but it shares the attributes specific to its derived type. For example, if a scaling operation is applied to a cloned entity, only that entity will be scaled. However if the text value of a string entity is changed, all instances of the original string will change.
The following functions act on entities. The entity argument of each function may take any entity value, including object, sprite, camera, light, and pivot.
Include entity as a child of parent. This will cause entity to be drawn in the coordinate system of parent, using its graphics state. If entity is already the child of some parent entity prior to the call, it is cleanly removed from that parent's child list. An entity may be unparented by specifying a parent entity of nil.
Remove entity from the scene hierarchy and release all resources associated with it. Any children of entity will be recursively deleted as well. If entity is a clone, then the entity itself will be removed, but any resources shared by other instances of the same entity will remain.
Return the parent of entity, or nil if it is unparented.
Return the nth child of entity, or nil if it has no such child. Unparented entities may be referenced as children of nil. The first child is at index 0.
Specify the position of the entity. Position is given in the coordinate system of the entity's parent.
Specify the rotation of the entity. The 3 values give the angles of rotation in degrees about the X, Y, and Z axes. Rotation is given in the coordinate system of the entity's parent.
Specify the scale of the entity. The 3 values give scale multipliers along the X, Y, and Z axes. Scale is given in the coordinate system of the entity's parent.
Specify the axis-aligned bounding box of the entity. The 6 values give the minimum and maximum X, Y, and Z values in object coordinates.
To enable view culling based on the given bound, set entity_flag_bounded. Keep in mind that object, sprite, and string bounds are computed automatically, and manually-set boundaries are not likely to be used. The intended use of set_entity_bound is the specification of pivot bounds for hierarchical view culling.
Specify the tracking parameters of the entity. If entity_flag_track_pos or entity_flag_track_rot is set on the entitiy, it will track sensor number sensor using one of the following tracking modes:
Position and orientation are given in the coordinate system local to the viewer. These are raw tracking values as received from the sensor. These are useful when the sensor transform is applied to camera navigation.
Position and orientation are given in the world coordinate system. These are useful when using tracking to position objects within a scene.
Strictly speaking, to provide both absolute and relative transformation functions is to violate the principle of orthogonality. In this case, I just couldn't resist. Inspiration for this feature is drawn from Blitz3D, which showed that relative transform is very beginner-friendly, leading to a very intuitive turtle-style system of entity control.
Move the entity relative to its current position. X is to the right, Y is up, and Z is to the rear, as defined by the entity's current orientation.
It might be more clear to the beginner if the Z axis to pointed forward rather than back. However, this would be in conflict with the normal right-handed coordinate system, and would only lead to inconsistency and confusion for the experienced 3D user.
Rotate the entity relative to its current orientation. Rotation about the X, Y, and Z axes corresponds to pitch, yaw, and roll, respectively.
Specify the transparency of the entity. A value of 1.0 is fully opaque and 0.0 is fully invisible. This transparency value propagates down the hierarchy. Transparency values specified by child nodes will accumulate. That is, if a parent and a child both specify alpha=0.5 then the child will appear with a transparency of 0.25.
Return the position (x, y, z) of the entity in local coordinates.
Return the vector pointing to the right from the entity in local coordinates.
Return the vector pointing up from the entity in local coordinates.
Return the vector pointing to the rear of entity in local coordinates.
Return the scaling of the entity along the local X, Y, and Z axes.
Return the minimum and maximum X, Y, and Z values of the entity. This may be used to determine the extent of an object or sprite. This is useful when computing pivot bounds for hierarchical view culling, or when positioning entities on-screen.
Return the transparency value of the entity.
Set or clear flags on the given entity. Entity flags enable and disable extra features in the entity hierarchy. These flags act not only on the entity that carries them, but also on the children of that entity. The flag parameter gives the set of flags to be modified, and may be the sum of multiple flags. The value parameter is a boolean giving the desired state. A value of true will set the given flags, and false will clear them.
The wire-frame flag causes an entity and its descendants to be rendered in wire-frame. An entire scene may be rendered in wire-frame by setting the wire-frame flag on a camera or light. The application is free to set or clear a wire-frame flag value at one point in the hierarchy and set an opposite value at a lower point. Entities will appear as expected.
The hidden flag causes an entity and its descendants to be omitted from rendering. Unlike the wire-frame flag, the hidden state cannot be reversed lower in the hierarchy, as it actually causes traversal of the hierarchy to be pruned.
Entities with the billboard flag are drawn facing the camera, regardless of their actual orientation. In effect, all rotations and translations are applied as usual, so the entity will be positioned in space as expected, but an extra rotation is applied in order to re-aim the entity's Z axis toward the camera.
Due to the manner in which the billboard transformation is implemented, scaling operations will not transform billboard entities below them in the hierarchy. This is a minor limitation in practice, as scaling is normally applied near the leaves of the scene hierarchy anyway. The common case of an entity with local scaling and a local billboard flag will work properly, but when in doubt, scale below bill-boarding.
Entities with the bounded flag are rendered only when their bounding box falls within the view frustum of the current camera. Objects, sprites, and strings have automatically computed bounding boxes, so they are automatically given the bounded flag. Other entities may be assigned a bounding box using set_entity_bound. When an entity is culled it behaves is though it is hidden and traversal of the hierarchy is pruned.
Entities with the position-tracked flag have their positions updated each frame to match a sensor position, if available. This is useful for implementing head or wand tracking in an immersive VR environment. Tracking parameters may be configured using set_entity_tracking. If an application requires the position of the tracker without reference to any visible entity, the position-tracked flag should be set on a pivot entity and the pivot's position queried with get_entity_position.
Entities with the rotation-tracked flag have their orientations updated to match a sensor rotation, if available. Again, this is useful in immersive VR applications. Tracking parameters may be specified using set_entity_tracking. The orientation of a tracker may be queried by setting the rotation-tracked flag on a pivot and calling get_entity_x_vector, etc.
These flags behave similarly to entity_flag_hidden. They allow the entity hierarchy to be pruned selectively during stereo rendering. Entities with entity_flag_left_eye are hidden while the right eye view is rendered, and vice-versa.
These flags enable a form of visual debugging for physical entities. Body-entities designated using set_entity_body_type are displayed with a coordinate axis indicating center of mass and orientation. Geom-entities designated using set_entity_geom_type are displayed with a wireframe outline indicating their exact collidable shape.
Return true if flags are set on the entity.
Electro uses the Open Dynamics Engine for collision detection and rigid body dynamics. These are broad topics, and ODE is a complex library. To fully document Electro's dynamics support would be to fully reproduce the ODE documentation. So in the interest of brevity, only Electro's interface to ODE is presented here. Interested readers should consult the full ODE documentation. Electro exposes most, but not all, of ODE's functionality. The API is simplified and heavily reduced, but the concepts are the same. Any ODE types and parameters not defined here are not supported by Electro.
In short, a rigid body system is composed of “geoms”, “bodies” and “joints”. A geom is a simple solid: a sphere, box, cylinder, or plane. A body is a compound solid: a rigid arrangement of one or more geoms. A joint is a non-rigid connection between bodies. Geoms define the collision characteristics of an object. Bodies define the physics characteristics of an object. Joints define the behaviors of articulated objects.
Bodies and geoms are defined using the normal Electro hierarchy. An entity may be marked as a body, as a geom, or as both. All geom-entities within the hierarchy of a body-entity are geoms of that body. Child entity positions and rotations define the arrangements of geoms within bodies.
Mark an entity as body. If type is true then the position and rotation will be updated each frame according to the parameters of the physical system. If false, the entity will remain exclusively user-controlled. The default is false.
Mark an entity as a geom and define its shape. This geom will become a part of the nearest body defined above it in the entity hierarchy. The child entity's transformation defines the geom's position within the body, and so affects the collision characteristics, mass, and moment of inertia of the body.
If no enclosing body exists, then the geom is rigidly attached to the environment. It will act in collision, but will not respond physically. This is the normal mechanism for creating solid scene geometry.
The following geom types and shape parameters are allowed:
No physical representation. This is the default.
A box with lengths x, y, z centered at the origin.
A sphere of radius r.
A cylinder with spherical end caps, oriented along the Z axis. The radius of the cylinder is r and its length is l.
An infinitely thin line from the point (px, py, pz) along the length of vector (vx, vy, vz).
Note: the ray is a non-colliding geom type. It can detect collision and generate contact callbacks, but it does not respond to collision physically. It is useful when finding a selected entity in response to a mouse click, or when determining whether a gunshot would hit. It can also be used as an entity trip-wire.
A plane satisfying the equation ax + by + cz = d.
Note: the plane is a degenerate geom type. It cannot act as part of a body and must be attached to the environment. It is defined only by the parameters given at creation time and does not respond to entity transformation. Planes are commonly used to define floors or walls to contain the physical system.
Define a joint between the two given body-entities. If a given entity is not a body-entity or is nil then the joint will be rigidly attached to the environment. The following joint types are defined. For detailed descriptions and images of these joints, see the ODE documentation.
Bodies, geoms, and joints have a variety of attributes defining their behavior. The following enumerations define these attributes and the functions provided to manipulate them. The functions take arguments of varying number and type, and all numbers and types are checked for correctness against the named attribute.
Set one of the following attributes on the given body-entity.
If true, the force of gravity will act on this body. If false, this body will behave weightlessly. The default is true.
Set one of the following attributes on the given geom-entity.
The category value is a 32-bit field allowing geoms to be classified. 32 categories are defined and geoms may be assigned to these categories as the application demands. If a bit in the category bit field is set then the geom belongs to that category. The default is 0xFFFFFFFF and all geoms belong to all categories.
The collider bit field uses the category bit field to determine if two geoms should be tested for collision. Given geoms A and B, if (categoryA ∧ colliderB) ∨ (categoryB ∧ colliderA) then collision will be tested. The default is 0xFFFFFFFF and all geoms are tested against all others.
The response bit field uses the category bit field to determine if two colliding geoms should respond physically in any way. If (categoryA ∧ responseB) ∨ (categoryB ∧ responseA) then the geoms will impact or bounce as their attributes define. The default is 0xFFFFFFFF and all collisions respond physically.
The callback bit field uses the category bit field to determine if two colliding geoms should be reported to the application. If (categoryA ∧ callbackB) ∨ (categoryB ∧ callbackA) then the do_contact callback will be invoked with arguments describing the collision. The default is 0x00000000 and no collisions are reported.
These bit fields define 4 useful combinations: 1) Non-interacting objects might include the particles of an explosion or cloud effect. 2) Unreported colliding objects might include a car's tires rolling on a road. 3) Reported colliding objects might include a bullet hitting a target. 4) Reported non-colliding objects might include a car crossing a finish line. The bit field defaults produce combination 2 for all geoms.
The mass of the entity.
The coefficient of restitution, or bounciness of an entity. This determines the fraction of the energy entering a collision that remains in the system leaving it. When two geoms of differing bounce collide, the maximum of the two values is used. This value should be between 0 and 1. The default is 0.5
The coefficient of friction of an entity. This determines the ease of sliding along the surface of an entity. When two geoms of differing friction collide, the minimum of the two values is used. This value should be between 0 and infinity. The default is infinity.
The Error Reduction Parameter and Constraint Force Mixing value determine the sponginess and springiness of a surface, respectively. For details, see the ODE documentation's discussion. When two geoms of differing values collide, the minimum ERP and maximum CFM are used. ERP should be between 0 and 1. The default is 0.2. CFM should be positive but small. The default is 0.01.
Set one of the following attributes on the joint between the given bodies. Most of these attributes are scalar values, but a few are vectors.
The point (x, y, z) of a ball, hinge, hinge2, or universal joint.
The primary axis vector (x, y, z) of a hinge, slider, hinge2, or universal joint.
The secondary axis vector (x, y, z) of a hinge2 or universal joint.
The minimum and maximum values of the primary and secondary joint attributes. For a rotating joint such as a hinge, these values define the minimum and maximum angles, in degrees. For a moving joint such as a slider, these define the minimum and maximum linear extensions.
Note, ODE requires that these angles be specified in radians, but Electro generally requires that angles be specified in degrees. Degrees are converted to radians here in order to ensure consistency across the Electro API.
The velocity and force applied by a joint motor. These enable the animation of bodies through the application of articulating forces at joints. The velocity attribute gives the desired linear or angular rate of change for the joint and the force attribute gives the maximum force or torque to applied attempting to meet this goal. These attributes can also simulate joint friction when given a zero desired velocity and a non-zero maximum force.
The bounciness and CFM of the joint between stops.
The ERP and CFM of a joint's lo_stop and hi_stop. These define the sponginess and springiness of the limits of the joint.
The ERP and CFM of a suspension joint. Currently, only the hinge2 joint defines suspension along its axis.
The following functions allow the attributes of the physical system to be queried. Most queried attributes are scalars, but a few are vectors. These query functions will return 1 or 3 values depending on the attribute.
Return the value of the corresponding body attribute. All of the settable body attributes defined above may be queried. In addition, the following attribute may be queried but not directly set:
The offset (x, y, z) of the center of mass of a body.
The center of mass of a body is a slightly sticky issue. ODE requires that the center of mass be at the origin of a body's local coordinate system. However, applications are free to distribute collision geoms and visible geometry arbitrarily in this coordinate system. To compensate, Electro translates a body, its geoms, and all local visible entities to center the body's mass. This means that an asymmetric rigid body might not appear where the application places it, and it therefore might not rotate about its intended center. Applications can query this center of mass offset in order to work around this limitation.
Return the value of the corresponding geom attribute. All of the geom attributes defined above may be queried.
Return the value of the corresponding joint attribute. All of the joint attributes defined above may be queried. In addition, the following attributes may be queried but not directly set:
The angle of rotation (in degrees) or distance of extension of a joint.
It is not possible to query all of the axes of rotation of multi-axis joints. This is an unexplained limitation in ODE.
The angular velocity of a rotating joint, or the linear velocity of an extension joint.
Direct Force Application
Joint motors are an incredibly powerful and flexible means of initiating action in a physical system. However, they do not always suffice. The following functions may be used to apply external forces on arbitrary body-entities. These forces accumulate, but are reset each frame. So, if a persistent force is to be applied to a body then it must be reapplied during each update.
Apply force to entity with the magnitude and direction of vector (x, y, z).
Apply torque to entity with the magnitude and axis of vector (x, y, z).
An object is a collection of vertices and meshes. A mesh is a collection of faces and edges. Faces and edges are defined by sets of indices into the object's vertex list. Brushes are applied per-mesh.
All vertices, meshes, faces, and edges are indexed beginning with zero, and all element indices in [0, n-1] are valid, where n is the respective element count.
The following functions allow objects to be created, destroyed, modified, and queried through the manipulation of object element indices.
Add a new mesh to object and return its index. A brush may be applied to the new mesh at creation time, but if none is provided then the default brush will be used.
Add a new vertex to object and return its index. The vertex's position (vx, vy, vz), normal (nx, ny, nz), and texture coordinate (tu, tv) may be specified. If any of these are not provided, default values of (0, 0, 0), (0, 0, 1), and (0, 0) are used.
Add a new triangular face to mesh iM of object defined by the vertices (iV, jV, kV). Vertex order distinguishes the front of a face from the back. Vertices should be appear counter-clockwise when the face is viewed from the front.
Add a new edge to mesh iM of object defined by the vertices (iV, jV)
Object elements are stored in vectors. The addition of a new element is usually a constant-time append operation, but the deletion of an element requires a linear-time traversal of the vector. In addition, a vertex removal necessitates the traversal of the all edge and face vectors, potentially causing removals there. Vertex removal also triggers the re-computation of the object bound. For these reasons, object element deletion can be expensive. Applications should avoid creating and deleting geometry on a per-frame basis.
Remove mesh iM from object. All faces and edges contained by the mesh are deleted as well.
Remove vertex iV from object. The vertex is deleted from the object's vertex vector and all following vertices are shifted to fill in the remaining space. Vertex references in the object's face and edge vectors are updated accordingly, but vertex indices held in Lua variables may be off by one. To ensure the internal correctness of the object and all its indices, any faces and edges referencing the missing vertex are also deleted.
Remove face iF from mesh iM of object. This function does not remove the vertices referenced by the face.
Remove edge iE from mesh iM of object. As with faces, this function does not alter the object's vertex vector.
The deletion of faces and edges can result in unused vertices within an object. This is sometimes desired, but often not. It is left to the application to do the right thing.
Set the brush used to render mesh iM of object.
Set the vector values of vertex iV. The normal and texture coordinate are optional and, if not specified, the existing values are retained.
Like vertex deletion, vertex modification can trigger object bound re-computation. This computation is done only when the bound becomes necessary, so modifying a large batch of vertices at once has the same overhead as modifying a single vertex.
Specify the set of vertices defining face iF. Again, vertices should be listed in counter-clockwise order.
Specify the set of vertices defining edge iE.
Return the brush used by a mesh.
Return the position, normal, and texture coordinate of a vertex.
Return the set of vertex indices that define a face.
Return the set of vertex indices that define an edge.
Return the number of meshes or vertices in an object, or the number of faces or edges in a mesh. All element indices in [0, n-1] are valid.
Set the brush used to display sprite.
Set the texture coordinate rectangle used by sprite. By default, a sprite uses its brush's entire image. This corresponds to texture coordinate rectangle (0.0, 1.0, 0.0, 1.0). However it is frequently useful to display only a subset of a texture on a sprite. For example, a numerical display might use a single texture that contains images of all of the digits 0-9, and select the digit currently displayed simply by modifying the sprite bounds.
Set the text displayed by the given string object.
Modifying a string value is very cheap. When an application requires that an on-screen text element change frequently, changes should be made using set_string_text rather than the deletion and creation of string objects.
Set the fill brush of the string entity.
Set the outline brush of the string entity.
Return the normalized world-space vector corresponding to the display position (displayx, displayy) as viewed from camera. In effect, this provides a mapping between the 2D display definition as specified using set_tile_viewport and its 3D definition specified by set_tile_position. It is especially useful when doing 3D picking using the 2D pointer position determined using do_point. The returned vector (x, y, z) takes into account the current camera offset, determined by set_camera_offset or by head tracking, but not any eye offset specified using set_camera_stereo. If the given point does not fall within any defined tile, then the last known correct world-space vector is returned. The default is (0.0, 0.0, 0.0).
Set stereo options on the given camera. The mode argument gives the stereo method, as described below. The (Lx, Ly, Lz) and (Rx, Ry, Rz) arguments give the offsets from the camera to the user's left and right eyes.
The available stereo modes are as follows:
This mode disables stereo rendering. This is the default.
This mode enables stereo rendering on tracked GeoWall-type displays. Both the left and right eye views are rendered with the given eye offsets, but no other stereo processing is done. It is up to the display configuration to use tile_flag_left_eye and tile_flag_right_eye appropriately to ensure that each view is visible where required.
This mode enables quad-buffered stereo viewing. This is appropriate for active stereo viewing using LCD flicker glasses, or passive stereo viewing using dual-output video hardware in “clone” mode. To function correctly, the underlying graphics hardware must support quad-buffered stereo, and host_flag_stereo must be enabled on the rendering host using set_host_flags at application startup.
This mode enables red-blue anaglyphic stereo.
Set the offset of a camera's view. The camera offset is a vector (x, y, z) giving the real position of the viewpoint relative to the position of the camera entity. This function moves the only apex of the view frustum, not its view rectangle. Thus it modifies the shape of the projection rather than its position.
Camera offset allows a distinction to be drawn between the navigational and projection-defining aspects of camera positioning. In a VR environment for example, the camera entity position represents the position of the display within the virtual space, while the camera offset represents the position of the user's head within the display. In the presence of trackd, Electro automatically updates the offset of all cameras based on the position of the head sensor.
Set the near and far clipping planes for a camera. The default range is (0.1, 1000.0) for perspective cameras and (-1000.0,+1000.0) for orthogonal cameras.
Set an image to be used as off-screen render target for camera. The left, right, bottom, and top arguments define the projection to be applied. The near and far planes of this projection are specified using set_camera_range and the projection is perspective or orthogonal depending on the camera type.
Set the diffuse color of a light source.
Pivots have no type-specific functionality, but they share all of the attributes common to entities.
Set the magnitude multiplier of a galaxy. By default, stars are rendered using their computed luminosity. For all but a few stars, this is far too dim to be visible. The magnitude multiplier can be treated as a linear scale of apparent star size. For example, a magnitude value of 100 will result in the very largest of stars being rendered approximately 100 pixels across.
Return the star “being pointed at” by the given entity. That is, return the index of the star closest to the forward vector of the entity. This is useful for star selection and galaxy navigation, and is particularly well applied to cameras and tracked entities.
Return the 3D position of the star at index iS of galaxy.
Images are used as textures for objects, strings, and sprites. A default image of 128×128 white pixels is always available. It may be referenced using the symbol nil in any context where an image is required.
Electro supports several different image types. Images of all types are created using the create_image function. Image type is distinguished by argument type.
Load a static image from the named PNG or JPEG file.
A given image file will only ever be loaded once. Calling create_image a second time with the same filename will result in the same image object.
Some hardware requires that image width and height be powers of two. If support for non-power-of-two images is available, Electro will use it. If a non-power-of-two image is used on hardware that does not support it, then the image will appear white.
Load a set of cube map images. All 6 cube map images must be the same size. If the image is to applied as a cubic environment map, applications must set brush_flag_env_map on any brush referencing it. Pixel queries act only on the first image of a cube map.
Create flip-book animated image. For optimal playback performance, flip-book images are assumed to be in raw data format. Pixel sizes of 4, 3, 2, and 1 correspond to RGBA, RGB, luminance-alpha, and monochome formats, respectively. Raw DXT1-compressed RGB images are supported, and are recognized by a .dxt extension.
The pattern argument gives the image file name pattern in C printf format. The width, height, and bytes arguments give the image and pixel size. The frame0 and framen arguments give the first frame number and total frame count to be applied to the file name pattern. The pulldownn and pulldownd give the numerator and denominator of the pulldown ratio, which may be used to adapt the playback rate of an animation to the sync rate of the display.
Create a video stream image using UDP port port. The UDP image protocol is documented here.
Create a blank image using of the given size and depth. A blank image may be used as a render target attached to a camera using set_camera_image.
Delete an image and release all resources associated with it. The image may not be deleted immediately if it is referenced by an existing brush.
In general, applications should explicitly delete any images that they explicitly create. This includes the circumstance where an image is created and assigned to a brush which is subsequently deleted. In that case, the image is not automatically released because it is presumed to be directly referenced by the application. The same create/delete policy applies to brushes.
Return the color value of the (x, y) pixel of an image. This function always returns 4 color components. If the source image does not include all four channels, then values are extrapolated: grey-scale values are copied to all three color channels and opaque textures are assigned an alpha value of 1.
Return the size of the image in pixels.
Brushes describe the appearance of the surfaces of objects, strings, and sprites.
A default brush is always available. It has 80% grey opaque diffuse material, 0% specular, and 20% grey ambient material with a specular exponent of 0. These coincide with the OpenGL defaults. It references the default image. The default brush may be referenced using the symbol nil in any context where a brush is required.
Create a new brush object with the default material properties.
Delete a brush and release all resources associated with it. The brush may not be deleted immediately if it is referenced by an existing entity.
Set the material color properties of brush. The (dr, dg, db, da) arguments give the diffuse color, (sr, sg, sb, sa) gives the specular color, (ar, ag, ab, aa) gives the ambient color, and e gives the specular exponent. Specular, ambient, and specular exponent properties are optional and any not specified retain their existing values.
Select image for use as the texture map of brush. The n argmument gives an optional texture unit number between 0 and 3, defaulting to zero.
Set or clear flags on the given brush. Brush flags enable and disable the application of various material properties. The flag argument gives the set of flags to be modified, and may be the sum of multiple flags. The value argument is a boolean giving the desired state. A value of true will set the given flags, and false will clear them.
These flags control the application of each of the material color properties. If any of these flags is false then the corresponding material is not applied at all. This provides applications with a mechanism to control how material properties to trickle down the entity hierarchy.
Surfaces with a transparent brush are drawn to the color buffer but not the depth buffer. This prevents transparent objects from occluding opaque objects during the depth test.
An environment map is dynamically applied to a surface based upon the surface normal and view direction. It creates the illusion that the surface is reflecting an image of the scene. The environment map brush flags enable this feature on each of the four texture units. To appear correct, an environment map image object should be bound to the corresponding brush image unit.
A sky map is dynamically applied to a surface based upon the location of each point of the surface. This is useful when creating sky spheres and boxes using environment map image objects. When an environment map image is bound to the sky surface's brush the result is a sky scene that compliments the scene reflected in environment mapped surfaces.
Specify a fragment shader to be applied to brush. The file argument gives a text file in GLslang syntax. To remove a fragment shader, specify nil for the file argument.
Specify a vertex shader to be applied to brush. The file argument gives a text file in GLslang syntax. To remove a vertex shader, specify nil for the file argument.
Specify a uniform sampler to be applied to brush. The name argument gives the name of the uniform, which must correspond to a uniform sampler declared in the brush's fragment shader or vertex shader. The T argument gives the sampler's texture unit number.
Specify a uniform vector to be applied to brush. The name argument gives the name of the uniform, which must correspond to a uniform vector declared in the brush's fragment shader or vertex shader. The (x, y, z, w) arguments give optional values.
Specify a uniform matrix to be applied to brush. The name argument gives the name of the uniform, which must correspond to a uniform variable declared in the brush's fragment shader or vertex shader. Supported matrix sizes include 2×2, 3×3, and 4×4. The variable argument list gives the uniform values.
Specify a fragment program to be applied to brush. The file argument gives a text file in ARB fragment program syntax. To remove a fragment program, specify nil for the file argument.
Specify a vertex program to be applied to brush. The file argument gives a text file in ARB vertex program syntax. to remove a vertex program, specify nil for the file argument.
Specify a local parameter to be accessible to brush's fragment program. The param argument gives an index between 0 and 96. The (x, y, z, w) arguments give optional values.
Specify a local parameter to be accessible to brush's vertex program. The param argument gives an index between 0 and 96. The (x, y, z, w) arguments give optional values.
Specify the width in pixels of all lines drawn using this brush. The default is 1.0. This will apply both to lines defined by OBJ models and to entities drawn in wire-frame mode.
Electro provides a basic audio API suitable for adding simple sounds to an application. It supports playback of 44.1 KHz stereo or mono Ogg Vorbis audio files. Any number of voices may play simultaneously.
Open a reference to the named Ogg Vorbis file. This is the normal means by which audio is imported into an Electro application. This function initializes a sound for playback, but does not start playback.
Close a sound and release all resources associated with it.
Start playback of a sound. If sound is already playing when this function is called, then the original playback will stop and the sound will be rewound to the beginning before being restarted. If it is necessary to mix multiple instances of one specific sound, then multiple sound objects must be used.
Begin playing a sound, and automatically rewind it when the end is reached.
Stop a playing sound. This function merely stops playback, and does not release any resources. The sound may be restarted from the beginning.
Set the playback amplitude (volume) of a sound. The amplitude argument should be a value between 0 (silent) and 1 (normal volume), though it may be higher if gain is desired. Negative values will be clamped at zero.
Set the playback frequency (pitch) of a sound. The frequency argument is a playback rate multiplier, so a value of 2 will cause the sound to play twice as fast normal. For reference, music playing with a frequency of 2 will sound one octive higher than normal, and will play at double tempo. Negative values will be clamped at zero.
Specify entity as the receiver. Any sound associated with an entity will be mixed according to that entity's position with respect to this receiver entity. The distance argument gives the maximum hearing range of the receiver. Sound is attenuated as the distance to an emitting entity appreaches this value, and any emitting entity outside of this range will be unheard. Commonly a perpective camera is used as a receiver. If the receiver is nil then all sounds will play at normal volume regardless of associated entity positions.
Associate sound with entity. The sound will be mixed in stereo according to the position and distance of the associated entity from the receiver entity. Sounds associated with entity nil will play at normal volume regardless of receiver position.
Electro uses a text console overlay to display error messages and enable run-time interaction with Lua state. This console can be enabled and disabled by pressing F1. It also appears automatically whenever anything is printed to it. Applications are free to use this console for their own purposes as well. For example, debugging information may be sent there.
Print all string and number arguments to the console. To print formatted output, pass arguments via Lua's string.format function.
Clear the console to blank.
Remove the console from the screen.
Set the console text color to (r, g, b).
Add a host, returning a host index. This function is used by configuration scripts to define the structure of the cluster driving a tiled display.
The name argument gives the Internet host name of the rendering node to be used. The x, y, w, h arguments give the position and size of the area of that host's desktop to be used for OpenGL rendering. A given render node can only support one Electro host. If the same name argument is reused for multiple configurations, only the first will be used. If name is “default” then the given host configuration will be applied to all hosts not specifically named in another configuration. If a render node is to handle multiple displays, they must be defined as Electro tiles.
Host configuration and rendering context creation is closely bound with MPI process initialization, so it must be performed immediately upon application startup, and cannot be modified later in an application's execution.
Set or clear host flags on host. The flags argument gives the set of flags to be modified and value gives the desired state. Like host window configurations, host flags must be specified at application startup and later modification will have no effect. The default value for all flags is false.
The full flag sets a full-screen flag on the host's render window, causing it to fill the display, possibly switching the resolution of the display to match the configuration. This flag may be necessary to remove window decoration or other operating system screen clutter.
The stereo flag enables quad-buffered stereo rendering on a host's render window. If this flag is not specified at startup, later use of stereo_mode_quad will fail.
The framed flag enables window decoration on a host's render window. Unconfigured host windows are framed by default, but configured host windows are not.
Full-screen and frame handling are notoriously unpredictable. Both are subject to the whim of the operating system, the window manager, and the display. Getting this right may take some experimentation. Also keep in mind that the host's window position (x, y) is measured from the upper left, while the tile's window position is measured from the lower left.
Add a tile to a host, returning a tile index. The x, y, w, h arguments give position and size of the area of the indexed host's render area to be used for display.
There is a static limit of 8 tiles per host.
Set the world-space position of tile. The (ox, oy, oz) arguments give the position vector of the origin of the tile, usually the real-space lower-left corner of the display to which the tile is rendered. The (rx, ry, rz) arguments give the “right” vector, from the origin to the lower-right corner. The (ux, uy, uz) arguments give the “up” vector, from the origin to the upper-left corner.
These three vectors, with the view position vector, define the view frustum of the indexed tile's perspective projection. The default view position vector is (0, 0, 0), though this is subject to the motion-tracked offset of any perspective camera used during rendering.
Set the pixel area of tile. This defines the range of any orthogonal camera used during rendering.
Specify a world-space plane of reflection to be applied to the view position vector when rendering to tile. The (x, y, z) arguments give the plane normal, and d gives the plane offset from the origin along the normal. This allows a correct view frustum to be computed on PARIS and IDesk4 systems, where the view position vector is dynamically tracked, but the reflection of a tile is viewed in a mirror. Reflection must be enabled by setting the tile_flag_mirror option.
Set or clear tile flags on tile. The flags argument gives the set of flags to be modified and value gives the desired state.
The mirror flag enables projection of the view position vector across the plane given by set_tile_mirror>.
The flip flags cause the scene rendered to the tile to be flipped horizontally or vertically, respectively. This may be used to correct tiles viewed by reflection in a mirror.
These flags behave similarly to entity_flag_left_eye and entity_flag_right_eye. They allow the display to be pruned selectively during stereo rendering. Tiles with tile_flag_left_eye display only the left eye view of a stereo camera and tiles with tile_flag_right_eye display only the right eye view. This is useful with a tracked stereo configuration such as a GeoWall or ImmersaDesk 4, where the stereoscopic effect is the result of separate viewpoints rendered to separate tiles. A stereo camera with stereo_mode_tile should be used in such a configuration.
Set the Varrier line screen parameters for tile. These are only significant for stereo_mode_varrier camera modes. They give the line screen pitch, angle of rotation about the tile's Z axis, optical thickness (shift along the tile's Z axis), shift along the tile's X axis, and duty cycle (percentage of black).
Return the total pixel size of the display. The return values x, y, w, h give the position, width, and height of the rectangle of available pixels. This is the union of the viewports of all tile definitions. This information is often useful when positioning entities in view of an orthogonal camera, or configuring a scene to match the aspect ratio of a display.
Return the axis-aligned bounding box of the entire display, in world coordinates. This information is useful when positioning entities in view of a perspective camera.
Set a transform to be applied to tracker sensor index. The 4×4 transform matrix is given in column-major order:
Exit Electro cleanly. This function should be used instead of Lua's os.exit function in order to ensure that processes running on client hosts of a cluster display are properly exited.
Change the current working directory to path. The previous working directory will be lost.
Push the current working directory to the directory stack and change to path.
Pop the previous current working directory from the directory stack and change there.
This symbol is bound to a table of command line arguments. Any arguments not recognized by Electro are passed along to the application in this fashion.
Set the background color of the display. If only one color (Tr, Tg, Tb) is specified, the background will appear a solid color. If an optional second color (Br, Bg, Bb) is supplied, the background will be drawn with a top-to-bottom gradient. The default background has the gradient (0.0, 0.0, 0.0) to (0.1, 0.2, 0.4).
Set the typeface to be used for all subsequently created string entities. The filename gives a TrueType font file.
The optional epsilon parameter gives an error bound in world units to which glyphs are tessellated. This allows the application to make a quality-speed trade-off, favoring finely tessellated text for magnified string entities, and coarse text for minimized string entities. The default epsilon value is 0.001.
The optional outline parameter gives the width of the glyph outline. The default value is 0.0 and glyphs are rendered without outline.
Applications that use multiple typefaces need not be concerned about the cost of switching typefaces. The overhead of loading a new typeface is incurred only the first time. Applications are free to switch from one typeface to another and back again without penalty. Note, however that two typefaces with different epsilon or outline values are distinct even when loaded from the same TrueType font file.
Enable or disable the do_timer callback. If enabled has value true then callback will occur.
Return the current state of a keyboard modifier. The return value is true if the modifier key is down. The queriable modifiers are:
Return the current value of a pair of axes of joystick number. The axisx and axisy arguments optionally give desired axis numbers. The defaults are axes 0 and 1. Requests for the values of non-existant axes will return 0.
There is no direct mechanism provided to determine the number of joysticks connected to the system. The capability exists in SDL, but it isn't really necessary in Electro. If an application needs to count joysticks, it should observe the device numbers received by the do_joystick callback. For example, allow the user to select the number of active joysticks by pressing Start on each.
Callback functions are the mechanism by which Electro Lua applications respond to user interface events. An application may define these functions as needed. If a function exists then it is invoked when the corresponding event occurs. Callback functions should return a boolean value to indicate whether the event resulted in a dirty screen. Returning true schedules a screen update to occur at the next opportunity.
This callback is invoked whenever the mouse pointer moves within the Electro main window. Motion is reported relatively, so the pointer may move an unlimited distance in any direction. Absolute position is not reported. If absolute mouse position is necessary, then it must be tracked manually, as follows:
mouse_x = 0 mouse_y = 0 function do_point(dx, dy) mouse_x = mouse_x + dx mouse_y = mouse_y + dy return true end
This callback is invoked whenever a mouse button is pressed or released. The b argument gives the button number, 1, 2, 3, etc. The s argument is a boolean giving button state. A value of true indicates the button has been pressed, and false indicates it has been released. Note, on most modern systems mouse wheel up and down are reported as presses of buttons 4 and 5. Button press events on wheel buttons do not have accompanying release events.
The do_timer callback is invoked regularly while idling is enabled. The dt argument gives the amount of time, in seconds, that has passed since the last time the callback was invoked. The rate of callback is not defined, but it will happen as often as is possible. The do_timer function is intended to be used to update animations and other background processes. Applications should be sure to return true in order to force an update to the display.
If an absolute measure of time is necessary, applications should accumulate the dt parameter, just as they would accumulate relative mouse motion.
time = 0 E.enable_idle(true) function do_timer(dt) time = time + dt return true end
The update rate of the do_timer callback is deliberately obscured because it is nearly impossible to guarantee. While it might make sense to allow an application to request a callback rate, this request can only be precisely filled in a limited number of cases. Just trust the dt.
This callback is invoked immediately before a frame is rendered. This is useful for operations that should be performed exactly once per frame.
In general, events are queued and several events are handled during each frame period. This is necessary because rendering is usually more expensive than event handling, and re-rendering after each event leads to sluggish performance. Often, the most efficient event-handling organization is to accumulate events as they arrive (as in the do_timer and do_point examples) and use the resulting totals to update the scene at the last moment.
Unlike other callbacks, the “dirty” flag return value from do_frame is ignored, as a redraw has already been scheduled.
This callback is invoked whenever a key is pressed or released. The s argument is a boolean giving the key state. The k argument gives a key identifier. For most keys, this gives the ASCII value of the unshifted character. For non-ASCII keys and modifiers it is a unique identifier outside of the range of ASCII. Here is a full listing of keys and their associated value symbols. When in doubt, the value of a key may be determined interactively as follows:
function do_keyboard(k, s) if s then print(k, "down") else print(k, "up") end return false end
This callback is invoked whenever a joystick button is pressed or released. The n argument gives the joystick device number. The b argument gives the button number. The s argument is a boolean giving button state. Applications respond to button presses in an event-driven fashion, but they should read joystick axis input more continuously. Usually joystick axes are acquired by calling get_joystick in a do_timer callback.
This callback is invoked when a rigid body collision has been detected between two bodies with a geom_attr_callback category bit set. The entityA and entityB arguments give the entities (in no specific order), (px, py, pz) gives the point of collision, (nx, ny, nz) gives the normal vector of the collision, and d gives the depth of penetration of the two geoms (assuming their CFM values permit penetration.)
Keep in mind that a collision can produce multiple contacts, so more than one may be reported. For example, a box sitting flat on a floor makes contact across an area larger than a point. This may be reported as multiple point contacts. Similarly, a soft or non-responding collision will be reported multiple times. Soft impacting bodies remain in contact for several frames, and contact will be reported each frame. Non-responding colliding bodies are allowed to pass through each other, and contact will be reported every frame during which they intersect.
rlk (at) evl.uic.edu