/*========================================================================== * * DEC PHIGS and X11, DECwindows Integration Sample Program * * Author: Garry Poegel * * Abstract: * * This sample program demostrates basic techniques for using * the DEC PHIGS graphics library with X11 and DECwindows. * It shows how to integrate PHIGS 3D graphics and PHIGS input * concepts with X11 concepts and DECwindows toolkit input. * * * Environment tested: * DEC PHIGS V2.2 * VAX/VMS V5.4 * *========================================================================*/ #include #include #include #ifdef VMS #include #include #include #endif #ifdef ultrix #include #include #include #endif /* PHIGS structure IDs used */ #define BOX_STRUCT 1 #define TEXT_STRUCT 2 /* PHIGS structure labels used */ #define BOX_LABEL 1 #define STAR_LABEL 2 #define STATUS_LABEL 3 /* Maximum number of PHIGS structures program can use */ #define MAX_STRUCT 100 /* Pickable structures name set */ #define PICK_SET 1 /* Constants to help define the boxes */ #define DELT -0.115 #define STEP 3 #define FACTOR ((float)STEP / 360.0) /* Points to define the first (default) box ) */ Ppoint3 first_point = { 0.27, 0.27, 0.27 }; Ppoint3 second_point = { 0.73, 0.73, 0.73 }; /* X11 display and X window PHIGS uses */ Display *display; Window phigs_x_window; Pint ws_id = 1; /* the PHIGS workstation ID */ Pdspsize display_size; /* the PHIGS display size */ int error_indicator; /* just a temp to hold errors */ int phigs_input_ongoing = 0; /* flag to indicator is interactive PHIGS- PHIGS input is going on */ int box_count = 1; /* number of boxes drawn */ int current_color = 1; /* current drawing color */ Pfloat current_line_width = 2.0; /* current drawing line width */ Pinterstyle current_int_style = PSOLID;/* current drawing interior style */ Pint current_line_type = PLN_SOLID; /* current drawing line type */ Pint pick_ints[1] = { PICK_SET }; /* list of pickable name sets */ /* Basic DEC PHIGS escape function data structure */ struct esc_data_struct { int num_ints; /* number of integers */ int num_floats; /* number of floats */ int num_strings; /* number of strings */ int *ints; /* list of integers */ float *floats; /* list of floats */ int *string_sizes; /* list of string sizes */ char **strings; /* list of strings */ } out_esc_data, in_esc_data; /* Data structure used to store the current state of each box in the PHIGS structure (as application data) for each box */ typedef struct { Ppoint3 center_point; /* center point of box */ Pfloat angle; /* current angle of rotation */ int counter; /* current counter */ int direction; /* current direction of rotation */ } box_status_struct; int int_buffer[3]; /* just a buffer to hold the integer array for the PHIGS escape function */ /* Variables used for calling the PHIGS escape function. */ int in_esc_size, out_esc_size, esc_data_return_size; /* Set up the Toolkit callbacks. */ void exit_pushed(); DwtCallback exit_callback[] = {{ exit_pushed, NULL}, NULL }; void double_buffer_pushed(); DwtCallback double_buffer_callback[] = {{ double_buffer_pushed, NULL}, NULL }; void save_image_pushed(); DwtCallback save_image_callback[] = {{ save_image_pushed, NULL}, NULL }; void clear_image_pushed(); DwtCallback clear_image_callback[] = {{ clear_image_pushed, NULL}, NULL }; /*========================================================================== 'exit_pushed' DESCRIPTION: This routine is called when the menu bar 'exit' button is pushed. It terminates the application. ==========================================================================*/ void exit_pushed( widget ) Widget widget; { /* Close the PHIGS workstation, close PHIGS, and exit. */ pclosews( ws_id ); pclosephigs( ); exit(1); } /*========================================================================== 'Double-Buffer' DESCRIPTION: This routine is called when the menu bar 'Double-Buffer' button is pushed. It toggles PHIGS double buffering ON and OFF. ==========================================================================*/ void double_buffer_pushed( widget ) Widget widget; { static int double_buffer_mode = 0; /* Start with double buffering off */ /* Check the current value and change it. */ if ( double_buffer_mode == 0 ) { double_buffer_mode = 1; } else { double_buffer_mode = 0; } /* Set up the PHIGS escape function data structures. */ int_buffer[0] = ws_id; int_buffer[1] = double_buffer_mode; int_buffer[2] = 0; /* initialize from X window */ in_esc_size = sizeof( struct esc_data_struct ); in_esc_data.num_ints = 3; in_esc_data.num_floats = 0; in_esc_data.num_strings = 0; in_esc_data.ints = int_buffer; in_esc_data.floats = NULL; in_esc_data.string_sizes = NULL; in_esc_data.strings = NULL; out_esc_size = sizeof( struct esc_data_struct ); out_esc_data.num_ints = 0; out_esc_data.num_floats = 0; out_esc_data.num_strings = 0; out_esc_data.ints = NULL; out_esc_data.floats = NULL; out_esc_data.string_sizes = NULL; out_esc_data.strings = NULL; /* Call the PHIGS escape to change the double buffering mode. */ pescape( PPESC_DOUBLE_BUFFER, &in_esc_data, in_esc_size, &out_esc_data, &out_esc_size ); } /*========================================================================== 'Save-Image' DESCRIPTION: This routine is called when the menu bar 'Save-Image' button is pushed. It calls the function 'save_image' to save the the current screen image as the background image. ==========================================================================*/ void save_image_pushed( widget ) Widget widget; { /* Call the save image function - a flag of '1' means save. */ save_image( 1 ); } /*========================================================================== 'clear_image_pushed' DESCRIPTION: This routine is called when the menu bar 'clear_image' button is pushed. It calls the 'save_image' routine and tells it to clear the current background image. ==========================================================================*/ void clear_image_pushed( widget ) Widget widget; { /* Call the save image function - a flag of '0' means clear the background image. */ save_image( 0 ); } /*========================================================================== 'Save_image' DESCRIPTION: Depending on the value of the 'flag' parameter, this routine will either set the current background image to be the current screen image (1) or clear the current background image (0). ==========================================================================*/ int save_image( flag ) int flag; /* Flag, 1 means set, 0 means clear */ { XWindowAttributes attributes; Pixmap background; if ( flag ) { /* Set the background to be the current screen image */ /* Get window size and depth */ XGetWindowAttributes( display, phigs_x_window, &attributes ); /* Create pixmap. */ background = XCreatePixmap( display, phigs_x_window, attributes.width, attributes.height, attributes.depth ); /* Copy window to pixmap. */ XCopyArea( display, phigs_x_window, background, DefaultGC( display, DefaultScreen( display ) ), 0, 0, attributes.width, attributes.height, 0, 0 ); int_buffer[0] = ws_id; int_buffer[1] = background; } else { /* Clear the background. */ int_buffer[0] = ws_id; int_buffer[1] = 0; } /* Set up the escape. */ in_esc_size = sizeof( struct esc_data_struct ); in_esc_data.num_ints = 2; in_esc_data.num_floats = 0; in_esc_data.num_strings = 0; in_esc_data.ints = int_buffer; in_esc_data.floats = NULL; in_esc_data.string_sizes = NULL; in_esc_data.strings = NULL; out_esc_size = sizeof( struct esc_data_struct ); out_esc_data.num_ints = 0; out_esc_data.num_floats = 0; out_esc_data.num_strings = 0; out_esc_data.ints = NULL; out_esc_data.floats = NULL; out_esc_data.string_sizes = NULL; out_esc_data.strings = NULL; /* Call the PHIGS escape to set the background pixmap. */ pescape (PPESC_SET_BCKGRND_PIXMAP, &in_esc_data, in_esc_size, &out_esc_data, &out_esc_size); if ( flag ) { /* free the X pixmap */ XFreePixmap( display, background ); } } /*========================================================================== 'Button_down' DESCRIPTION: This routine is called whenever the mouse button is depressed. If mouse button 1 is depressed, it samples the current PHIGS locator(mouse) position, and resets the PHIGS locator to have a rubber band box echo. If mouse button 2 is depressed, it samples the PHIGS pick input device to determine if a box is being 'picked'. If so, it deletes and unposts the structure containing the box. ==========================================================================*/ XtEventHandler button_down(w, data, event) Widget w; /* the widget */ int data; XEvent *event; /* the X event */ { Pint depth = 1; /* depth of the pick path */ Ppick pick; /* pick data structure */ Ppickpathel pick_path[2]; /* pick path */ /* Mouse button 1 down means start a new box */ if ( event->xbutton.button == 1 ) { Ploc locator_sample; /* locator sample results */ Plimit pecho_area; /* locator echo area */ Plocrec locator_record; /* locator data record */ /* Sample the locator devices. */ psampleloc( ws_id, 1, &locator_sample ); /* Re-initialize the locator to use the rubber band box. */ psetlocmode( ws_id, 1, PREQUEST, PES_ECHO ); /* Initialize echo area. */ pecho_area.xmin = 0.0; pecho_area.xmax = display_size.device.x; pecho_area.ymin = 0.0; pecho_area.ymax = display_size.device.y; /* Initialize data record for pet 5. */ locator_record.locpet5_datarec.pfcf = PPF_POLYLINE; locator_record.locpet5_datarec.attr.ln.type = PINDIVIDUAL; locator_record.locpet5_datarec.attr.ln.width = PINDIVIDUAL; locator_record.locpet5_datarec.attr.ln.colour = PINDIVIDUAL; locator_record.locpet5_datarec.attr.ln.index = 1; locator_record.locpet5_datarec.attr.ln.bundl.type = current_line_type; locator_record.locpet5_datarec.attr.ln.bundl.width = 1.0; locator_record.locpet5_datarec.attr.ln.bundl.colour = 1; pinitloc( ws_id, 1, &locator_sample, 5 /* rubber band box pet */, &pecho_area, &locator_record ); psetlocmode( ws_id, 1, PSAMPLE, PES_ECHO ); /* Set a flag that says that PHIGS input is ongoing - we don't want a lot of output going on at the same time */ phigs_input_ongoing = 1; first_point.x = locator_sample.position.x; first_point.y = locator_sample.position.y; } else if ( event->xbutton.button == 2 ) { /* Mouse button 2 down means delete the box being picked. */ pick.pick_path.pick_path = pick_path; psamplepick( ws_id, 1 /* device */, depth, &pick); if (pick.status == PP_OK) { pdelstruct( pick.pick_path.pick_path[0].struct_id ); /* Unpost it, too */ punpoststruct( ws_id, pick.pick_path.pick_path[0].struct_id ); } } } /*========================================================================== 'button_up' DESCRIPTION: This routine is called whenever the mouse button is released. If it is mouse button 1, then the locator device is sampled and the a new box created with the first_point and second_point of the rectangle. ==========================================================================*/ XtEventHandler button_up(w, data, event) Widget w; /* the widget */ int data; XEvent *event; /* the X event */ { /* Only define an action if Mouse Button 1 is pressed */ if ( event->xbutton.button == 1 ) { Ploc locator_sample; /* the locator sample results */ Plimit pecho_area; /* the locator echo area */ Plocrec locator_record; /* the locator data record */ /* Sample the locator devices. */ psampleloc( ws_id, 1, &locator_sample ); /* Re-initialize the locator to use the default cursor. */ psetlocmode( ws_id, 1, PREQUEST, PES_ECHO ); /* Clear the flag that says that PHIGS input is ongoing. */ phigs_input_ongoing = 0; /* initialize echo area */ pecho_area.xmin = 0.0; pecho_area.xmax = display_size.device.x; pecho_area.ymin = 0.0; pecho_area.ymax = display_size.device.y; pinitloc( ws_id, 1, &locator_sample, 1 /* default cursor */, &pecho_area, &locator_record ); psetlocmode( ws_id, 1, PSAMPLE, PES_ECHO ); second_point.x = locator_sample.position.x; second_point.y = locator_sample.position.y; /* Create a new box. */ create_box( BOX_STRUCT + box_count, first_point, second_point ); ppoststruct (ws_id, BOX_STRUCT + box_count, 1.0); box_count++; } } /*========================================================================== 'main' DESCRIPTION: This is the MAIN routine. This routine sets up the DECwindows display and opens a PHIGS workstation. It calls various routines to complete initialization and set up. It then calls a routine to begin processing X and PHIGS input. ==========================================================================*/ main( argc, argv ) unsigned int argc; char **argv; { char *name, *classname; Pchar conid[30]; Widget top_level; /* the DECwindows widgets */ Widget main_widget; Widget phigs_widget; Widget menu_bar; /* the menu bar buttons */ Widget exit_button; Widget double_buffer_button; Widget save_image_button; Widget clear_image_button; Widget phigs_output_widget; Arg arg_list[8]; /* Initialize the DECwindows Toolkit. */ XtToolkitInitialize(); /* Open the DECwindows display - display name defined by DECW$DISPLAY(VMS) or DISPLAY(Ultrix). */ display = XtOpenDisplay( /* (XtAppContext)*/ NULL, /* application context */ NULL, /* display name */ "DEC PHIGS and X11 Example",/* application name */ "TestClass", /* class name */ NULL, /* urlist */ 0, /* urcount */ &argc, /* argcount */ &argv ); /* argvalue */ if ( !display ) /* open failed */ { printf("XtopenDisplay failed, check DISPLAY setting.\n"); exit(1); } /* Create an application shell widget. */ top_level = XtAppCreateShell( "DEC PHIGS and X11 Example",/* name */ "TestClass", /* class */ applicationShellWidgetClass,/* widget class */ display, /* display */ NULL, /* arglist */ 0 ); /* argcount */ /* Create a main window widget. */ main_widget = DwtMainWindow( top_level, /* parent */ "Main", /* name */ 0, 0, /* position */ 0, /* width */ 0 ); /* height */ XtManageChild( main_widget ); /* Create Menu bar. */ menu_bar = DwtMenuBar( main_widget, /* parent */ "MenuBar", /* name * NULL, /* callback */ NULL ); /* help callback */ XtManageChild( menu_bar ); /* Create an Exit pushbutton. */ exit_button = DwtPushButton( menu_bar, /* parent */ "", /* name */ 0, 0, /* default position */ DwtLatin1String ("Exit"), /* String */ exit_callback, /* the activation callback */ NULL); /* no help callback */ XtManageChild( exit_button ); /* Create a 'double-buffer' pushbutton. */ double_buffer_button = DwtPushButton( menu_bar, /* parent */ "", /* name */ 0, 0, /* default position */ DwtLatin1String ("Double-Buffer"), /* String */ double_buffer_callback,/* the activation callback */ NULL); /* no help callback */ XtManageChild( double_buffer_button ); /* Create a 'save-image' pushbutton. */ save_image_button = DwtPushButton( menu_bar, /* parent */ "", /* name */ 0, 0, /* default position */ DwtLatin1String ("Save-Image"), /* String */ save_image_callback,/* the activation callback */ NULL); /* no help callback */ XtManageChild( save_image_button ); /* Create a 'clear-image' pushbutton. */ clear_image_button = DwtPushButton( menu_bar, /* parent */ "", /* name */ 0, 0, /* default position */ DwtLatin1String ("Clear-Image"), /* String */ clear_image_callback,/* the activation callback */ NULL); /* no help callback */ XtManageChild( clear_image_button ); /* Create a dialog box for PHIGS. It MUST be of fixed size. */ XtSetArg( arg_list[0], DwtNx, 0 ); XtSetArg( arg_list[1], DwtNy, 0 ); XtSetArg( arg_list[2], DwtNwidth, 1000 ); XtSetArg( arg_list[3], DwtNheight, 800 ); XtSetArg( arg_list[4], DwtNresize, DwtResizeFixed ); XtSetArg( arg_list[5], DwtNunits, DwtPixelUnits); phigs_widget = DwtDialogBoxCreate( main_widget, /* parent */ "PHIGS", /* name */ arg_list, /* override argument list */ 6 ); /* number of arguments */ XtManageChild( phigs_widget ); /* Hang menu bar, PHIGS window, and scroll bars off main window. */ DwtMainSetAreas( main_widget, /* widget to set up */ menu_bar, /* menu bar widget */ phigs_widget, /* work window */ NULL, /* no command window */ NULL, NULL ); /* no Scrollbars */ /* Widgets must be realized before the call to popenws(). */ XtRealizeWidget( top_level ); /* Build the connection identifier. */ sprintf( conid, "%d", phigs_widget ); popenphigs( 0, 0 ); popenws( ws_id, conid, PHIGS$K_DECWINDOWS_WIDGET ); /* Get and save the PHIGS display size. */ pinqdisplayspacesize( PHIGS$K_DECWINDOWS_WIDGET, &error_indicator, &display_size ); /* Call pescape() to get widget_ID of the output widget. This must be after the call to popenws(). */ in_esc_size = sizeof( struct esc_data_struct ); in_esc_data.num_ints = 1; in_esc_data.num_floats = 0; in_esc_data.num_strings = 0; in_esc_data.ints = &ws_id; in_esc_data.floats = NULL; in_esc_data.string_sizes = NULL; in_esc_data.strings = NULL; out_esc_size = sizeof( struct esc_data_struct ); out_esc_data.num_ints = 2; out_esc_data.num_floats = 0; out_esc_data.num_strings = 0; out_esc_data.ints = int_buffer; out_esc_data.floats = NULL; out_esc_data.string_sizes = NULL; out_esc_data.strings = NULL; pescape( PPESC_INQ_WINDOW_IDS, &in_esc_data, in_esc_size, &out_esc_data, &out_esc_size ); /* 'display' is in int_buffer[0], but in this case, that's already known, so just get the window that PHIGS is using. */ phigs_x_window = (Window)int_buffer[1]; /* Get the identifer of the Window Widget being used by PHIGS. */ phigs_output_widget = XtWindowToWidget( display, phigs_x_window ); /* Add an event handler for button press and release on the Phigs Window Widget. */ XtAddEventHandler( phigs_output_widget, ButtonPressMask, FALSE, button_down, 0 ); XtAddEventHandler( phigs_output_widget, ButtonReleaseMask, FALSE, button_up, 0 ); /* Create the text strings. */ create_text_struct( ); ppoststruct ( ws_id, TEXT_STRUCT, 1.0); /* Make sure the picture is correct. */ predrawallstruct ( ws_id, PALWAYS); /* Save the picture as the background. */ save_image( 1 ); /* Delete the complicated picture and get rid of the structure. */ pdelstruct( TEXT_STRUCT ); predrawallstruct ( ws_id, PALWAYS ); /* Create a simple object to move. */ create_box( BOX_STRUCT, first_point, second_point ); ppoststruct (ws_id, BOX_STRUCT, 1.0); /* Set up PHIGS input. */ initialize_phigs_input(); /* Put pick input in SAMPLE mode. */ psetpickmode( ws_id, 1, PSAMPLE, PES_ECHO ); /* Locator to enter new boxes */ psetlocmode( ws_id, 1, PSAMPLE, PES_ECHO ); /* Choice to enter line type */ psetchoicemode( ws_id, 1, PEVENT, PES_ECHO ); /* Choice to enter interior style */ psetchoicemode( ws_id, 7, PEVENT, PES_ECHO ); /* Valuator to enter line width */ psetvalmode( ws_id, 1, PEVENT, PES_ECHO ); /* Process X and PHIGS input events. */ process_input(); /* Never will get here. */ } /*========================================================================== 'Initialize_phigs_input' DESCRIPTION: This routine initializes the PHIGS input devices. It sets up a choice device for the current interior style, a choice device for the current line type, a valuator for the current line width, and the pick filters. ==========================================================================*/ int initialize_phigs_input() { Pvalrec valuator_record; /* valuator data record */ Pintlst excl_set; /* pick filter structures */ Pint excl_ints[10]; Pintlst incl_set; Plimit echo_area; /* input echo area */ Pchoicerec choice_record; /* choice data record */ static char *line_type_strings[] = { /* list of line types for choices */ "SOLID", "DASH", "DOT", "DOT-DASH", "DASH 2 DOT" }; static char *interior_style_strings[] = { /* list of interior style choice*/ "HOLLOW", "SOLID", "PATTERN", "HATCH" }; /* Display picture with pickable objects. */ incl_set.number = 1; incl_set.integers = pick_ints; excl_set.number = 0; excl_set.integers = excl_ints; psetpickfilter (ws_id, 1 /* device */, &incl_set, &excl_set); /* Set up the choice echo area. */ echo_area.xmin = 0.8 * display_size.device.x; echo_area.xmax = 1.0 * display_size.device.x; echo_area.ymin = 0.7 * display_size.device.y; echo_area.ymax = 1.0 * display_size.device.y; /* Set up the choice data record. */ choice_record.choicepet1_datarec.number = 5; choice_record.choicepet1_datarec.strings = line_type_strings; choice_record.choicepet1_datarec.title_string = "Line Types"; /* Initialize the PHIGS choice device. */ pinitchoice( ws_id, 1 /* device */, PCH_OK, 1 /* initial choice */, 1 /* prompt and echo type */, &echo_area, &choice_record ); /* Set up the choice echo area. */ echo_area.xmin = 0.8 * display_size.device.x; echo_area.xmax = 1.0 * display_size.device.x; echo_area.ymin = 0.35 * display_size.device.y; echo_area.ymax = 0.65 * display_size.device.y; /* Set up the choice data record. */ choice_record.choicepet1_datarec.number = 4; choice_record.choicepet1_datarec.strings = interior_style_strings; choice_record.choicepet1_datarec.title_string = "Interior style"; /* Initialize the PHIGS choice device. */ pinitchoice( ws_id, 7 /* device */, PCH_OK, 1 /* initial choice */, 1 /* prompt and echo type */, &echo_area, &choice_record ); /* Set up the valuator echo area. */ echo_area.xmin = 0.8 * display_size.device.x; echo_area.xmax = 1.0 * display_size.device.x; echo_area.ymin = 0.0 * display_size.device.y; echo_area.ymax = 0.3 * display_size.device.y; /* Initialize the data record. */ valuator_record.valpet1_datarec.low = 1.0; /* minimum of range. */ valuator_record.valpet1_datarec.high = 10.0; /* maximum of range. */ valuator_record.valpet1_datarec.title_string = "Line Width"; /* Initialize the PHIGS valuator device. */ pinitval( ws_id, 1 /* device */, 2.0 /* initial value */, 1 /* prompt and echo type */, &echo_area, &valuator_record ); } /*========================================================================== 'Process_Input' DESCRIPTION: This routine processes all X and PHIGS input and also calls functions to rotate the boxes. It will loop forever doing the following: o Process X events o Process PHIGS events o Increment rotation of each box ==========================================================================*/ int process_input() { int i; XEvent event; /* an X event */ while ( 1 ) /* forever */ { if ( !phigs_input_ongoing ) { /* Redraw all the PHIGS structures. */ predrawallstruct ( ws_id, PALWAYS ); /* Sync the X display - otherwise, the X output buffer is flooded with commands and input seems unresponsive. */ XSync( display, 0 ); } /* Process all the X events - do this before PHIGS events because X events dispatched to PHIGS internals cause PHIGS events to be generated. */ while( XPending( display ) ) { XNextEvent( display, &event ); XtDispatchEvent( &event ); } /* Check the PHIGS input event queue and process. */ process_phigs_input(); /* If the rubber band line echo is not ongoing, rotate all the boxes a little. */ if ( !phigs_input_ongoing ) { /* rotate all the boxes */ Pstructpost structures[MAX_STRUCT]; Pstructpostlst structures_posted; Pint actual_size; structures_posted.number = MAX_STRUCT; structures_posted.postings = structures; /* Ask PHIGS for the set of all posted structures. Each structure contains one box. */ pinqpostedstruct( ws_id, MAX_STRUCT, 0, &error_indicator, &structures_posted, &actual_size ); for ( i = 0; i < actual_size; i++ ) { /* rotate the box */ rotate_box( structures[i].id ); } /* for */ } /* if */ } /* while */ } /*========================================================================== 'Process_Phigs_input' DESCRIPTION: This routine processes all the PHIGS events on the PHIGS event queue. ==========================================================================*/ int process_phigs_input() { Pevent input_event; /* a PHIGS event */ /* Initialize it to something other than PI_NONE */ input_event.class = PI_LOCATOR; while ( input_event.class != PI_NONE ) { /* Check for PHIGS events - must use time out value of 0.0 or else we might wait the entire time. */ pawaitevent( 0.0 /* timeout */, &input_event ); /* Look at the type of event returned. */ switch ( input_event.class ) { case PI_NONE: /* no event occurred */ break; case PI_LOCATOR: break; case PI_VALUATOR: if ( input_event.dev == 1 ) { /* Change the current line width - get the value from the PHIGS event. */ pgetval( ¤t_line_width ); } break; case PI_STROKE: break; case PI_CHOICE: if ( input_event.dev == 1 ) { /* Line type choice device */ Pchoice choice_event; /* a choice event */ /* Get the PHIGS choice event. */ pgetchoice( &choice_event ); if ( choice_event.status == PCH_OK ) { /* process the choice event */ switch( choice_event.choice ) { case 1: current_line_type = PLN_SOLID; break; case 2: current_line_type = PLN_DASH; break; case 3: current_line_type = PLN_DOT; break; case 4: current_line_type = PLN_DOTDASH; break; case 5: current_line_type = PLN_DASH_2_DOT; break; } } } else if ( input_event.dev == 7 ) { /* Interior style choice device */ Pchoice choice_event; /* the choice event */ /* get the PHIGS choice event */ pgetchoice( &choice_event ); if ( choice_event.status == PCH_OK ) { /* Process the choice event. */ switch( choice_event.choice ) { case 1: current_int_style = PHOLLOW; break; case 2: current_int_style = PSOLID; break; case 3: current_int_style = PPATTERN; break; case 4: current_int_style = PHATCH; break; } } } break; case PI_PICK: break; case PI_STRING: break; } } } /*========================================================================== 'Rotate-Box' DESCRIPTION: This routine rotates the box specified by the structure passed to it. It will inquire from PHIGS the structure element that is used to store the current box state (application data). ==========================================================================*/ int rotate_box( struct_id ) Pint struct_id; /* the box to rotate */ { Pmatrix3 matrix; /* a PHIGS matrix */ Pvector3 shift; Pvector3 scale; int error; /* just an error value */ float star_angle, old_angle; /* locals for the angle of rotation */ int j; /* counter */ box_status_struct box_status; /* box status information */ Pint actual_size; /* actual size of the element */ Peldata element_data; /* PHIGS element data structure */ Pdata data; /* PHIGS application data structure */ /* Initialize the vectors. */ shift.x = 0.0; shift.y = 0.0; shift.z = 0.0; scale.x = 1.0; scale.y = 1.0; scale.z = 1.0; /* Open the PHIGS structure for editing. */ popenstruct( struct_id ); psetelemptr( 0 ); /* Go to the status point in the structure. */ psetelemptrlabel( STATUS_LABEL ); poffsetelemptr( 1 ); /* Ask PHIGS for the current element content of the element that is used for storing the box status. This is an application data element. */ pinqcurelemcontent( sizeof( box_status_struct ), &error_indicator, &box_status, &actual_size, &element_data ); /* Editing is replacing elements */ pseteditmode (PEDIT_REPLACE); /* Calculate new box size and position. */ old_angle = box_status.angle; box_status.angle = 0.0174532 * (float)box_status.counter; shift.x = 2.0 * (sin(box_status.angle) - sin(old_angle)); shift.y = 2.0 * (cos(box_status.angle) - cos(old_angle)); scale.z = scale.y = scale.x = scale.x - box_status.direction * FACTOR; /* Rotate, scale, and translate the box. */ pbuildtran3( &box_status.center_point, &shift, box_status.angle, box_status.angle, box_status.angle, &scale, &error, matrix ); psetelemptr( 0 ); /* Go to where the matrix is stored. */ psetelemptrlabel( BOX_LABEL ); poffsetelemptr( 1 ); /* Change the box matrix. */ psetglobaltran3( matrix ); /* Rotate the star in the other direction, twice as fast. */ star_angle = -box_status.angle * 2.0; pbuildtran3( &box_status.center_point, &shift, star_angle, star_angle, star_angle, &scale, &error, matrix); /* Change the star matrix. */ psetelemptrlabel( STAR_LABEL ); poffsetelemptr( 1 ); psetglobaltran3( matrix ); box_status.counter += STEP; if ( box_status.counter >= 360 ) { /* It's gone all the way around, now go back the other way. */ box_status.counter = 1; box_status.direction = -box_status.direction; } psetelemptr( 0 ); /* Update the current box status as application data in the structure. */ psetelemptrlabel( STATUS_LABEL ); poffsetelemptr( 1 ); /* Update the state of the box in the structure store. */ data.size = sizeof( box_status_struct ); /* application data size */ data.data = ( char *) &box_status; /* application data */ papplicationdata( &data ); /* Close the PHIGS structure. */ pclosestruct(); } /*========================================================================== 'Create_box' DESCRIPTION: This routine creates a PHIGS structure containing a box defined by two points. ==========================================================================*/ int create_box ( struct_id, p0, p1 ) int struct_id; /* structure ID to create */ Ppoint3 p0; /* first corner point */ Ppoint3 p1; /* second corner point */ { /* Arrays to hold the points */ Ppoint3 bottom[5]; Ppoint3 top[5]; Ppoint3 box_edge1[2], box_edge2[2], box_edge3[2], box_edge4[2]; Ppoint3 star_edge1[2], star_edge2[2], star_edge3[2]; Ppoint3 point; Pdata data; /* PHIGS application data */ Pmatrix3 matrix; Pvector3 shift; Pvector3 scale; int error; Pint bounds[1]; /* list of fill area set bounds */ box_status_struct box_status; /* initial box status */ Pintlst names; /* name set list */ bounds[0] = 5; /* 5 points in fill area set */ /* Initialize the vectors. */ shift.x = 0.0; shift.y = 0.0; shift.z = 0.0; scale.x = 1.0; scale.y = 1.0; scale.z = 1.0; /* Initialize all the point arrays. */ point.x = ( p0.x + p1.x ) / 2.0; point.y = ( p0.y + p1.y ) / 2.0; point.z = ( p0.z + p1.z ) / 2.0; bottom[0].x = p0.x; bottom[0].y = p1.y; bottom[0].z = p1.z; bottom[1].x = p0.x; bottom[1].y = p0.y; bottom[1].z = p1.z; bottom[2].x = p1.x; bottom[2].y = p0.y; bottom[2].z = p1.z; bottom[3].x = p1.x; bottom[3].y = p1.y; bottom[3].z = p1.z; bottom[4].x = p0.x; bottom[4].y = p1.y; bottom[4].z = p1.z; top[0].x = p0.x; top[0].y = p1.y; top[0].z = p0.z; top[1].x = p0.x; top[1].y = p0.y; top[1].z = p0.z; top[2].x = p1.x; top[2].y = p0.y; top[2].z = p0.z; top[3].x = p1.x; top[3].y = p1.y; top[3].z = p0.z; top[4].x = p0.x; top[4].y = p1.y; top[4].z = p0.z; box_edge1[0].x = p0.x; box_edge1[0].y = p1.y; box_edge1[0].z = p1.z; box_edge1[1].x = p0.x; box_edge1[1].y = p1.y; box_edge1[1].z = p0.z; box_edge2[0].x = p0.x; box_edge2[0].y = p0.y; box_edge2[0].z = p1.z; box_edge2[1].x = p0.x; box_edge2[1].y = p0.y; box_edge2[1].z = p0.z; box_edge3[0].x = p1.x; box_edge3[0].y = p0.y; box_edge3[0].z = p1.z; box_edge3[1].x = p1.x; box_edge3[1].y = p0.y; box_edge3[1].z = p0.z; box_edge4[0].x = p1.x; box_edge4[0].y = p1.y; box_edge4[0].z = p1.z; box_edge4[1].x = p1.x; box_edge4[1].y = p1.y; box_edge4[1].z = p0.z; star_edge1[0].x = ( p0.x + p1.x ) / 2.0; star_edge1[0].y = ( p0.y + p1.y ) / 2.0; star_edge1[0].z = p0.z - DELT; star_edge1[1].x = ( p0.x + p1.x ) / 2.0; star_edge1[1].y = ( p0.y + p1.y ) / 2.0; star_edge1[1].z = p1.z + DELT; star_edge2[0].x = p0.x - DELT; star_edge2[0].y = ( p0.y + p1.y ) / 2.0; star_edge2[0].z = ( p0.z + p1.z ) / 2.0; star_edge2[1].x = p1.x + DELT; star_edge2[1].y = ( p0.y + p1.y ) / 2.0; star_edge2[1].z = ( p0.z + p1.z ) / 2.0; star_edge3[0].x = ( p0.x + p1.x ) / 2.0; star_edge3[0].y = p0.y - DELT; star_edge3[0].z = ( p0.z + p1.z ) / 2.0; star_edge3[1].x = ( p0.x + p1.x ) / 2.0;; star_edge3[1].y = p1.y + DELT; star_edge3[1].z = ( p0.z + p1.z ) / 2.0; /* Open (create) the PHIGS structure. */ popenstruct( struct_id ); pseteditmode( PEDIT_INSERT); /* Add this structure to the pick name set. */ names.number = 1; names.integers = pick_ints; pick_ints[0] = PICK_SET; paddnameset (&names); /* Use view index 0. */ psetviewind( 0 ); /* Build the default matrix. */ pbuildtran3( &point, &shift, 0.0, 0.0, 0.0, &scale, &error, matrix); /* Define the PHIGS attributes. */ psetintstyle( current_int_style ); psetintcolourind( current_color ); psetedgecolourind( current_color ); psetedgewidth( current_line_width ); psetedgetype( current_line_type ); psetlinecolourind( current_color ); psetlinewidth( current_line_width ); psetlinetype( current_line_type ); /* Save the center point in the structure. */ plabel( STATUS_LABEL ); /* Save the starting state in the structure. */ box_status.center_point = point; box_status.angle = 1.0; box_status.counter = 1; box_status.direction = 1; data.size = sizeof( box_status_struct ); /* application data size */ data.data = (char *)&box_status; /* application data */ papplicationdata( &data ); plabel( BOX_LABEL ); psetglobaltran3( matrix ); /* Draw the box and star. */ pfillareaset3( 1, bounds, bottom ); pfillareaset3( 1, bounds, top ); ppolyline3 ( 2, box_edge1 ); ppolyline3 ( 2, box_edge2 ); ppolyline3 ( 2, box_edge3 ); ppolyline3 ( 2, box_edge4 ); psetlinecolourind( current_color + 1 ); plabel( STAR_LABEL ); psetglobaltran3( matrix ); ppolyline3( 2, star_edge1 ); ppolyline3( 2, star_edge2 ); ppolyline3( 2, star_edge3 ); pclosestruct(); /* Increment the current color so the next one will be different. */ current_color++; } /*========================================================================== 'Create_text_struct' DESCRIPTION: This routine creates a simple PHIGS structure with some text in it. This will be used as the starting background image. This structure could contain anything. ==========================================================================*/ int create_text_struct( ) { Ppoint text_pt; /* text position */ int i; popenstruct( TEXT_STRUCT ); psetcharheight( 0.08 ); psettextfont( -16 ); /* nice stroke font */ for(i = 1; i <= 9; i++) /* repeat 10 times */ { text_pt.x = 0.1; text_pt.y = i*0.1; ptext( &text_pt, "DEC PHIGS and X11 "); } pclosestruct( ); }