Dave's Graphics Library (DGL) ----------------------------- Intro ----- DGL is a graphics library designed to support networked applications. The library has two components a renderer/platform indepedant part which provides graphics primitives and basic geometric operations and one or more renderer dependant parts which perform rendering for specific platform/renderer combincations. The renderer independant types are defined using CTM so that they can be marshalled and unmarshalled using the CTM library. The renderer supports user input using the mouse and keyboard in addition to notifying clients of other events such as resizing and window close events. The DGL renderer is also (depending on the platform) capable of handling multiple drawables (objects which graphics are renderered to) on multiple displays and supports both on and off screen rendering. DGL provides the following graphics primitives: - Basic primitives: cone, cuboid, cylinder, disk, face set (set of polygons), point set, polyline, sphere, text, triangle strip, quadrilateral mesh - Lights: directional, spotlight, point light, ambient - Structuting: group, switch, LOD - Misc: property, transformation Also to support these primitives, several simpler types are defined - ordinates, components of points, matrices etc (dgl_ordinate_t) - angles (dgl_radian_t) - 2D point (dgl2_point_t) - 3D point (dgl3_point_t) - 3D homogeneous point (dgl3_hpoint_t) - 3D homogeneous matrix (dgl3_matrix_t) - quaternion (dgl3_quat_t) - "6D" points - position + orientation (dgl3_6point_t) - bounding spheres (dgl3_bsphere_t) - ray/line - origin + unit direction vector (dgl3_ray_t) - colour (dgl_colour_t) - material (dgl_material_t) - texture (dgl_texture_t) - viewpoint (dgl3_viewpoint_t) Every type defintion ("_t" suffix) has a corresponding type with a "_p" suffix which is defined to be a pointer to that type (eg dgl3_point_t and dgl3_point_p) Primitives can be rendered in arbitrary locations in space or attached to a "visor" (as in DIVE) which is positioned in front of the viewpoint and parallel to the view plane. Supported File Formats ---------------------- Using CTM it is possible to read and write a collection of DGL primitives (in either ACII or binary formnat) to a file. In addition to this other more "standard" file formats are supported. Currently, DGL supports reading primitives from AC3D format files. VRML support is planned and currently being implemented. It is also planned to support reading textures from GIF, JPEG & IRIS RGB format files. Units ----- Distances in DGL are in metres and angles are in radians. Naming conventions ------------------ General graphics types and functions will have the prefix "dgl_", 3D types have functions will have the prefix "dgl3_" and 2D types and functions will have the prefix "dgl2_". Renderer functions have the prefix "dglr_". Using DGL --------- The definitive description of the API is in the C header files :-) However, this section will briefly describe the main classes of operation. - dgl.h - main include file and renderer independant API - dgl_types.t - renderer independant type definitions (types designed to be accessible to programmer) - renderer.h - renderer API and defintion of abstract data types (types hidden from programmer) A typical DGL program will perform (some of) the following operations 1 create some primitives 2 localise the primitives so that they are in the format for the current renderer (note "localise" is an explicit oepration since the creation and display of the primitives might happen on differnt machines). 3 create a drawable on which to render the primitives 5 enter an event loop which handles rendering and user input 6 Terminate and delete drawables and primitives * 1 Primitive creation Each primitive type has an associated new function which can be used to create a correctly initialised instance of that primitive type. Once created primitives can be manipulated and hierarchically structered using group primitives - routines are provided to add and remove primitives to group/switch/LOD primitives. * 2 Localising the primitives Before rendering a primitive must be coinverted into a local form. This allows the renderer to optimise the rendering of the primitives in a platform dependant manner. Once localised, the client does not have access to the internals of the primitive since the implementation is platform specific. dglr_primitive_localise() takes a primitve (which may eb a group containing many other primitives) and returns a localised version. Since this fucntion can localise groups of primitives you will only need to call it once for each "tree" of structured primitives. dglr_primitive_localise() can localise either non-destructively or destructively. Non-destructive operation leaves the source primitive unchanged. Destructive localisation destroys the source primitive and re-uses as much of the source primitive's storage as possible to create the localised primitive - this mode is more efficient if the program does not need to re-use the renderer independant version of the primitive. * 3 Creating a drawable Before rendering a drawable object must be created to render onto. You can create more than one drawable and render to them independantly. dglr_drawable_new() create a new drawable object. Currently supported drawables types are - DGLR_NORMAL - creates a window on the specified display - DGLR_X_PIXMAP - renders to an X pixmap which the client can then use. * 4 Rendering primitives Rendering takes place in several stages (to allow maximum control over the rendering process). First the client signals the start of a new frame, then the client sets up any lights and textures. Thirdly the client renders the primitives and finally signals that the frame is complete. 1 dglr_start_frame() starts the rendering process from a specified viewpoint (or with a NULL viewpoint to use the last specified viewpoint). 2 If you are using any lights or textures you must call dglr_setup() on light and texture primitives (on on the groups containing them) to set them up. You need only do this once, unless you modify the lights or textures - if you change them you must call setup again on the frame after you've made the changes. NOTE: You don't have to create a light source - if you don't create any lights a default light source will be provided. 3 Call dglr_render() for each group of primtives you need to render. 4 dglr_end_frame() signals the end of the frame and causes the frame to be displayed. On most renderers (if they support double buffering) you will not see any change until you call dglr_end_frame(). * 5 handling events dglr_callback_set() allows the client to associate callback functions with particular events. dglr_callback_reset() resets the callback for a particular event. dglr_callbacks_poll() can be called to explicitly poll for events, but the preferred method is to call crg_select_loop() and use timer callbacks to handle frame updates. * 6 Tidying up dgl_primitive_delete() deletes renderer independant primitives. dglr_drawable_delete() deletes a drawable. dglr_primitive_delete() deletes localised primitives. There are example DGL programs in $CRGSHARE/examples - dgl_example1.c (AKA graphics_test.c) Creates some primitives and rotates them, almost demonstrates each of the renderer callbacks. - dgl_example2.c (AKA dgl_view.c) Reads a model from a given file and allows the user to navigate around it using the mouse. TO DO ----- - intersection tests - VRML support - texture support - better support for modifying localised primitives Stuff to think about -------------------- - level of detail for spheres/cones/cylinders etc - "quality of service" specification - end frame measures time to render frame - callback mechanism for LOD decisions - shadow generation (project onto ground plane) - support for ground plane/grids - function to test intersection between bounding sphere and viewcone (dgl3_viewpoint_t)