 |
» |
|
|
 |
In Chapter 4 “The Basics of Using a Display List”, the
"House.c" example
showed examples of refreshing display list segments. Below, the
program is modified in two ways: This time, the display list is a device-independent
display list. This has a couple of implications: There are two different file descriptors
needed: one for the display list (displist)
and one for the output device (outdev). The image is drawn using the display- routines rather
than the refresh-
routines.
The segments are displayed one element at a time
in the "piecemeal" section. This was implemented through use of
a subroutine.
Accessing Elements One at a Time |  |
When a segment is refreshed or displayed, all the elements
in it are drawn consecutively and inseparably. If your application
would benefit from the ability to access single elements within
a segment, Display List has routines to do it. The element-specific
routines used in the modified "house" program are as follows: - set_ele_ptr
Set the element pointer to an absolute location
in the currently open segment. This is called only once, to initialize
the element pointer to the first (null) element in the open segment. - display_element
Draw, on the specified output device, the portion
of the image that is represented by the current element in the specified
display list. - print_element
Print, on stdout,
the function name and the parameters of the current element in the
currently open segment. This is merely for the user's information
(it is a debugging tool), and is not required for the logic of the
program to work. - set_ele_ptr_relative
Set the element pointer to a location relative to
the current element in the currently open segment. This is used
to step through the elements in the open segment one at a time. - inq_ele_ptr_at_bound
This routine returns two boolean values: the first
tells you whether or not the current element is the first element
in the segment, and the second tells you whether or not the current
element is the last element in the segment. Only the second is used
in this program, and it is the loop-control variable.
These routines are used in the subroutine as follows:  |
ShowElementDisplay(displist, outdev, SegNo, SegName) int displist; /* file descriptor display list */ int outdev; /* file descriptor output device */ int SegNo; /* the segment number to display */ char *SegName; /* the name of the segment */ int AtTop, AtBottom; /* loop control variables */ printf("%s (segment #%d)...\\n", SegName, SegNo); open_segment(displist, SegNo, AppendOff, DisplayOff); set_ele_ptr(displist, 0); /* set ptr. to NULL element */ do { /* for all non-NULL elements */ inq_ele_ptr_at_bound(displist, /* is the current element... */ &AtTop, &AtBottom); /* ...at one of the ends? * if (AtBottom) /* if so... */ continue; /* skip rest of the loop. */ set_ele_ptr_relative(displist, 1); /* increment element ptr. */ print_element(displist, AbbrevArrays); /* for user's benefit */ fflush(stdout); /* make sure it prints */ display_element(displist, outdev);/* display current element */ sleep(1); /* let user notice */ } while (! AtBottom); /* if not at end, loop */ close_segment(displist); sleep(1); } |
 |
The identifier AbbrevArrays
is a macro defined to be the boolean value TRUE. It tells the print_element function to
"abbreviate the arrays," which means to note the fact that there
is an array there, but don't print all the values in the array.
If AbbrevArrays
is FALSE, all
values in the array are printed. Selected segments are drawn by sending the appropriate information
to the subroutine: ShowElementDisplay(displist, outdev, Roof, "Roof"); ShowElementDisplay(displist, outdev, Window, "Window"); ShowElementDisplay(displist, outdev, Door, "Door"); ShowElementDisplay(displist, outdev, Wall, "Wall"); |
Note that when segment Wall
is drawn, it re-draws Door
and Window, since
they are sub-segments of Wall.
At this point, nothing appears to happen: lines are being drawn
over already-existent lines. And finally, the whole house is drawn at once by sending the
file descriptor of the device-independent display list, the segment
number, and the file descriptor of the output device to the routine
display_segment: display_segment(displist, House, outdev); |
Here is a listing of the modified program, called HouseEle.c. There are several
things of note[15]: Notice that there are now two gopen statements: one for
the device-independent display list, and one for the output device. The display-list-defining logic is identical to
that of program House.c. The initialization statements — those which
are not in any segment — are called with the file descriptor
outdev, and not
displist. There is a one-second wait after each element has
been displayed, and an additional one-second wait after each segment
has been completed. Thus, there is a two-second wait between segments,
so you can identify where one segment ends and another one starts.
 |
