/* mclip.c 1.3 */ /* Copyright 1992, 1993 O'Reilly and Associates, Inc. Permission to use, copy, and modify this program is hereby granted, as long as this copyright notice appears in each copy of the program source code. */ #include "book_utils.h" /* Miscellaneous constants. */ #define ROTATION_XFORM 1 #define LOCAL_MCLIP_VOLUME 2 /* Globals. */ static PEXStructure model, sphere; static PEXHalfSpace half_space[2]; static Display *dpy; static Window window; static PEXRenderer renderer; /* Utility functions defined below. */ static void handle_input(), set_view(); void create_model() { PEXListOfCoord sphere_points; PEXCoord axes_loc; PEXVector center; PEXMatrix xform; PEXStructure axes; /* Create the axes structure. */ axes_loc.x = axes_loc.y = axes_loc.z = 0; axes = ora_build_axes_struct( dpy, &axes_loc, 0.15 ); /* Create the sphere structure. */ sphere = PEXCreateStructure( dpy ); /* Store a transform element that we can change later to rotate * the sphere. */ PEXRotate( PEXXAxis, 0.0, xform ); PEXLabel( dpy, sphere, PEXOCStore, ROTATION_XFORM ); PEXSetLocalTransform( dpy, sphere, PEXOCStore, PEXReplace, xform ); /* Place the modeling coordinate axes at center of sphere. */ PEXExecuteStructure( dpy, sphere, PEXOCStore, axes ); /* Set the local model-clipping volume. One half-space. */ half_space[0].point.x = 0.15; half_space[0].point.y = 0; half_space[0].point.z = 0; half_space[0].vector.x = -1; half_space[0].vector.y = 0; half_space[0].vector.z = 0; PEXLabel( dpy, sphere, PEXOCStore, LOCAL_MCLIP_VOLUME ); PEXSetModelClipVolume( dpy, sphere, PEXOCStore, PEXModelClipIntersection, 1, &half_space[0] ); /* Turn model-clipping on. */ PEXSetModelClipFlag( dpy, sphere, PEXOCStore, PEXClip ); /* Create the sphere. */ ora_build_sphere( 0.25, &sphere_points ); PEXPolyline( dpy, sphere, PEXOCStore, sphere_points.count, sphere_points.points ); /* Create the top-level structure. */ model = PEXCreateStructure( dpy ); PEXSetViewIndex( dpy, model, PEXOCStore, 1 ); PEXExecuteStructure( dpy, model, PEXOCStore, axes ); /* Set the global model-clipping volume. One half-space. */ half_space[1].point.x = 0; half_space[1].point.y = 0.6; half_space[1].point.z = 0; half_space[1].vector.x = 0; half_space[1].vector.y = -1; half_space[1].vector.z = 0; PEXSetModelClipFlag( dpy, model, PEXOCStore, PEXClip ); PEXSetModelClipVolume( dpy, model, PEXOCStore, PEXModelClipReplace, 1, &half_space[1] ); /* Position the sphere and execute it. */ center.x = center.y = center.z = 0.5; PEXTranslate( ¢er, xform ); PEXSetLocalTransform( dpy, model, PEXOCStore, PEXReplace, xform ); PEXExecuteStructure( dpy, model, PEXOCStore, sphere ); } static void redraw() { XClearWindow( dpy, window ); PEXRenderNetwork( dpy, window, renderer, model ); XFlush( dpy ); } #define ANGLE_SCALE (M_PI/200) #define CLIP_SCALE (0.01) static void handle_input() { XEvent event; int lastx, lasty, done = 0; double x_ang = 0, y_ang = 0; PEXMatrix xxform, yxform, transform; /* Set the edit mode for the sphere structure, which we edit. */ PEXSetEditingMode( dpy, sphere, PEXStructureReplace ); /* Read and respond to X events. */ XSelectInput( dpy, window, ButtonPressMask | Button1MotionMask | Button2MotionMask | ExposureMask ); while ( !done ) { XNextEvent( dpy, &event ); switch ( event.type ) { case ButtonPress: switch ( event.xbutton.button ) { case Button1: case Button2: /* Initialize. */ lastx = event.xbutton.x; lasty = event.xbutton.y; break; default: done = 1; break; } break; case MotionNotify: PEXSetElementPtr( dpy, sphere, PEXBeginning, 0 ); if ( event.xmotion.state & Button1Mask ) { /* Increment the running rotation angles. */ x_ang += ANGLE_SCALE * (event.xmotion.y - lasty); y_ang += ANGLE_SCALE * (event.xmotion.x - lastx); /* Build the new rotation transform. */ PEXRotate( PEXXAxis, x_ang, xxform ); PEXRotate( PEXYAxis, y_ang, yxform ); PEXMatrixMult( xxform, yxform, transform ); /* Replace the rotation transform. */ PEXSetElementPtrAtLabel( dpy, sphere, ROTATION_XFORM, 1 ); PEXSetLocalTransform( dpy, sphere, PEXOCStore, PEXReplace, transform ); } else if ( event.xmotion.state & Button2Mask ) { /* Replace the model-clipping volume. */ PEXSetElementPtrAtLabel( dpy, sphere, LOCAL_MCLIP_VOLUME, 1 ); half_space[0].point.x += CLIP_SCALE * (event.xmotion.x - lastx); PEXSetModelClipVolume( dpy, sphere, PEXOCStore, PEXModelClipIntersection, 1, &half_space[0] ); } /* Update the display. */ redraw(); lastx = event.xmotion.x; lasty = event.xmotion.y; break; case Expose: /* Flush remaining Expose events, then redraw. */ while ( XCheckTypedWindowEvent( dpy, window, Expose, &event ) ) ; /* empty statement */ redraw(); break; } } } #define WIN_GEOM "500x500+50+50" main( argc, argv ) int argc; char *argv[]; { XEvent event; XVisualInfo vis_info; XColor bkgd_color; XStandardColormap cmap_info; PEXColorApproxEntry capx_info; PEXRendererAttributes rattrs; PEXExtensionInfo *pexinfo; int done = 0; /* Open a display and initialize PEX. */ dpy = ora_init_pex( argv, &pexinfo ); if ( !dpy ) exit(1); /* Determine the best visual to use. */ ora_find_best_visual( dpy, &vis_info ); /* Get a standard colormap for the visual. */ if ( !ora_get_standard_colormap( dpy, &vis_info, &cmap_info ) ) { fprintf ( stderr, "Cannot find a standard colormap\n" ); exit(1); } ora_set_stdcmap_approx( &vis_info, &cmap_info, &capx_info ); /* Create the window, giving it a gray background. */ bkgd_color.red = bkgd_color.green = bkgd_color.blue = 0x5555; bkgd_color.flags = DoRed | DoGreen | DoBlue; window = ora_create_window( dpy, &vis_info, &cmap_info, WIN_GEOM, &bkgd_color ); if ( STRUCTURE_SPT( pexinfo ) ) { renderer = ora_setup_renderer( dpy, window, &capx_info, &rattrs ); create_model( dpy ); } else { fprintf( stderr, "Structures not supported.\n" ); exit(1); } set_view( rattrs.view_table ); handle_input(); XCloseDisplay( dpy ); return 0; } static void set_view( view_table ) PEXLookupTable view_table; { PEXViewEntry view; PEXCoord2D window[2]; double view_plane, front_plane, back_plane; PEXCoord prp; PEXNPCSubVolume viewport; /* The view orientation parameters. */ static PEXCoord view_ref_pt = {0.5, 0.5, 0.5}; static PEXVector view_plane_normal = {0, 0.2, 1}; static PEXVector view_up_vec = {0,1,0}; /* Compute the view orientation transform. */ (void)PEXViewOrientationMatrix( &view_ref_pt, &view_plane_normal, &view_up_vec, view.orientation ); /* The view mapping parameters. */ prp.x = 0; prp.y = 0; prp.z = 5; window[0].x = -0.6; window[1].x = 0.6; window[0].y = -0.6; window[1].y = 0.6; front_plane = 0.6; view_plane = 0; back_plane = -0.6; viewport.min.x = 0; viewport.max.x = 1; viewport.min.y = 0; viewport.max.y = 1; viewport.min.z = 0; viewport.max.z = 1; /* Compute the view mapping transform. */ (void)PEXViewMappingMatrix( window, &viewport, True, &prp, view_plane, back_plane, front_plane, view.mapping ); /* The view clipping parameters. */ view.clip_flags = 0; /* no view clipping */ view.clip_limits = viewport; /* Set view 1. */ PEXSetTableEntries( dpy, view_table, 1, 1, PEXLUTView, (PEXPointer) &view ); }