/* plineset.c 1.1 */
/*
    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"

/* Cube coordinates. */
static PEXCoord	top[] = {{.3,.7,.3}, {.3,.7,.7}, {.7,.7,.7},
			 {.7,.7,.3}, {.3,.7,.3}};
static PEXCoord	bottom[] = {{.3,.3,.3}, {.3,.3,.7}, {.7,.3,.7},
			    {.7,.3,.3}, {.3,.3,.3}};
static PEXCoord	front[] = {{.3,.7,.7}, {.3,.3,.7}, {.7,.3,.7},
			   {.7,.7,.7}, {.3,.7,.7}};
static PEXCoord	back[] = {{.3,.7,.3}, {.3,.3,.3}, {.7,.3,.3},
			  {.7,.7,.3}, {.3,.7,.3}};

/* Structure ID */
static PEXStructure	struct_id;

static void
create_structure( dpy )
    Display	*dpy;
{
    PEXColor		color;
    PEXListOfVertex	cube[4];
    PEXCoord		origin;
    PEXStructure	axes;
    
    /* Create the structure. */
    struct_id = PEXCreateStructure( dpy );
    
    /* Set the view index to view 1. */
    PEXSetViewIndex( dpy, struct_id, PEXOCStore, 1 );
    
    /* Set the line color, which applies only to the cube because */
    /* the axes have colors specified in their vertex data. */
    SET_COLOR( 1, 1, 1, color ); /* white */
    PEXSetLineColor( dpy, struct_id, PEXOCStore,
		     PEXColorTypeRGB, &color );
    
    /* Set the other line attributes. */
    PEXSetLineWidth( dpy, struct_id, PEXOCStore, 1.0 );
    PEXSetLineType( dpy, struct_id, PEXOCStore, PEXLineTypeSolid );
    PEXSetPolylineInterpMethod( dpy, struct_id, PEXOCStore,
			        PEXPolylineInterpNone );
    
    /* Build the axes. */
    origin.x = origin.y = origin.z = 0;
    axes = ora_build_axes_struct( dpy, &origin, 0.2 );
    PEXExecuteStructure( dpy, struct_id, PEXOCStore, axes );
			   
    /* Build and store the polyline set for the cube. */
    cube[0].count = 5; cube[0].vertices.no_data = top;
    cube[1].count = 5; cube[1].vertices.no_data = bottom;
    cube[2].count = 5; cube[2].vertices.no_data = front;
    cube[3].count = 5; cube[3].vertices.no_data = back;
    PEXPolylineSetWithData( dpy, struct_id, PEXOCStore, PEXGANone,
			    PEXColorTypeRGB, 4, cube );
}

static void
redraw( dpy, window, renderer )
    Display	*dpy;
    Window	window;
    PEXRenderer	renderer;
{
    XClearWindow( dpy, window );
    PEXRenderNetwork( dpy, window, renderer, struct_id );
    XFlush( dpy );
}

#define WIN_GEOM	"500x500+50+50"

static void	set_view(); /* A utility defined below. */

main( argc, argv )
    int		argc;
    char	*argv[];
{
    Display			*dpy;
    Window			window;
    XEvent			event;
    XVisualInfo			vis_info;
    XColor			bkgd_color;
    XStandardColormap		cmap_info;
    PEXColorApproxEntry		capx_info;
    PEXRenderer			renderer;
    PEXRendererAttributes	rattrs;
    PEXExtensionInfo		*pexinfo;
    int				done = 0;
    char			*dpy_name;
    
    /* 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_structure( dpy );
    } else {
	fprintf( stderr, "Structures not supported.\n" );
	exit(1);
    }
    
    set_view( dpy, rattrs.view_table );
    
    /* Read and respond to X events. */
    XSelectInput( dpy, window, ExposureMask | ButtonPressMask );
    while ( !done ) {
	XNextEvent( dpy, &event );
	switch ( event.type ) {
	case Expose:
	    /* Flush remaining Expose events, then redraw. */
	    while ( XCheckTypedWindowEvent( dpy, window,
					    Expose, &event ) )
		; /* empty statement */
	    redraw( dpy, window, renderer );
	    break;
	case ButtonPress:
	    done = 1;
	    break;
	}
    }

    XCloseDisplay( dpy );
    return 0;
}

static void
set_view( dpy, view_table )
    Display		*dpy;
    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 = {2, 0.5, 0.5};
    static PEXVector	view_up_vec = {0,1,0};

    /* Compute the view orientation transform. */
    PEXViewOrientationMatrix( &view_ref_pt, &view_plane_normal,
			      &view_up_vec, view.orientation );
    
    /* The view mapping parameters. */
    prp.x = 0; prp.y = 0; prp.z = 20;
    window[0].x = -0.5; window[1].x = 0.5;
    window[0].y = -0.5; window[1].y = 0.5;
    front_plane = 100; view_plane = 0; back_plane = -100;
    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. */
    PEXViewMappingMatrix( window, &viewport, False, &prp,
			  view_plane, back_plane, front_plane,
			  view.mapping );
    
    /* The view clipping parameters. */
    view.clip_flags = PEXClippingAll;
    view.clip_limits = viewport;
    
    /* Set view 1. */
    PEXSetTableEntries( dpy, view_table, 1, 1, PEXLUTView,
		       (PEXPointer) &view );
}