#include <starbase.c.h> /* get Starbase definitions */ #include <dl.c.h> /* get Display List definitions */ #include <stdio.h> /* get standard I/O functions */ #define AppendOff FALSE /* sent to "open_segment" */ #define AppendOn TRUE /* sent to "open_segment" */ #define DisplayOff FALSE /* sent to "open_segment" */ #define DisplayOn TRUE /* sent to "open_segment" */ #define AbbrevArrays TRUE /* sent to "print_element" */ #define AlwaysCurrent FALSE /* sent to "buffer_mode" */ #define Edges TRUE /* sent to "interior_style" */ #define NoFlags FALSE /* sent to "polygon2d" */ #define House 1 /* \\ */ #define Wall 11 /* \\ */ #define WallSurface 111 /* \\ These mnemonic tokens*/ #define Door 112 /* \\ are associated with */ #define Window 113 /* \\ segment numbers that */ #define Frame 1131 /* / indicate the house's */ #define Panes 1132 /* / hierarchical */ #define Roof 12 /* / structure. */ #define RoofSurface 121 /* / */ #define Chimney 122 /* / */main() /* program "HouseEle.c" */ { int displist, outdev; /* file descriptors */ if ((displist = gopen("&<dev>/null", OUTDEV, "display_list", INIT)) == -1) { fprintf(stderr, "Open of outdev-independent display list failed.\\n"); exit(-1); } if ((outdev = gopen(getenv("SB_OUTDEV"), OUTDEV, NULL, INIT)) == -1) { fprintf(stderr, "%s %s\\n", "Error: gopen failed using environment", "variable SB_OUTDEV."); exit(-2); } buffer_mode(outdev, AlwaysCurrent); vdc_extent(outdev, 0.0, 0.0, 0.0, 1.25, 1.0, 0.0); view_window(outdev, 0.0, 0.0, 10.0, 8.0); interior_style(outdev, INT_HOLLOW, Edges); /*=== define the display list segments comprising the house =======*/ /*- Section 1: Define the house's structure */ open_segment(displist, House, AppendOff, DisplayOff); call_segment(displist, Wall); call_segment(displist, Roof); close_segment(displist); /*- Section 1.1: Define the wall's structure -*/ open_segment(displist, Wall, AppendOff, DisplayOff); call_segment(displist, WallSurface); call_segment(displist, Door); call_segment(displist, Window); close_segment(displist); /*- Section 1.1.1: Define the wall surface's structure -*/ open_segment(displist, WallSurface, AppendOff, DisplayOff); rectangle(displist, 2.0, 1.0, 8.0, 5.0); close_segment(displist); /*- Section 1.1.2: Define the door's structure -*/ open_segment(displist, Door, AppendOff, DisplayOff); rectangle(displist, 2.5, 1.0, 4.2, 4.2); ellipse(displist, 0.06, 0.06, 2.65, 2.3); close_segment(displist); /*- Section 1.1.3: Define the window's structure -*/ open_segment(displist, Window, AppendOff, DisplayOff); call_segment(displist, Frame); call_segment(displist, Panes); close_segment(displist); /*- Section 1.1.3.1: Define the window frame's structure -*/ open_segment(displist, Frame, AppendOff, DisplayOff); rectangle(displist, 5.0, 2.0, 7.0, 4.0); close_segment(displist); /*- Section 1.1.3.2: Define the window panes' structure */ open_segment(displist, Panes, AppendOff, DisplayOff); rectangle(displist, 5.1, 2.1, 5.95, 2.95); rectangle(displist, 6.05, 2.1, 6.9, 2.95); rectangle(displist, 6.05, 3.05, 6.9, 3.9); rectangle(displist, 5.1, 3.05, 5.95, 3.9); close_segment(displist); /*- Section 1.2: Define the roof's structure -*/ open_segment(displist, Roof, AppendOff, DisplayOff); call_segment(displist, RoofSurface); call_segment(displist, Chimney); close_segment(displist); /*- Section 1.2.1: Define the roof surface's structure -*/ open_segment(displist, RoofSurface, AppendOff, DisplayOff); { static float RoofStructure[3][2] = { 1.0, 5.0, 9.0, 5.0, 5.0, 7.0}; polygon2d(displist, RoofStructure, 3, NoFlags); } close_segment(displist); /*- Section 1.2.2: Define the chimney's structure */ open_segment(displist, Chimney, AppendOff, DisplayOff); { static float ChimneyStructure[4][2] = { 6.0, 6.5, 7.0, 6.0, 7.0, 7.5, 6.0, 7.5}; polygon2d(displist, ChimneyStructure, 4, NoFlags); } close_segment(displist); /*=== draw the house piecemeal ==================================*/ ShowElementDisplay(displist, outdev, Roof, "Roof"); ShowElementDisplay(displist, outdev, Window, "Window"); ShowElementDisplay(displist, outdev, Door, "Door"); ShowElementDisplay(displist, outdev, Wall, "Wall"); /*=== draw the house all at once ================================*/ clear_view_surface(outdev); sleep(1); printf("House...\\n"); fflush(stdout); display_segment(displist, House, outdev); gclose(displist); gclose(outdev); }/********************************************************************/ ShowElementDisplay(displist, outdev, SegNo, SegName) int displist; /* file descriptor of display list */ int outdev; /* file descriptor of output outdev */ int SegNo; /* the segment number to display */ char *SegName; /* the name of the segment */ { int AtTop, AtBottom; /* loop control variables */ printf("%s (segment #%d)...\\n", SegName, SegNo); open_segment(displist, SegNo, AppendOff, DisplayOff); set_ele_ptr(displist, 0); /* set ptr. to NULL element */ do { /* for all non-NULL elements */ inq_ele_ptr_at_bound(displist, /* is the current element... */ &AtTop, &AtBottom); /* ...at one of the ends? */ if (AtBottom) /* if so... */ continue; /* skip the rest of the loop. */ set_ele_ptr_relative(displist, 1); /* increment element ptr. */ print_element(displist, AbbrevArrays); /* for user's benefit */ fflush(stdout); /* make sure it prints */ display_element(displist, outdev); /* display current element */ sleep(1); /* let user notice */ } while (! AtBottom); /* if not at end, loop */ close_segment(displist); sleep(1); } |
 |
The graphical output of this program is visually identical
to that of the program House.c
that appeared in Chapter 4 “The Basics of Using a Display List”
Here is the output:
|