Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
Starbase Display List Programmer's Manual: HP 9000 Series 700 Computers > Chapter 7 Display List Editing

Segment-Directed Functions

» 

Technical documentation

» Feedback
Content starts here

 » Table of Contents

 » Glossary

 » Index

As mentioned above, the phrase "segment-directed functions" refers to those functions whose actions can relate to segments other than the currently open one, and those functions that can act upon many segments at once. The various operations are:

  • Changing references. You can cause all segments that refer to a particular segment name, to refer to a different segment name.

  • Renaming segments. You can rename either a single segment, or simultaneously rename a segment and all references to it.

  • Deleting segments. You can delete a specified segment from the display list, as well as all references to it in all other segments, or delete all segments in the entire display list.

  • Copy segments. You can copy a segment from elsewhere in the display list (or from a different display list) into the currently open segment.

These operations are described below in the context of our house. After considering for a while, we want to make the following changes:

  • It seems unnecessarily complex to have the Window segment call the Frame and Panes segments; let's move the Starbase primitives to the Window segment itself, and remove the Frame and Panes segments.

  • Instead of having the square window in the display list, as we had before, we want an octagonal window.

Copying Display List Segments

Suppose our house model was complex enough to have several windows. If all the windows were identical, we could have a single segment describing the window, and call that segment (with appropriate transformations on the stack) to draw the many windows. If you want a different window, just edit the window segment. However, in such a case, a change to the window definition changes all instances of the window.

If we want only one window to be different, we could copy the window segment into another segment, edit the copy, and then call the new window where desired.

This scenario is a good use of the copy_segment functionality, but the house model we're dealing with has but a single window. Thus, we'll use copy_segment for another reason. We mentioned above that we wanted to consolidate the Frame and Panes segments into the Window segment, since there wasn't enough in either of the two smaller segments. To do this, we can use the copy_segment routine:

  • copy_segment(〈fildes〉, 〈segno〉);

where:

  • segno〉 is the number specifying the segment to be copied into the currently open segment. The copied segment is placed immediately after the current element.

Segment-copying is illustrated by the following diagrams. Assume the existence of "Segment A," with three elements, and "Segment B," with two elements. The current element in Segment A is the second user-defined element:

Figure 7-8 Segment A

Segment A

Figure 7-9 Segment B

Segment B

Segment A looks like this after executing copy_segment(fildes, B);[20]:

Figure 7-10 Segment A

Segment A

Segment B is left unchanged.

In our example, we want to copy the Frame and Panes segments into the Window segment. However, we don't want the call_segment elements referring to those subordinate segments to also remain in the Window segment. If we do, the window will be drawn twice: once from the Window segment, and once from the subordinate segments called by Window. Therefore, we must delete at least the call_segment elements, and we might as well delete the two subordinate segments as well.

Deleting Display List Segments

To delete elements from a segment, you can use the delete_eles routine, as described above. To delete whole segments, use delete_segment:

  • delete_segment(〈fildes〉, 〈segno〉);

where:

  • segno〉 is an integer specifying the segment to be deleted.

Or, to simultaneously delete a segment as well as all the elements in the display list that refer to that segment, you can call delete_segment_and_references. The parameters are the same as for delete_segment. And, since it is easier, let's use delete_segment_and_references in our example.

These operations need to be done:

  • In order to see exactly what is going on in the display list, let's print out the pertinent segments, using the same subroutine as before. At this point, it's a "before" picture of the Window segment, and it's labelled to that effect.

  • Open the Window segment.

  • Set the element pointer to the null element.

  • Copy the Frame segment into the current segment. It goes immediately after the current element, which, at this point, is the null element. After the copy, the element pointer will be pointing to the last element copied into the current element.

  • Copy the Panes segment into the current segment. It goes immediately after the current element, which is now the last element element copied from Frame.

  • Close the Window segment.

  • The call_segment elements (referring to Frame and Panes) are still in the Window segment, but these are deleted at this point by calls to delete_segment_ and_references.

  • Print an "after" picture of the Window segment, labelled as such.

In code, this would look like:

printf("Window segment before consolidation:\n");
PrintSegment(fildes, Window);
open_segment(fildes, Window, AppendOff, DisplayOff);
set_ele_ptr(fildes, 0); /* the null element */
copy_segment(fildes, Frame); /* get elements from "Frame" */
copy_segment(fildes, Panes); /* get elements from "Panes" */
close_segment(fildes);
delete_segment_and_references(fildes, Frame); /* delete frame seg */
delete_segment_and_references(fildes, Panes); /* delete panes seg */
printf("\nWindow segment after consolidation:\n");
PrintSegment(fildes, Window);

The non-graphical output of this section of the program looks like this:

