.\"#ident "%W%" %G%
.\"
.\" Copyright (C) 1988, 1989, 1990, 1991 by Kubota Pacific Computer Inc.
.\"         All Rights Reserved
.\" This program is a trade secret of Kubota Pacific Computer Inc. and
.\" it is not to be reproduced, published, disclosed to others, copied,
.\" adapted, distributed, or displayed without the prior authorization
.\" of Kubota Pacific Computer Inc.  Licensee agrees to attach or embed
.\" this Notice on all copies of the program, including partial copies
.\" or modified versions thereof.
.\"
.so /usr/local/lib/tmac/local.me
.ds CT Views, Frames, and Devices
.ds BT \*(Dd Programmer's Guide
.ds h1 9
.PN 175
.L1 V IEWS,
.L2 "F" "RAMES, AND"
.L3 D EVICES
.CH NINE
.EQ
delim $$
.EN
.rs
.sp -1v
This chapter describes the organizational objects: \f2views,
frames\fP, and \f2devices\fP.
\f2Display groups\fP and \f2definition groups\fP are discussed.
Two chapter examples show the same display group added to four
different views, each with a different definition group.
A third example shows combining display objects and definition objects
into the same group. 
Mapping from frame coordinates to device coordinates is also
explained.
Examples and a discussion of pseudocolor devices are
provided at the end of the chapter.
Concepts and terms introduced in this chapter include adding objects
to views; adding views to frames; updating views, frames, and
devices; the device viewport; and pseudocolor. 
.sp -.5v
.H1 "Organizational Objects"
.rs
.sp -.25v
\f2Organizational\fP objects are \*(Dd objects that are used to create
structure in the graphical database.
They are used to collect groups of objects.
Three organizational objects in \*(Dd are views, frames, and
devices.
.sp -.25v
.lp
A \f2view\fP describes a scene.
It is used to collect \f2primitive objects\fP and
their attributes, as well as the \f2viewing parameters\fP
for those objects (cameras and lights, along with their attributes).
.sp -.25v
.lp
Views are collected into \f2frames\fP. 
As shown in \*(FT, multiple views can be collected into one frame,
much like papers are posted on a bulletin board.
A frame is used to define a virtual image.
.sp -.25v
.lp
The frame is assigned, or \f2set\fP, to one or more devices.
A \f2device\fP is an output mechanism used to display a frame.
Examples of devices are the video display, an X-window, an image file,
or a hardcopy device.
Figure 9-1 shows the same frame being set to both an X-window and a file.
Note that a device could be a separate physical entity, such as a
plotter, or it could be one of several X-windows being displayed
on the same screen.
A device can have only one frame attached to it at a time.
.bp
\ 
.(F 
.\"./PS/9.1ps" 2i -1
.sp 2i
.)F "Views, Frames, and Devices" figvfd
.rs
.sp -.5v
.H1 "Overview of Creating Views, Frames, and Devices"
This section presents a brief overview of the steps involved in
creating views, frames, and devices.  Examples and more detailed
explanations are offered later in this chapter.
.lp
To render a scene, you will generally complete the following
steps.  This list is provided mainly as an instructional aid.
(You can revise the order of these steps. For instance, 
example 1 shows the device
created first.  Objects
must, however, be created before things are added to them, and
the update must occur last.)
.sp -.25v
.np
Create a view (\f2DoView <DOVW>\fP).
.sp -.25v
.np
Add display objects and definition objects to the view
(\f2DgAdd-ObjToGroup <DGAOG>, DvInqDisplayGroup <DVQIG>\fP and
\f2DvInqDefinitionGroup <DVQDG>\fP).
.sp -.25v
.np
Set various view features, such as rendering style, clear flag,
background color, view boundary (\f2Dvxxx\fP
functions).
.sp -.25v
.np
Create a frame (\f2DoFrame <DOFR>\fP).
.sp -.25v
.np
Add the view to a frame (\f2DgAddObjToGroup <DGAOG>\fP and
\f2DfInqViewGroup <DFQVG>\fP).
.sp -.25v
.np
Set various frame features, such as frame boundary, frame
justification (\f2Dfxxx\fP functions).
.sp -.25v
.np
Create a device (\f2DoDevice <DOD>\fP).
.sp -.25v
.np
Set device viewport, if necessary (\f2DdSetViewport <DDSDV>\fP).
.sp -.25v
.np
Assign frame to a device (\f2DdSetFrame <DDSF>\fP).
.sp -.25v
.np
Update the device (\f2DdUpdate <DDU>\fP).
.H1 "Adding Objects to Views"
Objects can be added to a view as either definition objects
or display objects.
The \f2definition objects\fP include the cameras and lights for the
view, along with their attributes. 
They are executed during \f2rendering initialization\fP.
These objects are described in Chapter 8.
.lp
The \f2display objects\fP include primitive objects, along with their
attributes and geometric transformations.
They are executed during \f2rendering\fP. 
These objects are described in Chapter 4, 5, and 6.
.lp
Usually, you add display objects and definition objects to
separate groups (see Examples 2 and 3, below).
In certain cases, however, you will want to combine display objects
and definition objects into the same group.
Example 4, below, shows a spaceship/camera group moving through space.
Placing the spaceship and the camera in the same group allows the same 
geometric transformations to be applied to both the primitive object
and the studio object.
.lp
When a view is created with \f2DoView <DOVW>\fP, it has an empty
display group and an empty definition group.
To add display objects to the display group, use
\f2DvInqDisplayGroup <DVQIG>\fP to obtain the handle to the
specified view's display group.  For example, to add \f2sphere_group
<SPHGRP>\fP to the display group of \f2view1 <VIEW1>\fP, the code
would be:
.CL
.(m
C code:

.\"#	ident "@(#)ch10.ex01	1.3" 5/15/91
.\"
DtObject view1, sphere_group;

DgAddObjToGroup(DvInqDisplayGroup(view1), sphere_group);

.sp
\*(Fo code:

.\"#	ident "@(#)ch10.ex01.f	1.3" 5/15/91
.\"
      INTEGER*4 VIEW1, SPHGRP

      CALL DGAOG(DVQIG(VIEW1), SPHGRP)
.)m
.lp
To add definition objects to the definition group, use
\f2DvInqDefinitionGroup <DVQDG>\fP to obtain the handle to the
specified view's definition group.
.H1 "Important View Features"
Several important view features are listed below.  Each of
these features has a related inquiry function, beginning with 
DvInq- <DVQ->, to inquire the current value. 
.sp .25v
.ip "\f3DvSetRendStyle <DVSRS>\fP
selects the renderer.
Most \*(Dd configurations include two renderers:  \f2real time\fP, for
fast, dynamic rendering; and \f2production time\fP, for the most
realistic rendering, which takes the most time.
The default rendering style is \f2DcRealTime <DCRLTM>\fP.
See your \f2\*(Dd System Guide\fP for a list of available renderers.
Chapter 10 also discusses the selection of renderers.
.sp .25v
.ip "\f3DvSetClearFlag <DVSCF>\fP
sets the clear flag of a view.
If the clear flag is on, then the view is first cleared to its
background color each time the view is updated.
If a background raster is defined for the view it will be drawn to the
view background after the background color.
.sp .25v
.ip "\f3DvSetBackgroundColor <DVSBC>\fP
sets the background color of a view.
.sp .25v
.ip "\f3DvSetBackgroundRaster <DVSBR>\fP
sets the background raster object for the view.
See Chapter 14 for more details of background rasters.
.sp .25v
.ip "\f3DvSetBackgroundJust <DVSBJ>\fP
specifies how a background raster will be aligned to the view when
there is a mismatch in size between the raster and the mapping of the view
onto the device. 
.sp .25v
.ip "\f3DvSetBoundary <DVSB>\fP
sets the view boundary.
The default view boundary is (0.0, 0.0, 0.0) to (1.0, 1.0, 1.0).
.rs
.H1 "Important Frame Features
A frame defines a virtual image composed of one or more views.
Each frame defines a three dimensional space.
The frame boundary, set with \f2DfSetBoundary <DFSB>\fP, defines the
volume in frame coordinates that will be displayed on each device that
it is attached to.
\*(Dd will maintain the aspect ratio (the ratio between the height and
width) of the frame when it is displayed on a device.
\f2DfSetJust <DFSJ>\fP allows you to control how the frame is placed
within the device volume when the aspect ratio of the device is
different than that of the frame.
.sp -.5v
.H1 "Adding Views to Frames
When a frame is created with \f2DoFrame <DOFR>\fP, it has an empty view
group.
Once you obtain the handle to a frame's view group (with
\f2DfInqViewGroup <DFQVG>\fP), you can add one or more views to the
frame.
For example, to add the \f2solar_system <SOLAR>\fP view and the
\f2spaceship <SHIP>\fP view to the same frame \f2frame1 <FRAME1>\fP,
the code would read: 
.(m
C code:

.\"#	ident "@(#)ch10.ex02	1.3" 5/15/91
.\"
DtObject frame1, solar_system, spaceship;

DgAddObjToGroup(DfInqViewGroup(frame1), solar_system);
DgAddObjToGroup(DfInqViewGroup(frame1), spaceship);


\*(Fo code:

.\"#	ident "@(#)ch10.ex02.f	1.3" 5/15/91
.\"
      INTEGER*4 FRAME1, SOLAR, SHIP

      CALL DGAOG(DFQVG(FRAME1), SOLAR)
      CALL DGAOG(DFQVG(FRAME1), SHIP)
.)m
.rs
.sp -1.5v
.H1 "Creating a Device
A \*(Dd device is an organizational object that provides access to
physical and virtual display devices like rasterfiles, X-windows, or
high performance graphics displays.
When you create a \*(Dd device with \f2DoDevice <DOD>\fP, you must
specify the type of device driver.
The device driver type is a string like \f2stdx11\fP.
.lp
\*(Dd provides several different device drivers, and you can determine
the names and descriptions of these via the functions
\f2DsInqNumDrivers <DSQND>\fP and \f2DsInqDriverInfo <DSQDI>\fP.
Your \f2\*(Dd System Guide\fP also contains a list of available device
drivers.
.lp
The following code fragment prints out the names and descriptions of
the installed device drivers.
.(m
C code:
.sp
    DtInt num_drive;
    DtPtr *driver_name;
    DtPtr *driver_info;
    DtInt i;

    num_drive = DsInqNumDrivers();
    driver_name = (DtPtr *)malloc (num_drive*sizeof(DtPtr));
    driver_info = (DtPtr *)malloc (num_drive*sizeof(DtPtr));

    DsInqDriverInfo(num_drive, driver_name, driver_info);
    printf ("\\\\nInstalled Drivers:\\\\n");
    print (i=0; i<num_drivers; i++) {
	printf ("\\\\t%-15s   '%s'\\\\n", driver_name[i], 
		driver_info[i]);
    }
.sp
\*(Fo Code:
.sp
      INTEGER*4 NDRVS
      CHARACTER*80 DRVNAM(50)
      CHARACTER*80 DRVINF(50)
      INTEGER*4

      NDRVS = DSQND()

      IF (NDRVS .GT. 50) THEN
          WRITE(6,*) 
     1         'Only displaying the first 50 device drivers'
          NDRVS = 50
      ENDIF

      CALL DSQDI(NDRVS, DRVNAM, 80, DRVINF, 80)

      WRITE(6, *) 'Installed Drivers:'
      DO 10 I=1, NDRVS
          WRITE(6, 20) DRVNAM(I), DRVINF(I)
10    CONTINUE

20    FORMAT(' ', A, ': ', A)
.)m
.rs
.sp -2v
.H1 "Example 1: Creating a Device, Frame and View"
A simple method for creating views, frames, and devices is shown
in Example 1.
The device, a standard X11 window, is created with \f2DoDevice <DOD>\fP.  
(See your \f2\*(Dd System Guide\fP for a list of available device
drivers.)
Then \f2DdInqExtent <DDQE>\fP is used to obtain the volume range
available to that particular device.
This  volume is used for the frame and for the view, so that they
overlap completely.
.(m
C code:

.\"#	ident "@(#)ch10.ex03	1.3" 5/15/91
.\"
DtObject device, frame, view;
DtVolume volume;

/* create device and 
 * return device's volume 
 */
device = DoDevice("stdx11","-geometry =640x512+0+0");
DdInqExtent(device, &volume);	

/* create frame, 
 * assign to device, and
 * set frame boundary to device volume 
 */
frame = DoFrame();		
DdSetFrame(device, frame);
DfSetBoundary(frame, &volume);

/* create view, 
 * add to frame, 
 * set view boundary,
 * set clear flag, and 
 * set render style */
view = DoView();		
DgAddObjToGroup(DfInqViewGroup(frame), view);
DvSetBoundary(view, &volume);
DvSetClearFlag(view, DcTrue);
DvSetRendStyle(view, DcRealTime);

/*		.
 *		.
 * create the objects, add the objects to the view
 *		.
 *		.
 */

/* display the view */
DdUpdate(device);		
.sp
\*(Fo code:

.\"#	ident "@(#)ch10.ex03.f	1.3" 5/15/91
.\"
     INTEGER*4 DEVICE, FRAME, VIEW
     REAL*8 VOLUME(3)
C
     ! create device and
     ! return device volume
     DEVICE=DOD('stdx11',6,'-geometry=640x512+0+0',22)
     CALL DDQE(DEVICE, VOLUME)	
C
     ! create frame,
     ! assign to device, and
     ! set frame boundary to device volume
     FRAME=DOFR()	
     CALL DDSF(DEVICE, FRAME)	
     CALL DFSB(FRAME, VOLUME)	
C
     ! create view,
     ! add to frame,
     ! set view boundary to device volume,
     ! set clear flag, and
     ! set render style
     VIEW=DOVW()
     CALL DGAOG(DFQVG(FRAME), VIEW)
     CALL DVSB(VIEW, VOLUME)
     CALL DVSCF(VIEW, DCTRUE)
     CALL DVSRS(VIEW, DCRLTM)
C
     !		.
     !		.
     ! create the objects; add objects to the view
     !		.
     !		.
C
     ! display the view
     CALL DDU(DEVICE)
.)m
.IX priorities of views
.lp
Objects within a group are rendered in the order in which they
are added to the group.
Similarly, \f2views\fP are rendered in the order in which they are
added to a frame.
If views overlap, the last view to be rendered will be the only one
entirely visible.
.H1 "Transformations between Views, Frames, and Devices
The boundary of a view is specified in frame coordinates.
The default view boundary is (0.0, 0.0, 0.0) to (1.0, 1.0, 1.0)
in frame coordinates and is the same as the default frame boundary.
The frame boundary can be set to any convenient volume using
\f2DfSetBoundary <DFSB>\fP.
Examples 2 and 3 add four different views to the same frame.
Each view has boundaries set with \f2DvSetBoundary\fP.
The frames in both examples use the default boundaries.
When a view is placed within a frame, any areas of the view that fall
outside of the frame boundary are \f2clipped\fP (see \*(FT).
.(F "./PS/9.2ps" 1.5i -1
.)F "Clipping a View to the Frame Boundary"
The next step is the transformation from the frame coordinate
system into the device coordinate system, which consists of floating
point pixels directly related to the device extent.
Device coordinates range from (0.0, 0.0, 0.0) in the back lower left
corner to the device extent in the front upper right corner (for
example, 1024.0, 1280.0, 65536.0).
.lp
The \f2device viewport\fP specifies the portion of the device extent
that is to be used to display the frame assigned to it.
The default viewport uses the entire device volume.
If the device extent changes, for example if an X window is resized,
the device viewport automatically resizes to fill the new device volume.
Use \f2DdSetViewport <DDSDV>\fP to explicitly set the device viewport.
When a device is created with \f2DoDevice <DOD>\fP, you can specify
\f2-noautosize\fP to turn off autosizing.
.lp
When a frame is mapped into the device viewport, the frame is
sized as large as possible, while preserving its aspect ratio.
In cases where the new volume and the device viewport have
different aspect ratios, there will be extra white space in the
device viewport.  Use \f2DfSetJust <DFSJ>\fP to specify where to
put this white space.
.IX justifying frames in viewports
.H1 "Updating Views, Frames, and Devices"
\*(Dd offers various update functions at different levels of the view,
frame, device hierarchy.
When an update occurs, each view to be affected is displayed or
redisplayed on the associated devices.
These functions are:
.sp .25v
.ip "\f3DvUpdate <DVU>\fP
updates the specified view.
.sp .25v
.ip "\f3DfUpdate <DFU>\fP
updates all views associated with a particular frame.
.sp .25v
.ip "\f3DdUpdate <DDU>\fP
updates the frame, and all its views, associated with a particular device.
.sp .25v
.lp
Each view has an update type, set with \f2DvSetUpdateType <DVSUT>\fP:
.sp .25v
.ip "\f3DcUpdateAll <DCUALL>\fP 
updates both the display objects and the definition objects. 
Use this type if cameras and lights have been modified since the previous
update of the view.
.sp .25v
.ip "\f3DcUpdateDisplay <DCUDIS>\fP
updates only the display objects.
This type is specified if the cameras and lights have \f2not\fP been
changed since the previous update.
Since camera and light groups are not updated at all, increased
efficiency results.
.sp .25v
.lp
Use \f2DvInqUpdateType <DVQUT>\fP to query the view's update type.
.sp .25v
.H1 "Example 2:  Adding an Object to Four Different Views"
.sp .25v
The device in this example is a standard X11 window.
Four views are added to a frame that uses the default boundary, from
(0.0, 0.0, 0.0) to (1.0, 1.0, 1.0).
Mapping from views to frames is easy because they both use the same
(frame) coordinates.
Each view in \*(FT uses one-fourth of
the frame volume.
\*(FT shows the general orientation of the image in each of the four views.
.bp
\ 
.(F "./PS/9.3ps" 2i -1
.)F "Adding Four Views to a Frame"
.(F "./PS/9.4ps" 3.5i -1
.)F "Sample Output for Example 2"
.(m
C code:

.\"#	ident "@(#)ch10.ex04	1.3" 5/15/91
.\"
DtObject plane;     /* details omitted for simplicity */
DtObject camera1, camera2, camera3, camera4, 
	 view1, view2, view3, view4, 
	 device, frame;
DtVolume volume;
static DtPoint3
     origin = {0.0, 0.0, 0.0},
     from1 = {0.0, 0.0, 4.0},      /* front view */
     from2 = {4.0, 0.0, 0.0},      /* side view */
     from3 = {0.0, 4.0, 0.0},      /* top view */
     from4 = {4.0, 4.0, 4.0};      /* perspective view */
static DtVector3
     y_dir = {0.0, 1.0, 0.0},
     z_dir = {0.0, 0.0, 1.0};
static DtVolume
     vol_1 = {{0.0, 0.0, 0.0}, {0.5, 0.5, 1.0}},
     vol_2 = {{0.0, 0.5, 0.0}, {0.5, 1.0, 1.0}},
     vol_3 = {{0.5, 0.0, 0.0}, {1.0, 0.5, 1.0}},
     vol_4 = {{0.5, 0.5, 0.0}, {1.0, 1.0, 1.0}};

device = DoDevice("stdx11", "-geometry =640x512+0+0");  

/* create frame with default boundaries */
frame = DoFrame();            
DdSetFrame(device, frame);

camera1 = DoGroup(DcTrue);    
     DgAddObj(DoParallel(4.0, -0.1, -100.0));
     DgAddObj(DoLookAtFrom(origin, from1, y_dir));
     DgAddObj(DoCamera());
     DgAddObj(DoLight());
DgClose();

camera2 = DoGroup(DcTrue);    
     DgAddObj(DoParallel(4.0, -0.1, -100.0));
     DgAddObj(DoLookAtFrom(origin, from2, y_dir));
     DgAddObj(DoCamera());
     DgAddObj(DoLight());
DgClose();

camera3 = DoGroup(DcTrue);    
     DgAddObj(DoParallel(4.0, -0.1, -100.0));
     DgAddObj(DoLookAtFrom(origin, from3, z_dir));
     DgAddObj(DoCamera());
     DgAddObj(DoLight());
DgClose();


camera4 = DoGroup(DcTrue);    
     DgAddObj(DoPerspective(90.0, -0.1, -100.0));
     DgAddObj(DoLookAtFrom(origin, from4, y_dir));
     DgAddObj(DoCamera());
     DgAddObj(DoLight());
DgClose();

/* bottom left quadrant */

view1 = DoView();
DgAddObjToGroup(DfInqViewGroup(frame), view1);
DvSetBoundary(view1, &vol_1);   
DgAddObjToGroup(DvInqDisplayGroup(view1), plane); 
DgAddObjToGroup(DvInqDefinitionGroup(view1), camera1); 

/* top left quadrant */

view2 = DoView();
DgAddObjToGroup(DfInqViewGroup(frame), view2);
DvSetBoundary(view2, &vol_2);   
DgAddObjToGroup(DvInqDisplayGroup(view2), plane); 
DgAddObjToGroup(DvInqDefinitionGroup(view2), camera2); 

/* bottom right quadrant */

view3 = DoView();
DgAddObjToGroup(DfInqViewGroup(frame), view3);
DvSetBoundary(view3, &vol_3);   
DgAddObjToGroup(DvInqDisplayGroup(view3), plane); 
DgAddObjToGroup(DvInqDefinitionGroup(view3), camera3); 

/* top right quadrant */

view4 = DoView();                
DgAddObjToGroup(DfInqViewGroup(frame), view4);  
DvSetBoundary(view4, &vol_4);   
DgAddObjToGroup(DvInqDisplayGroup(view4), plane); 
DgAddObjToGroup(DvInqDefinitionGroup(view4), camera4); 

\*(Fo code:

.\"#	ident "@(#)ch10.ex04.f	1.3" 5/15/91
.\"
      INTEGER*4 PLANE ! details omitted for simplicity
      INTEGER*4 CAMERA1, CAMERA2, CAMERA3, CAMERA4
      INTEGER*4 DEVICE, FRAME, VIEW1, VIEW2, VIEW3, VIEW4
      REAL*8 VOLUME (3)
      REAL*8 ORIGIN(3) 
      REAL*8 FROM1(3), FROM2(3), FROM3(3), FROM4(3)
      REAL*8 YDIR(3), ZDIR(3)
      REAL*8 VOL1, VOL2, VOL3, VOL4
      DIMENSION VOL1(3,2), VOL2(3,2), VOL3(3,2), VOL4(3,2)
C
      DATA ORIGIN / 0.0D0, 0.0D0, 0.0D0 /
      DATA FROM1  / 0.0D0, 0.0D0, 4.0D0 / ! front view 
      DATA FROM2  / 4.0D0, 0.0D0, 0.0D0 / ! side view 
      DATA FROM3  / 0.0D0, 4.0D0, 0.0D0 / ! top view 
      DATA FROM4  / 4.0D0, 4.0D0, 4.0D0 / ! persp view 
      DATA YDIR   / 0.0D0, 1.0D0, 0.0D0 /
      DATA ZDIR   / 0.0D0, 0.0D0, 1.0D0 /
      DATA VOL1   / 0.0D0, 0.0D0, 0.0D0, 
     1		    0.5D0, 0.5D0, 1.0D0 /
      DATA VOL2   / 0.0D0, 0.5D0, 0.0D0, 
     1		    0.5D0, 1.0D0, 1.0D0 /
      DATA VOL3   / 0.5D0, 0.0D0, 0.0D0, 
     1		    1.0D0, 0.5D0, 1.0D0 /
      DATA VOL4   / 0.5D0, 0.5D0, 0.0D0, 
     1		    1.0D0, 1.0D0, 1.0D0 /
C
      DEVICE = DOD ('stdx11',6,'-geometry=640x512+0+0',22)
C
      ! create frame with default boundaries
      FRAME=DOFR() 
      CALL DDSF (DEVICE, FRAME)
C
      CAMERA1 = DOG (DCTRUE) 
         CALL DGAO(DOPAR(4.0D0, -0.1D0, -100.0D0))
         CALL DGAO(DOLAF(ORIGIN, FROM1, YDIR))
         CALL DGAO(DOCM())
         CALL DGAO(DOLT())
      CALL DGCS()
C
      CAMERA2 = DOG(DCTRUE)  
         CALL DGAO(DOPAR(4.0D0, -0.1D0, -100.0D0))
         CALL DGAO(DOLAF(ORIGIN, FROM2, YDIR))
         CALL DGAO(DOCM())
         CALL DGAO(DOLT())
      CALL DGCS()
C
      CAMERA3 = DOG(DCTRUE) 
         CALL DGAO(DOPAR(4.0D0, -0.1D0, -100.0D0))
         CALL DGAO(DOLAF(ORIGIN, FROM3, ZDIR))
         CALL DGAO(DOCM())
         CALL DGAO(DOLT())
      CALL DGCS()
C
      CAMERA4 = DOG(DCTRUE)  
         CALL DGAO(DOPER(90.0D0, -0.1D0, -100.0D0))
         CALL DGAO(DOLAF(ORIGIN, FROM4, YDIR))
         CALL DGAO(DOCM())
         CALL DGAO(DOLT())
      CALL DGCS()
C
      ! bottom left quadrant
      VIEW1=DOVW()
         CALL DGAOG(DFQVG(FRAME), VIEW1)
         CALL DVSB(VIEW1, VOL1) 
         CALL DGAOG(DVQIG(VIEW1), PLANE) 
         CALL DGAOG(DVQDG(VIEW1), CAMERA1) 
C
      ! bottom right quadrant
      VIEW2=DOVW()
         CALL DGAOG(DFQVG(FRAME), VIEW2)
         CALL DVSB(VIEW2, VOL2) 
         CALL DGAOG(DVQIG(VIEW2), PLANE) 
         CALL DGAOG(DVQDG(VIEW2), CAMERA1) 
C
      ! top left quadrant
      VIEW3=DOVW()
         CALL DGAOG(DFQVG(FRAME), VIEW3)
         CALL DVSB(VIEW3, VOL3) 
         CALL DGAOG(DVQIG(VIEW3), PLANE) 
         CALL DGAOG(DVQDG(VIEW3), CAMERA1) 
C
      ! top right quadrant
      VIEW4=DOVW()
         CALL DGAOG(DFQVG(FRAME), VIEW4)
         CALL DVSB(VIEW4, VOL4) 
         CALL DGAOG(DVQIG(VIEW4), PLANE) 
         CALL DGAOG(DVQDG(VIEW4), CAMERA1) 
.)m
.H1 "Example 3: Views using Relative Frame Coordinates"
Example 3 is identical to Example 2, except that the boundaries
for the four views are specified with relative references rather
than absolute references, for added flexibility.
.(m
C code:

.\"#	ident "@(#)ch10.ex05	1.3" 5/15/91
.\"
DtObject plane_obj, light_group, camera_groups[2][2];
DtObject view, frame, device;
DtVolume volume;
DtReal width, height, Xoff, Yoff, Xstep, Ystep;
DtInt i, j;

device = DoDevice("stdx11", "-geometry =640x512+0+0");
DdInqViewport(device, &volume);


/* volume.bll is the back lower left corner 
 * 		of the bounding cube.
 * volume.fur is the front upper right corner 
 *		of the bounding cube 
 */

width  = volume.fur[0] - volume.bll[0];
height = volume.fur[1] - volume.bll[1];
Xoff = volume.bll[0];
Yoff = volume.bll[1];
Xstep = width  / 2.0;
Ystep = height / 2.0;

/* crt frame with boundary that matches device viewport */
frame = DoFrame();
DdSetFrame(device, frame);
DfSetBoundary(frame, &volume); 

/* define the light group and 
 * the 2x2 array of camera groups here 
 */

/* make views and add them to the frame */
for(i=0; i<2; i++) {
    for(j=0; j<2; j++) {
        view = DoView();         
        DgAddObjToGroup(DfInqViewGroup(frame), view);
        volume.bll[0] = i * Xstep + Xoff;
        volume.bll[1] = j * Ystep + Yoff;
        volume.fur[0] = (i + 1) * Xstep + Xoff;
        volume.fur[1] = (j + 1) * Ystep + Yoff;
        DvSetBoundary(view, &volume);
        DgAddObjToGroup(DvInqDefinitionGroup(view),
             		camera_groups[i][j]);
        DgAddObjToGroup(DvInqDefinitionGroup(view), 
			light_group);
        DgAddObjToGroup(DvInqDisplayGroup(view), 
			plane_obj);
    }
}
.sp
\*(Fo code:

.\"#	ident "@(#)ch10.ex05.f	1.3" 5/15/91
.\"
      INTEGER*4 PLNOBJ
      INTEGER*4 LGTGRP, CAMGRP(2,2), 
      INTEGER*4 VIEW, FRAME, DEVICE
      REAL*8 VOLUME (3,2), 
      REAL*8 WIDTH, HEIGHT, XOFF, YOFF, XSTEP, YSTEP
      INTEGER*4 I,J
      INCLUDE '/usr/include/fortran/DORE'
C
      DEVICE = DOD('stdx11',6,'-geometry =640x512+0+0',22)
      CALL DDQV (DEVICE, VOLUME)
C
      ! VOLUME(*,1) is back lower left corner 
      !			of bounding cube
      ! VOLUME(*,2)  is front upper right corner 
      !			of bounding cube
      WIDTH=VOLUME(1,2)-VOLUME(1,1)
      HEIGHT=VOLUME(2,2)-VOLUME(2,1)
      XOFF=VOLUME(1,1)
      YOFF=VOLUME(2,1)
      XSTEP=WIDTH/2.0
      YSTEP=HEIGHT/2.0
C
      ! create frame with boundary matching device viewport
      FRAME=DOFR()
      CALL DDSF(DEVICE, FRAME)
      CALL DFSB(FRAME, VOLUME)   
C     
      ! define the light group and 
      ! the 2x2 array of camera groups here
C
      ! make view and add them to the frame
      DO 30 I=0,1
            DO 20 J=0,1
                  VIEW=DOVW()
                  CALL DGAOG(DFQVG(FRAME),VIEW)
                  VOLUME(1,1)=I*XSTEP+XOFF
                  VOLUME(2,1)=J*YSTEP+YOFF
                  VOLUME(1,2)=(I+1)*XSTEP+XOFF
                  VOLUME(2,2)=(J+1)*YSTEP+YOFF
                  CALL DVSB(VIEW,VOLUME)
                  CALL DGAOG(DVQIG(VIEW),CAMGRP(J+1,I+1))
                  CALL DGAOG(DVQIG(VIEW),LGTGRP)
                  CALL DGAOG(DVQDG(VIEW),PLNOBJ)
20          CONTINUE
30    CONTINUE
.)m
.H1 "Example 4:  Combining Definition and Display Groups"
Example 4 shows adding a group twice to the same view\(emonce as
a definition object, and a second time as a display object.
Studio objects and studio attribute objects, along with their
geometric transformations, will execute when they are used in a
definition group.
The primitive objects and primitive attribute objects in a definition
group are ignored.
Primitive objects and their attributes, and the same geometric
transformations, will execute, when they are used in a display group,
but the studio objects and studio attribute objects are ignored.
.lp
This feature is especially useful when the position and orientation of
a studio object is  directly tied to a display object in the scene.
For instance, in this example one camera is placed on the spaceship,
and another camera is located on the planet.
\*(FT shows the spaceship/camera group orbiting the earth and the 
observer/camera group located on the surface of the planet.
.(F "./PS/9.5ps" 3.4i -1
.)F "Spaceship and Observer Camera Groups"
.(m
.rs
.sp -1v
C code:

#include "dore.h"

main()
{
    DtObject device, frame, observer_view, ship_view,
            solar_system, observer_camera, ship_camera;
    static DtVolume
        frame_volume = {{0.0, 0.0, 0.0}, 
			{1.0, 1.0, 1.0}},
        observer_view_volume = {{0.0, 0.0, 0.0}, 
				{0.5, 0.5, 1.0}},
        ship_view_volume = {{0.5, 0.5, 0.0}, 
			    {1.0, 1.0, 1.0}};
    static DtPoint3
        origin         = {0.0,  0.0, 0.0},
        ship_from      = {0.0, 12.0, 0.0},
        ship_at        = {0.0, 12.0, 1.0},
        observer_from  = {0.0,  0.0, 10.1},
        observer_at    = {0.0,  1.0, 10.1},
        light_from     = {0.0,  0.0, 15.0};
    static DtVector3
        y_dir = {0.0, 1.0, 0.0},
        z_dir = {0.0, 0.0, 1.0};
    static DtReal
        red[]     = {1.0, 0.0, 0.0},
        yellow[]  = {1.0, 1.0, 0.0};
    DtInt i;

    DsInitialize(0);

     /* all angles will be measured in degrees */

    DsSetAngleUnits(DcAngleDegrees);

    solar_system = DoGroup(DcTrue);
        DgAddObj(DoPerspective(90.0, -0.1, -400.0));
        DgAddObj(DoRepType(DcSurface));
        DgAddObj(DoBackfaceCullable(DcTrue));
        DgAddObj(DoAmbientSwitch(DcOff)); 
        
        /* make the planet */

        DgAddObj(DoPushMatrix());
            DgAddObj(DoDiffuseColor(DcRGB, red));
            DgAddObj(DoScale(10.0, 10.0, 10.0));
            DgAddObj(DoPrimSurf(DcSphere));
        DgAddObj(DoPopMatrix());

        /* position camera on planet's surface */

        DgAddObj(DoPushMatrix());
            DgAddObj(DoLookAtFrom(observer_from, 
				  observer_at, z_dir));
            DgAddObj(observer_camera = DoCamera());
        DgAddObj(DoPopMatrix());

        /* make light source from the sun */


        DgAddObj(DoPushMatrix());
            DgAddObj(DoLookAtFrom(origin, 
			          light_from, y_dir));
            DgAddObj(DoLightIntens(1.0));
            DgAddObj(DoLight());
        DgAddObj(DoPopMatrix());

        /* position the spaceship and its onboard camera */
        /* insert dummy rotate, with label */

        DgAddObj(DoLabel(1));
        DgAddObj(DoRotate(DcXAxis, 0.0));  
        DgAddObj(DoTranslate(0.0, 0.0, 12.0));

        /* make the spaceship model */

        DgAddObj(DoPushMatrix());
            DgAddObj(DoDiffuseColor(DcRGB, yellow));
            DgAddObj(DoScale(0.5, 0.5, 1.0)); 
            DgAddObj(DoPrimSurf(DcCone));   
            DgAddObj(DoTranslate(0.0, 0.0, -1.0));
            DgAddObj(DoPrimSurf(DcCylinder)); 
        DgAddObj(DoPopMatrix());

        /* position onboard camera looking forward */

        DgAddObj(DoPushMatrix());
            DgAddObj(DoLookAtFrom(ship_from, 
				  ship_at, y_dir));
            DgAddObj(ship_camera = DoCamera());
        DgAddObj(DoPopMatrix());
        DgSetElePtr(0, DcBeginning); 

	/* prepare to replace rotate object */ 
       
	 DgSetElePtrRelLabel(1, 1); 
     DgClose();

     /* set up display environment */
    
     device = DoDevice("stdx11", "-geometry =640x512+0+0");
     frame = DoFrame();
     DdSetFrame(device, frame);
     DfSetBoundary(frame, &frame_volume);
     observer_view = DoView();
     ship_view = DoView();
     DvSetBoundary(observer_view, &observer_view_volume);
     DvSetBoundary(ship_view, &ship_view_volume);
     DgAddObjToGroup(DfInqViewGroup(frame), observer_view);
     DgAddObjToGroup(DfInqViewGroup(frame), ship_view);
     DvSetActiveCamera(observer_view, observer_camera);
     DvSetActiveCamera(ship_view, ship_camera);
     DgAddObjToGroup(DvInqDisplayGroup(observer_view), 
		     solar_system);
     DgAddObjToGroup(DvInqDefinitionGroup(observer_view), 
	             solar_system);
     DgAddObjToGroup(DvInqDisplayGroup(ship_view), 
		     solar_system);
     DgAddObjToGroup(DvInqDefinitionGroup(ship_view), 
		     solar_system);
   
     for(i=0; i<720; i++) { /* orbit the planet twice */
         DdUpdate(device);
         DgReplaceObjInGroup(solar_system, 
			DoRotate(DcXAxis, (DtReal)i));
     }

     DsReleaseObj(device);
     DsTerminate();
}


 
\*(Fo code:

.\"#	ident "@(#)ch10.ex06.f	1.3" 5/15/91
.\"
      PROGRAM MAIN
C
      IMPLICIT NONE
      INCLUDE '/usr/include/fortran/DORE'
C
      INTEGER*4 DEVICE, FRAME, OBSVW, SHPVW, I
      INTEGER*4 SOLSYS, OBSCAM, SHPCAM
      REAL*8 FRMVOL(3,2), OBSVOL(3,2), SHPVOL(3,2)
      REAL*8 ORIGIN(3), SHPFRM(3), SHPAT(3)
      REAL*8 OBSFRM(3), OBSAT(3), LTFROM(3)
      REAL*8 YDIR(3), ZDIR(3), RED(3), YELLOW(3)
C
      DATA FRMVOL / 0.0D0, 0.0D0, 0.0D0,   
     1		    1.0D0, 1.0D0, 1.0D0 /
      DATA OBSVOL / 0.0D0, 0.0D0, 0.0D0,   
     1		    0.5D0, 0.5D0, 1.0D0 /
      DATA SHPVOL / 0.5D0, 0.5D0, 0.0D0,   
     1		    1.0D0, 1.0D0, 1.0D0 /
      DATA ORIGIN / 0.0D0, 0.0D0, 0.0D0 /
      DATA SHPFRM / 0.0D0, 12.0D0, 0.0D0 /
      DATA SHPAT / 0.0D0, 12.0D0, 1.0D0 /
      DATA OBSFRM / 0.0D0, 0.0D0, 10.1D0 /
      DATA OBSAT / 0.0D0, 1.0D0, 10.1D0 /
      DATA LTFROM / 0.0D0, 0.0D0, 15.0D0 /
      DATA YDIR / 0.0D0, 1.0D0, 0.0D0 /
      DATA ZDIR / 0.0D0, 0.0D0, 1.0D0 /
      DATA RED / 1.0D0, 0.0D0, 0.0D0 /
      DATA YELLOW / 1.0D0, 1.0D0, 0.0D0 /
C
      CALL DSINIT(0)
C
      ! all angles will be measured in degrees
      CALL DSSAU(DCAD)
C
      SOLSYS=DOG(DCTRUE)
         CALL DGAO(DOPER(90.0D0, -0.1D0, -400.0D0))
         CALL DGAO(DOREPT(DCSURF))
         CALL DGAO(DOBFC(DCTRUE))
         CALL DGAO(DOAMBS(DCOFF)) 
C     
      ! make the planet
      CALL DGAO(DOPUMX())
         CALL DGAO(DODIFC(DCRGB, RED))
         CALL DGAO(DOSC(10.0D0, 10.0D0, 10.0D0))
         CALL DGAO(DOPMS(DCSPHR))
      CALL DGAO(DOPPMX())
C     
      ! position camera on planet's surface
      CALL DGAO(DOPUMX())
         CALL DGAO(DOLAF(OBSFRM, OBSAT, ZDIR))
	 OBSCAM=DOCM()
         CALL DGAO(OBSCAM)
      CALL DGAO(DOPPMX())
C     
      ! make light source from the sun
      CALL DGAO (DOPUMX())
         CALL DGAO(DOLAF(ORIGIN, LTFROM, YDIR))
         CALL DGAO(DOLI(1.0D0))
         CALL DGAO(DOLT())
      CALL DGAO(DOPPMX())
C     
      ! position the spaceship and its onboard camera
      ! include dummy rotate, with label
      CALL DGAO(DOLL(1)) 
      CALL DGAO(DOROT(DCXAX, 0.0D0))
      CALL DGAO(DOXLT(0.0D0, 0.0D0, 12.0D0))
C     
      ! make the spaceship
      CALL DGAO(DOPUMX())
         CALL DGAO(DODIFC(DCRGB, YELLOW))
         CALL DGAO(DOSC(0.5D0, 0.5D0, 1.0D0)) 
         CALL DGAO(DOPMS(DCCONE)) 
         CALL DGAO(DOXLT(0.0D0, 0.0D0, -1.0D0))
         CALL DGAO(DOPMS(DCCYL))
      CALL DGAO(DOPPMX())
C     
      ! position onboard camera looking forward
      CALL DGAO(DOPUMX())
         CALL DGAO(DOLAF(SHPFRM, SHPAT, YDIR))
	 SHPCAM=DOCM()
         CALL DGAO(SHPCAM)
      CALL DGAO(DOPPMX())
C     
      ! prepare to replace the rotate object
      CALL DGSEP(0,DCBEG)
      CALL DGSEPL(1,1)
      CALL DGCS()
C     
      ! set up display envrionment
      DEVICE=DOD('stdx11',6,'-geometry =640x512+0+0',22)
      FRAME=DOFR()
      CALL DDSF(DEVICE, FRAME)
      CALL DFSB(FRAME, FRMVOL)
      OBSVW=DOVW()
      SHPVW=DOVW()
      CALL DVSB(OBSVW, OBSVOL)
      CALL DVSB(SHPVW, SHPVOL)
      CALL DGAOG(DFQVG(FRAME), OBSVW)
      CALL DGAOG(DFQVG(FRAME), SHPVW)
      CALL DVSAC(OBSVW, OBSCAM)
      CALL DVSAC(SHPVW, SHPCAM)
      CALL DGAOG(DVQIG(OBSVW), SOLSYS)
      CALL DGAOG(DVQDG(OBSVW), SOLSYS)
      CALL DGAOG(DVQIG(SHPVW), SOLSYS)
      CALL DGAOG(DVQDG(SHPVW), SOLSYS)
C
      DO 90 I=0, 719  ! circle the world twice
         CALL DDU(DEVICE)
         CALL DGROG(SOLSYS, DOROT(DCXAX, I))
   90 CONTINUE
C
      CALL DSRO(DEVICE)
      CALL DSTERM()

      END
.)m
.rs
.sp -1v
.H1 "Pseudocolor"
Often pseudocolor is used when the output display device
supports only a limited number of colors.
The following discussion and examples introduce the use of
pseudocolor devices.
.lp
To produce pseudocolor output you must first indicate that the device
uses pseudocolor with the \f2-visualtype DcPseudoColor\fP option to
\f2DoDevice <DOD>\fP.
Because a given pseudocolor device may or may not
set up a default color map, the application should \f2always\fP
set up the color map for a pseudocolor device with
\f2DdSetColorEntries <DDSCE>\fP.
.lp
The \*(Dd renderers typically generate all images in full color.
With pseudocolor, the full-color image 
is converted into a pseudocolor image by one of two methods:
\f2bit compression\fP or \f2range intensity mapping\fP.  The
\f2DdSetShadeMode <DDSSM>\fP function indicates the mode
selected:  \f2DcComponent <DCCOMP>\fP for bit compression, or
\f2DcRange <DCRNG>\fP for range intensity mapping.
.H2 "Bit Compression"
With bit compression, the full-color value generated by the renderer
is reduced to an 8-bit value by taking the top three significant bits
for red from the full-color value, the top three bits for green, and
the top two bits for blue.
(See \*(FT.)
This 8-bit value produces a number between 0 and 255 which is used as
an index into the color table that was set up by \f2DdSetColorEntries
<DDSCE>\fP.
.(F "./PS/9.6ps" 2.0i 0
.)F "Using Bit Compression for Pseudocolor"
The following example shows how to set up an RGB color table for
bit compression mode.  
Note that \*(Dd always specifies colors using floating point numbers
between 0 and 1, but in this case, the device will convert these
numbers to byte values between 0 and 255.
\*(FT illustrates the color table setup.
.bp
\ 
.(F 
.\ "./PS/9.7ps" 2.5i 0
.sp 2.5i
.)F "Color Table Using RGB Bit Compression"
.(m
C code:

.\"#	ident "@(#)ch10.ex07	1.3" 5/15/91
.\"
DtReal entries [256*3], *p;
p = entries;
for (i=0; i<256; i++) {
     *p++ = (DtReal)(i>>5)/7.;          /* red */
     *p++ = (DtReal)((i>>2) & 0x7)/7.;  /* green */
     *p++ = (DtReal)(i & 0x3)/3.;       /* blue */
}
device = DoDevice("stdx11","-visualtype DcPseudoColor");

/* set up color table and specify bit compression mode */
DdSetColorEntries(device, DcRGB, 0, 256, entries);
DdSetShadeMode (device, DcComponent);  

.sp
\*(Fo code:

.\"#	ident "@(#)ch10.ex07.f	1.3" 5/15/91
.\"
      REAL*8 ENTRYS(3,256)
      INTEGER*4 DEVICE
C
      DO 30 I=0,255
      ENTRYS(1,I+1)=DFLOAT(I/32)/7.0D0          ! red
      ENTRYS(2,I+1)=DFLOAT(MOD(I/4),8)/7.0D0    ! green
      ENTRYS(3,I+1)=DFLOAT(MOD(I,4))/3.0D0      ! blue 
30    CONTINUE
      DEVICE=DOD('stdx11',6,'-visualtype DcPseudocolor',25)
C
      ! set up color table and specify bit compression mode
      CALL DDSCE(DEVICE,DCRGB,0,256,ENTRYS) 
      CALL(DDSSM(DEVICE, DCCOMP)   
.)m
.lp
The color map created in the example above does not result in a
true grey scale.
Since red and green values are in sevenths, and blue values are in
thirds, it is not possible to get equal values of red, green and blue.
(See \*(FT.
A true grey scale represents a straight line between the black and white
corners of the color cube.
There are no entries in the color table that lie on this line except
black and white.)
.(F "./PS/9.8ps" 2.25i 0
.)F "Color Cube Using 3-3-2 Bit Compression"
The following algorithm would give us a true grey scale, but
we would not have true black, or fully saturated red, green, or
blue (those three corners of the cube would be sliced off).
.(m
C code:

.\"#	ident "@(#)ch10.ex08	1.2" 5/15/91
.\"
(DtReal)((i>>5) + 1)/8.;
(DtReal)(((i>>2) & 0x7) + 1)/8.;
(DtReal)((i& 0x3) + 1)/4.;

.sp
\*(Fo code:

.\"#	ident "@(#)ch10.ex08.f	1.2" 5/15/91
.\"
	(I/32+1)/8.0D0
	(MOD(I/4,8)+1)/8.0D0
	(MOD(I,4)+1)/4.0D0
.)m
.H2 "Range Intensity Mapping"
With range intensity mapping, you partition the color map for the
device into a series of shade ranges, where each range corresponds to
a particular color, for instance red or gold.
Within each range, the intensity increases from zero to the maximum
intensity for that color.
When this mode is used, the full-color value is converted to an
intensity value that is mapped to a 
particular shade range, and then converted to an index into the
color table.
.lp
For example, in \*(FT, the color table is divided into eight
shade ranges (0 to 7) for eight different colors (gold, red, green,
blue, cyan, yellow, magenta, and white).
.(F "./PS/9.9ps" 2.5i 0
.)F "Color Table Using Shade Ranges"
The blue range extends from entry 96 to 127 in the color table.
Within this range, entry 96 contains none of this color (black) and entry
127 contains the full intensity of this color (blue).
The primitive attribute \f2DoShadeIndex <DOSI>\fP specifies which
shade range to use for subsequent objects.
For example, \f2DoShadeIndex(3) <DOSI(3)>\fP would make the objects
blue.
The computed full-color value is converted to an intensity value of
\f2I\fP, which is between 0 and 1.
This value is then multiplied by the number of entries in that color 
range (here, 31) and then added to the beginning of the range
(here, 96) to generate the index into the color table (i.e. 
$index~=~I~times~( 127 - 96 ) + 96$).
.lp
The following code illustrates setting up the color table for
eight shade ranges, each with 32 values.

.(m
C code:

.\"#	ident "@(#)ch10.ex09	1.3" 5/15/91
.\"
DtReal entries [256*3], *p;
DtReal colors [8][3] = {.8, .498, .196, /* gold */
                        1., 0., 0.,     /* red */
                        0., 1., 0.,     /* green */
                        0., 0., 1.,     /* blue */
                        0., 1., 1.,     /* cyan */
                        1., 1., 0.,     /* yellow */
                        1., 0., 1.,     /* magenta */
                        1., 1., 1.};    /* white */
DtInt range [16];
p = entries;
    for(i=0; i<8; i++) {
       for (j=0; j<32; j++){
           *p++ = colors[i][0]*(j/31.);
           *p++ = colors[i][1]*(j/31.);
           *p++ = colors[i][2]*(j/31.);
       }
       range [2*i] = i*32;
       range [2*i +1] = (i+1)*32-1;
    }

device = DoDevice("stdx11","-visualtype DcPseudoColor");

/* set up color table, and 
 * specify range intensity mapping with 8 shade ranges
 */

DdSetColorEntries(device, DcRGB, 0, 256, entries);
DdSetShadeMode (device, DcRange);  
DdSetShadeRanges (device, 0, 8, range); 

/* specify which shade index to use */

DgAddObj(DoShadeIndex(n));    

/*	.
 *	.
 *  display objects here...
 *	.
 *	.
 */

.sp
\*(Fo code:

.\"#	ident "@(#)ch10.ex09.f	1.3" 5/15/91
.\"
      REAL*8 ENTRYS(3,256), COLORS(3,8)
      INTEGER*4 RANGE(16), DEVICE
C
      DATA COLORS / .8D0, .498D0, .196D0,     ! gold 
                        1.D0, 0.D0, 0.D0,     !red 
                        0.D0, 1.D0, 0.D0,     !green 
                        0.D0, 0.D0, 1.D0,     !blue
                        0.D0, 1.D0, 1.D0,     !cyan
                        1.D0, 1.D0, 0.D0,     !yellow 
                        1.D0, 0.D0, 1.D0,     !magenta
                        1.D0, 1.D0, 1.D0 /    !white
C
      DO 40 I=0,7
      DO 30 J=0,31
      K=1+32*I+J
      DO 20 L=1,3
20    ENTRYS(L,K)=COLORS(L,I+1)*(J/31.0)
30    CONTINUE
      RANGE(2*I+1)=I*32
40    RANGE(2*I+2)=(I+1)*32-1
C
      DEVICE=DOD('stdx11',6,'-visualtype DcPseudoColor',25)
C
      ! set up color table and
      ! specify range intensity mode with 8 shade ranges
      CALL DDSCE(DEVICE, DCRGB,0,256,ENTRYS) 
      CALL DDSSM(DEVICE, DCRNG) 
      CALL DDSSR(DEVICE,0,8,RANGE) 
C
      ! specify which shade range to use
      CALL DGAO (DOSI(n))  
C   
      ! display objects here
.)m
.rs
.sp -.5v
.H2 "Pros and Cons"
There are tradeoffs to consider before choosing one of the two
pseudocolor modes.  With bit compression, you have a wide spread
across the color spectrum but a coarse sampling of shades within
each color.  With range intensity mapping, you typically choose a smaller
selection of colors, but for each color, you can have a full range of
intensities.  Bit compression is useful for widely varied
applications that require many different colors.  But if the
application requires only a limited number of colors, range
intensity mapping produces the best simulation of true color,
since each color can have a full range of intensities.  Range
intensity mapping also allows you to set up a single grey scale,
from 0 to 255, for an intensity map that ranges from black to
white.  With bit compression, vertex shading produces color
banding because the samples of color are far apart.  To avoid
this effect, specify constant shading for the interpolation type.
.H1 "Chapter Summary"
Chapter 9 describes how primitive objects, studio objects, and
their attributes are organized into \f2views\fP and \f2frames\fP, and
then assigned to a particular \f2device.\fP
.lp
A \f2view\fP is used to combine primitive objects and their
attributes with the viewing parameters for those objects (cameras,
lights, and their attributes).
The \f2definition group\fP for a view consists of the cameras, lights,
and their attributes.
The \f2display group\fP for a view consists of the primitive objects
and their attributes.
View features that can be specified include rendering style, update
type, active camera, clear flag, background color, background raster,
background justification, and view boundary.
.lp
A \f2frame\fP defines a virtual image, which consists of one or
more views.
Multiple views can be collected into one frame.
Views are rendered in the order in which they are added to a frame.
If the views overlap, the last one to be rendered will be the only one
entirely visible.
Views and frames both use \f2frame coordinates\fP.
When a view is placed within a frame, it is \f2clipped\fP to the frame
boundary.
.lp
A \f2device\fP is an output mechanism used to display a frame.
Examples of devices include the video display, an X-window, an image
file, or a hardcopy device.
A device can have only \f2one\fP  frame attached to it at a time.
A given frame, however, can be set to more than one device.
If extra white space results when a frame is mapped to a device,
the frame can be \f2justified\fP inside the device viewport to
allocate this white space.
Device coordinates are three-dimensional floating point values in
pixels that relate directly to the display device.
For \f2pseudocolor\fP devices, you should always set up a color table.
With pseudocolor, the full-color image is converted into a pseudocolor
image by one of two methods: \f2bit compression\fP or \f2range
intensity mapping.\fP 
.lp
When a view, frame, or device is \f2updated\fP, it is redisplayed.
The view \f2update type\fP indicates whether all objects within a view
should be updated or only the display objects should be updated.
