 |
» |
|
|
 |
When modeling an object with a hierarchical structure, one
soon realizes a need to have one segment be able to "call" others.
Display List does this with any of the four routines call_segment, cond_call_segment, execute_segment, or cond_execute_segment. By
using these routines, you can have one segment call many other segments,
each of which can call still others. Designing a House |  |
Suppose we are designing a house. Let's make a list of things
we need to include in it. The list below, where indentation indicates
the hierarchical structure, notes some things we might need. Of
course, at the top of the list is the house itself. In order to structure the display list as noted above, each
of the "entities" must be put into its own segment (in this context,
an "entity" is a part of the house, regardless of its location in
the structure hierarchy). This is pretty straightforward: just open
a segment, call the desired Starbase/Display List routines, and
close the segment. The open_segment
routine requires a segment number as one of its parameters. In many
large interactive applications, segment numbers are determined during
execution, and the user may never know what the numbers are. On
the other hand, one approach which can be quite useful for small,
simple, static display lists is to define the segment numbers such
that the numbers themselves indicate the hierarchical structure.
The latter approach is taken for the small example programs in this
manual: #define House 1 #define Wall 11 #define WallSurface 111 #define Door 112 #define Window 113 #define Frame 1131 #define Panes 1132 #define Roof 12 #define RoofSurface 121 #define Chimney 122 |
 |