Window segment before consolidation:
ELEMENT 0
call_segment( fd, 1131)
call_segment( fd, 1132)

Window segment after consolidation:
ELEMENT 0
rectangle( fd, 5, 2, 7, 4)
rectangle( fd, 5.1, 2.1, 5.95, 2.95)
rectangle( fd, 6.05, 2.1, 6.9, 2.95)
rectangle( fd, 6.05, 3.05, 6.9, 3.9)
rectangle( fd, 5.1, 3.05, 5.95, 3.9)

As you can see, before consolidation, the Window segment called the Frame segment (1131) and the Panes segment (1132). After consolidation, the Window segment contains the former contents of those two subordinate segments.

Changing Segment References

To "change a segment reference" means to change all call_segment or execute_segment elements that refer to Segment n, in the entire display list, conditional or not, to refer to Segment m. That is, it replaces all call_segment, cond_call_segment, execute_segment, and cond_execute_segment elements that call a particular segment with corresponding elements that call a different segment.

A typical use for this functionality is when the user of an interactive graphics program says something like, "Make all of these look like that one." All occurrences calling a particular segment can be converted so they call the desired segment instead.

The Display List routine that does this is change_segment_references; its syntax is:

  • change_segment_references(〈fildes〉, 〈old_segno〉, 〈new_segno〉);

where:

  • old_segno〉 is an integer specifying the current name of the segment — that one that you no longer want to be called.

  • new_segno〉 is an integer specifying the new name to be referenced by the changed "calling" elements.

The actions of change_segment_references are illustrated below. Assume the existence of a segment 2, a segment 3, and a segment 7, which calls segment 3:

Figure 7-11 Segment 7

Segment 7

Figure 7-12 Segment 2

Segment 2

Figure 7-13 Segment 3

Segment 3

After executing change_segment_references(fildes, 3, 2); the display list looks like this. The results are the same regardless of which segment was open at the time of the change_segment_references:

Figure 7-14 Segment 7

Segment 7

Figure 7-15 Segment 2

Segment 2

Figure 7-16 Segment 3

Segment 3

In our example, we want the old window — the square one — to be replaced by a new octagonal one. Thus, the Wall segment, which currently calls segment Window, must be changed to call the octagonal window segment, named NewWindow. And at some point, the octagonal window must be defined in terms of Starbase primitives. Remember, a segment need not be defined before it is called: an empty segment with the appropriate name will be created if a nonexistent segment is referenced.

Specifically, what we want to do is this:

  • Print the Wall segment to show that it originally calls the old, rectangular window (even though it is now consolidated into a single segment).

  • Draw the house. It indeed uses the rectangular window. Pause until the user presses Return to go on. This "pausing" sequence, which is called more than once in this program, is implemented via a C macro called NewImage.

  • Define the octagonal window segment (called NewWindow), using Starbase primitives. For reasons of brevity, another macro was used here: triangle. You pass it 〈fildes〉, x1, y1, x2, y2, x3, y3, and it draws a triangle.

  • Using change_segment_references, modify the Wall segment so that it calls NewWindow instead of Window.

  • Print the Wall segment so you can see that the called segment number is indeed different.

  • Redraw the house. It now has an octagonal window.

In code, this looks like the following:

/*- draw the original house with consolidated window segment */
printf("\\nWall segment (original):\\n");
PrintSegment(fildes, Wall);
refresh_segment(fildes, House);
NewImage;
/*- Section 1.1.4: Define the octagonal window's structure */
open_segment(fildes, NewWindow, AppendOff, DisplayOff);
curve_resolution(fildes, STEP_SIZE, 45 deg, 45 deg, 45 deg, 45 deg);
ellipse(fildes, 1.08, 1.08, 6.0, 3.0, 22.5 deg);/* window frame */
rectangle(fildes, 5.65, 2.65, 6.35, 3.35); /* central square */
rectangle(fildes, 5.05, 2.65, 5.60, 3.35); /* west rectangle */
triangle(fildes, 5.60, 3.40, 5.60, 3.95, 5.05, 3.40); /* NW triangle */
rectangle(fildes, 5.65, 3.40, 6.35, 3.95); /* north rectangle */
triangle(fildes, 6.40, 3.40, 6.95, 3.40, 6.40, 3.95); /* NE triangle */
rectangle(fildes, 6.40, 2.65, 6.95, 3.35); /* east rectangle */
triangle(fildes, 6.40, 2.60, 6.40, 2.05, 6.95, 2.60); /* SE triangle */
rectangle(fildes, 5.65, 2.05, 6.35, 2.60); /* south rectangle */
triangle(fildes, 5.60, 2.60, 5.05, 2.60, 5.60, 2.05); /* SW triangle */
close_segment(fildes);
/*- change calls to square window to calls to octagonal window */
change_segment_references(fildes, Window, NewWindow);
printf("\\nWall segment (after \\"change_segment_references\\"):\\n");
PrintSegment(fildes, Wall);
refresh_segment(fildes, House);

The house, with its new octagonal window, now looks like this:

Figure 7-17 House with New Window Segment

House with New Window Segment

The non-graphical output of this section of the program looks like this:

Wall segment (original):
call_segment( fd, 111)
call_segment( fd, 112)
call_segment( fd, 113)

Wall segment (after "change_segment_references"):
call_segment( fd, 111)
call_segment( fd, 112)
call_segment( fd, 114)

Note that the call_segment element referencing segment 113 (Window) has been changed to 114 (NewWindow).

Renaming Segments

Although the above approach using change_segment_references works perfectly well, it has the effect of changing the segment number referenced by the calling segment. In our example, the third element of the Wall segment is modified: 113 changes to 114. If this is undesirable in your application, you can change window styles without changing called segment numbers. In other words, you can:

  • Cause the house to change windows from square to octagonal, and

  • Retain a call to Window (as opposed to NewWindow) in the Wall segment.

The routines that address this need are:

  • rename_segment(〈fildes〉, 〈old_segno〉, 〈new_segno〉);

    • and

  • rename_segment_and_references(〈fildes〉,〈old_segno〉,〈new_segno〉);

where:

  • old_segno〉 is an integer that specifies the segment whose name is to be changed.

  • new_segno〉 is an integer that specifies the new name of the segment specified by 〈old_segno〉.

This action is illustrated by the following diagrams. There are several different variations on this theme of renaming segments. The differences arise because referenced segments may or may not exist, and an affected segment may or may not be referred to from elsewhere. These possibilities are shown below:

Only the first segment exists.

Before renaming, assume the display list looks like:

Figure 7-18 Segment 3

Segment 3

After renaming with rename_segment(fildes, 3, 2); the display list looks like this:

Figure 7-19 Segment 2

Segment 2

This is perhaps the most intuitive of all the possible scenarios involving rename_segment.

Both segments exist; references exist.

Before renaming, assume the display list looks like:

Figure 7-20 Segment 2

Segment 2

Figure 7-21 Segment 3

Segment 3

Figure 7-22 Segment 7

Segment 7

After renaming Segment 3 to Segment 2 via rename_segment(fildes, 3, 2); the display list has this configuration:

Figure 7-23 Segment 2

Segment 2

Figure 7-24 Segment 3

Segment 3

Figure 7-25 Segment 7

Segment 7

As before, the original Segment 2 is destroyed by renaming another segment to its name. Segment 3, however, is still required to exist because it is referenced from elsewhere. So, in the tradition of Display List, the reference to a nonexistent segment causes an empty segment by that name to be created.

Both segments exist; no references to either one.

Before renaming, assume the display list looks like:

Figure 7-26 Segment 2

Segment 2

Figure 7-27 Segment 3

Segment 3

After renaming Segment 3 to Segment 2 via rename_segment(fildes, 3, 2); the display list has this configuration:

Figure 7-28 Segment 2

Segment 2

As you can see, the original Segment 2 is destroyed by renaming another segment to its name.

Only the second segment exists.

Before renaming, assume the display list looks like:

Figure 7-29 Segment 2

Segment 2

After renaming with rename_segment(fildes, 3, 2); the display list looks like this:

Figure 7-30 Segment 2

Segment 2

What happened was this. When a reference to the nonexistent Segment 3 was made, Display List noticed and created an empty Segment 3. Then it continues the renaming operation as if it were in the category of "Both segments exist; no references to either one," as described above.

In our house example, we wish to install the new octagonal window without requiring segment Wall to call NewWindow instead of Window. The first thing to do is to put things back the way they were: reinstall the old rectangular window by calling change_segment_references:

change_segment_references(fildes, NewWindow, Window);

Now we can do the appropriate renaming:

#define OldWindow       9999
.
.
.
rename_segment(fildes, Window, OldWindow);
rename_segment(fildes, NewWindow, Window);

And finally, print and refresh the segment so we can see if the operation was successful:

printf("\\nWall segment (after \\"rename_segment\\"s):\\n");
PrintSegment(fildes, Wall);
refresh_segment(fildes, House);

The graphical output from this invocation of refresh_segment is the same as above, but the segment Wall is different. Here is what the program prints at this point:

Wall segment (after "rename_segment"s):
call_segment( fd, 111)
call_segment( fd, 112)
call_segment( fd, 113)

A quick check of the original state of segment Wall will satisfy you that while the child segment name is the same as before, the contents of the segment referenced by Window are now different.