These are two opposing methods of designing a hierarchy, either
of which might be more appropriate for your application. The top-down method defines the largest, most all-encompassing
structure first. In our case: "The house is made of a wall and a
roof." Then, take these entities, and define them; e.g.: "The wall
is made of the wall's surface, a door, and a window." Then, you
take these entities and further define them; e.g.: "The window is
made of the window frame and the panes of glass." And so on, as
far as your application requires. The bottom-up method, on the other hand, starts at the finest
details and defines them first. The rationale for using bottom-up
might go: "Let's not worry about building a house until we figure
out how to build a window." So, the window is defined, along with
other low-level entities. In our case, other low-level entities
would include the wall surface, the door, etc. Then, once these
low-level entities exist, they can be combined into larger structures.
Then, these larger structures can be combined into still larger
structures. As stated, either of these approaches, or even a combination
of them, may be most appropriate for your application. Display List supports both approaches. If you wish to define
segments for the low-level entities first, then define higher-level
entities by calling the lower-level ones, this is fine. Or, if you
wish to define high-level segments first, by calling the (nonexistent)
lower-level segments, Display List will create empty segments which
you can later define to be what you want. For our example, let's take the top-down approach. The highest
level in the structure is this: house consists of the wall and the
roof. In code: open_segment(fildes, House, AppendOff, DisplayOff); call_segment(fildes, Wall); call_segment(fildes, Roof); close_segment(fildes); |
Notice that since this is the first time the segment House has been opened, the
state of 〈append〉 makes
no difference; appending elements to the end of an empty segment
and adding elements after the current element in an empty segment
amount to the same thing. Also note that since we are taking the
top-down approach, Wall
and Roof are
not yet defined. Therefore, it makes no sense to set the 〈display〉
parameter of open_segment
to TRUE; Display
List doesn't know what Wall
and Roof are
supposed to be (and right now they are empty), so nothing could
be displayed. After House
is defined in terms of Wall
and Roof, Wall is defined: open_segment(fildes, Wall, AppendOff, DisplayOff); call_segment(fildes, WallSurface); call_segment(fildes, Door); call_segment(fildes, Window); close_segment(fildes); |
and so forth. Every segment is defined either in terms of
other segments, or in terms of Starbase commands. After all the segments are defined, our program displays them
twice: The first time, the segments are displayed
one at a time, with an appropriate announcement being printed before
each one, and with a one-second pause after each segment. This illustrates
that you can display any segment of a display list you like; you
don't have to display starting at the highest level. The second time, the House
segment is displayed. Since this is the highest-level segment in
the structure, all sub-structures are included — the whole
house is drawn.
Here is the program that implements the house structure in
a display list:  |
#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 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 "House.c" */ { int fildes; /* file descriptor */ if ((fildes = gopen(getenv("SB_OUTDEV"), OUTDEV, NULL, INIT)) == -1) { fprintf(stderr, "%s %s\\n", "Error: gopen failed using environment", "variable SB_OUTDEV."); exit(-1); } buffer_mode(fildes, AlwaysCurrent); vdc_extent(fildes, 0.0, 0.0, 0.0, 1.25, 1.0, 0.0); view_window(fildes, 0.0, 0.0, 10.0, 8.0); interior_style(fildes, INT_HOLLOW, Edges); /*=== define the display list segments comprising the house =======*/ /*- Section 1: Define the house's structure */ open_segment(fildes, House, AppendOff, DisplayOff); call_segment(fildes, Wall); call_segment(fildes, Roof); close_segment(fildes); /*- Section 1.1: Define the wall's structure -*/ open_segment(fildes, Wall, AppendOff, DisplayOff); call_segment(fildes, WallSurface); call_segment(fildes, Door); call_segment(fildes, Window); close_segment(fildes); /*- Section 1.1.1: Define the wall surface's structure -*/ open_segment(fildes, WallSurface, AppendOff, DisplayOff); rectangle(fildes, 2.0, 1.0, 8.0, 5.0); close_segment(fildes); /*- Section 1.1.2: Define the door's structure -*/ open_segment(fildes, Door, AppendOff, DisplayOff); rectangle(fildes, 2.5, 1.0, 4.2, 4.2); ellipse(fildes, 0.06, 0.06, 2.65, 2.3); close_segment(fildes); /*- Section 1.1.3: Define the window's structure -*/ open_segment(fildes, Window, AppendOff, DisplayOff); call_segment(fildes, Frame); call_segment(fildes, Panes); close_segment(fildes); /*- Section 1.1.3.1: Define the window frame's structure -*/ open_segment(fildes, Frame, AppendOff, DisplayOff); rectangle(fildes, 5.0, 2.0, 7.0, 4.0); close_segment(fildes); /*- Section 1.1.3.2: Define the window panes' structure */ open_segment(fildes, Panes, AppendOff, DisplayOff); rectangle(fildes, 5.1, 2.1, 5.95, 2.95); rectangle(fildes, 6.05, 2.1, 6.9, 2.95); rectangle(fildes, 6.05, 3.05, 6.9, 3.9); rectangle(fildes, 5.1, 3.05, 5.95, 3.9); close_segment(fildes); /*- Section 1.2: Define the roof's structure -*/ open_segment(fildes, Roof, AppendOff, DisplayOff); call_segment(fildes, RoofSurface); call_segment(fildes, Chimney); close_segment(fildes); /*- Section 1.2.1: Define the roof surface's structure -*/ open_segment(fildes, RoofSurface, AppendOff, DisplayOff); { static float RoofStructure[3][2] = { 1.0, 5.0, 9.0, 5.0, 5.0, 7.0}; polygon2d(fildes, RoofStructure, 3, NoFlags); } close_segment(fildes); /*- Section 1.2.2: Define the chimney's structure */ open_segment(fildes, 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(fildes, ChimneyStructure, 4, NoFlags); } close_segment(fildes); /*=== draw the house piecemeal =================================*/ printf("Chimney...\\n"); fflush(stdout); refresh_segment(fildes, Chimney); sleep(1); printf("RoofSurface...\\n"); fflush(stdout); refresh_segment(fildes, RoofSurface); sleep(1); printf("WallSurface...\\n"); fflush(stdout); refresh_segment(fildes, WallSurface); sleep(1); printf("Door...\\n"); fflush(stdout); refresh_segment(fildes, Door); sleep(1); printf("Frame...\\n"); fflush(stdout); refresh_segment(fildes, Frame); sleep(1); printf("Panes...\\n"); fflush(stdout); refresh_segment(fildes, Panes); sleep(1); /*=== draw the house all at once ==============================*/ clear_view_surface(fildes); sleep(1); printf("House...\\n"); fflush(stdout); refresh_segment(fildes, House); gclose(fildes); } |
 |
Note that the Starbase "initialization" statements (vdc_extent, view_window, interior_style) are outside
the display list entirely, rather than being included in, say, the
House segment.
Putting these statements in the House
segment is entirely permissible, but if you attempt to display lower-level
segment before the segment that executes these
initialization-type statements, the image may not appear at all
(in our case, everything would be outside the
clip limits), or it may be improper (e.g., filled polygons instead
of hollow). Here is the graphical output of the program:
|