Here is the whole program. It draws three pictures: the first is the original house with the rectangular window, and the last two are the house with the octagonal window (shown a few pages ago).

#include <starbase.c.h>               /* get Starbase definitions */
#include <dl.c.h> /* get Display List definitions */
#include <stdio.h> /* get standard I/O functions */
#include <math.h> /* link with library "-lm" */

#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 AbbreviateArrays 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 /* / */

#define NewWindow 114 /* for the octagonal window */
#define OldWindow 9999 /* get it out of the way */
#define deg *M_PI/180 /* convert degrees to radians */
#define triangle(fd,x1,y1,x2,y2,x3,y3) move2d(fd,x1,y1), draw2d(fd,x2,y2); \\
draw2d(fd,x3,y3); draw2d(fd,x1,y1);
#define NewImage make_picture_current(fildes); \\
fprintf(stderr, \\
"Press [Return] to go on. "); \\
getchar(); \\
clear_view_surface(fildes)main() /* program "SegHouse.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 square 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 square 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 square 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);
/*=== modify the house and re-draw it ===========================*/
/*- combine window segments into one */
printf("Window segment before consolidation:\\n");
PrintSegment(fildes, Window);
open_segment(fildes, Window, AppendOff, DisplayOff);
set_ele_ptr(fildes, 0); /* the null element */
copy_segment(fildes, Frame); /* get elements from "Frame" */
copy_segment(fildes, Panes); /* get elements from "Panes" */
close_segment(fildes);
delete_segment_and_references(fildes, Frame); /* delete frame seg */
delete_segment_and_references(fildes, Panes); /* delete panes seg */
printf("\\nWindow segment after consolidation:\\n");
PrintSegment(fildes, Window);
/*- draw the original house with consolidated window segment */
printf("\\nWall segment (original):\\n");
PrintSegment(fildes, Wall);
refresh_segment(fildes, House);
NewImage;
/*- Section 1.1.4: Define the octagonal window's structure */
open_segment(fildes, NewWindow, AppendOff, DisplayOff);
curve_resolution(fildes, STEP_SIZE, 45 deg, 45 deg, 45 deg, 45 deg);
ellipse(fildes, 1.08, 1.08, 6.0, 3.0, 22.5 deg); /* window frame */
rectangle(fildes, 5.65, 2.65, 6.35, 3.35); /* central square */
rectangle(fildes, 5.05, 2.65, 5.60, 3.35); /* west rectangle */
triangle(fildes, 5.60, 3.40, 5.60, 3.95, 5.05, 3.40); /* NW triangle */
rectangle(fildes, 5.65, 3.40, 6.35, 3.95); /* north rectangle */
triangle(fildes, 6.40, 3.40, 6.95, 3.40, 6.40, 3.95); /* NE triangle */
rectangle(fildes, 6.40, 2.65, 6.95, 3.35); /* east rectangle */
triangle(fildes, 6.40, 2.60, 6.40, 2.05, 6.95, 2.60); /* SE triangle */
rectangle(fildes, 5.65, 2.05, 6.35, 2.60); /* south rectangle */
triangle(fildes, 5.60, 2.60, 5.05, 2.60, 5.60, 2.05); /* SW triangle */
close_segment(fildes);
/*- change calls to square window to calls to octagonal window */
change_segment_references(fildes, Window, NewWindow);
printf("\\nWall segment (after \\"change_segment_references\\"):\\n");
PrintSegment(fildes, Wall);
refresh_segment(fildes, House);
NewImage;
/*- but we don't want the segment name to be changed... -*/
change_segment_references(fildes, NewWindow, Window); /* revert */
rename_segment(fildes, Window, OldWindow);
rename_segment(fildes, NewWindow, Window);
printf("\\nWall segment (after \\"rename_segment\\"s):\\n");
PrintSegment(fildes, Wall);
refresh_segment(fildes, House);
gclose(fildes);
}/******************************************************************/
PrintSegment(fildes, SegmentNo)
int fildes; /* file descriptor */
int SegmentNo; /* segment to print */
{
int AtTop, AtBottom; /* booleans */

open_segment(fildes, SegmentNo, AppendOff, DisplayOff);
set_ele_ptr(fildes, 0);
do {
print_element(fildes, AbbreviateArrays);
inq_ele_ptr_at_bound(fildes, &AtTop, &AtBottom);
set_ele_ptr_relative(fildes, 1);
} while (! AtBottom);
close_segment(fildes);
}


[20] You can use display_segment to do a pseudo-copy of a segment from one display list into an entirely different display list if the destination device has an open segment. As mentioned, this display-list-to-display-list copying is subject to restrictions: elements with the attribute DISP_IGNORE are not copied, and references are expanded.

Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© 1995 Hewlett-Packard Development Company, L.P.