kelvin@cs.utexas.edu (Kelvin Thompson) (07/27/88)
This is the second of two shar files that contain source for 'boxview', a 3D object viewer. The program displays a faceted object (read from a data file) and lets the user rotate it and alter the viewing geometry used to project it. 'Boxview' is different from other viewers because it uses a unique, intuitive user interface that provides excellent feedback to the user. (I consider the standard set of Iris demos to have *awful* feedback.) 'Boxview' will run only on an Iris, because it makes extensive use of the Iris' architecture. I've tested it on a 3000-series Iris running a fairly old OS, and fairly new 4D. The program may not work well on Irises with 8 or fewer bitplanes. I decided to post the program after I noticed that Siggraph next week will have a paper entitled (roughly) "A Study in 3D Rotation with a 2D Pointing Device," which is exactly what I think 'boxview' is good at. I thought I might grab myself some credit by letting people compare my rotater with the one(s?) from the published paper. Instructions for unpacking and running: (1) Save this article and the accompanying one into two Iris files. (2) Trim the text before and after the "--- cut here ---" lines in each of the two files. (3) Unpack the files by typing "sh file1" and "sh file2". (4) If you have a 4D system, edit 'Makefile' and remove the "-Zf" from the 'CFLAGS' definition. (5) Run "make" without parameters. (6) Read the documentation in README and 'boxview.1l' (the latter by typing "nroff -man boxview.1l".) (7) Run the program by typing either "boxview" or "boxview sticks.geom". (8) Exit 'boxview' by hitting the escape key. Have fun. I've got gobs more '.geom' files -- most stolen from DEC's OFF release a year ago. Send questions or comments to me at: kelvin@cs.utexas.edu {backbone}!cs.utexas.edu!kelvin If you want to see a live demo at Siggraph, you can contact me (Kelvin Thompson) at the Nth Graphics booth, or at the Radisson Hotel. I will have a tar-tape (cartridge), but not an Iris (but maybe we can find one). #------------------- cut this line and above ---------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by cs.utexas.edu!kelvin on Tue Jul 26 21:19:44 CDT 1988 # Contents: boxobj.c boxview.c manip.c rotate.c view.c xh.c echo x - boxobj.c sed 's/^@//' > "boxobj.c" <<'@//E*O*F boxobj.c//' /* FILENAME: boxobj.c AUTHOR: Kelvin Thompson, 10/87 DESCRIPTION: Routines for handling the object(s) displayed in the viewbox. You can modify this file to have 'boxview' display objects of your own creation. Just write a new version of 'init_obj' (which 'boxview' calls shortly after startup) and 'draw_obj' (which 'boxview' calls every time it wants to draw the object). See the function code itself for more information. COPYRIGHT: This software is Copyright 1986,1987,1988 by Kelvin Thompson and carries GNU-like restrictions: Permission is granted to use, copy, modify, and redistribute this software for non- commercial purposes, as long as copies and derivative works carry these same restrictions. */ #include <stdio.h> #include <math.h> #include <gl.h> #include <device.h> #include "ktypes.h" #include "idraw.h" /* programs in this file */ extern void init_obj(); extern void draw_obj(); extern void gen_sphere(); extern int gen_geomobj(); /* globals */ static Object theobj; /* ************************************ * * * init_obj * * * ************************************ DESCRIPTION: Initialize the object to be shown. This routine is called once, shortly after 'boxview' starts up. Graphics operations have been initialized, but the user has not yet seen anything on the screen. This routine should do its initializations based only on input provided by the entry parameters 'argc' and 'argv'. This routine should not ask the user for information. Programmers should use calls of the form cm_mapcolor( seg1, s1_OBJSTART+idx, R, G, B ); to define color map entries. 'seg1' and 's1_OBJSTART' are globals; idx varies for different index values; R,G,B are the color entries in the table. Corresponding references to the color map should take the form color( s1_OBJSTART+idx ); ENTRY: argc,argv -- Standard Unix input. */ void init_obj ( argc, argv ) int argc; char *argv[]; { FILE *geomfile; /* init */ theobj = genobj(); if ( argc == 2 ) { makeobj( theobj ); if ( ! gen_geomobj(argv[1]) ) gen_sphere(); closeobj(); } else { makeobj( theobj ); gen_sphere(); closeobj(); } } /* ************************************ * * * draw_obj * * * ************************************ DESCRIPTION: Draw the object. This routine is called every time 'boxview' wants to redraw the object it is showing. It is called every refresh time (up to 60 times a second) even if the user performs no action, so moving objects can be displayed in this routine. The drawn object should fit inside the cube from (-1,-1,-1) to (1,1,1). Only drawing and model-transforming calls should be made inside this routine (i.e. no viewing or windowing calls). */ void draw_obj ( ) { pushmatrix(); callobj( theobj ); popmatrix(); } /* ************************************ * * * gen_sphere * * * ************************************ DESCRIPTION: Generate a colorful sphere-like object. This is intended to be a cheap default object, in case the real object can't be obtained. */ void gen_sphere ( ) { /* three colors in sphere */ cm_mapcolor( seg1, s1_OBJSTART+0, 255, 100, 100 ); cm_mapcolor( seg1, s1_OBJSTART+1, 100, 255, 100 ); cm_mapcolor( seg1, s1_OBJSTART+2, 100, 100, 255 ); color( s1_OBJSTART+0 ); circ( 0.0, 0.0, 0.5 ); rotate( 90*10, 'x' ); color( s1_OBJSTART+1 ); circ( 0.0, 0.0, 0.5 ); rotate( 90*10, 'y' ); color( s1_OBJSTART+2 ); circ( 0.0, 0.0, 0.5 ); } /* ************************************ * * * gen_geomobj * * * ************************************ DESCRIPTION: Load an object consisting of polygons from a file and store it in an Iris display list. The object will render as a wireframe. ENTRY: Filename of a geometry file. EXIT: Returns FALSE if something went wrong, TRUE otherwise. */ #define MAX_POLY_EDGES 10 int gen_geomobj ( filename ) char *filename; { register i,j,temp; int vcount,pcount,ecount,vindex; register VEC3 *vertex,*vptr; register float thisdist,maxdist; VEC3 thispoly[MAX_POLY_EDGES]; FILE *gstream; /* open the file */ gstream = fopen( filename, "r" ); if ( gstream == 0 ) return FALSE; /* read top line */ temp = fscanf( gstream, "%d %d %d", &vcount, &pcount, &ecount ); if ( temp != 3 ) { fclose(gstream); return FALSE; } /* allocate for vertex array */ vertex = (VEC3 *) malloc( vcount * sizeof(VEC3) ); if ( vertex == 0 ) { fclose(gstream); return FALSE; } /* read in vertex array */ maxdist = 0.0; for ( i = 0, vptr = vertex; i < vcount; i++, vptr++ ) { /* read in the point */ temp = fscanf( gstream, "%f %f %f", &vptr->x, &vptr->y, &vptr->z ); if ( temp != 3 ) { free(vertex); fclose(gstream); return FALSE; } /* update maximum distance */ thisdist = vptr->x * vptr->x + vptr->y * vptr->y + vptr->z * vptr->z; if ( thisdist > maxdist ) maxdist = thisdist; } /* scale vertex array */ maxdist = 1.0 / sqrt(maxdist); for ( i = 0, vptr = vertex; i < vcount; i++, vptr++ ) { vptr->x *= maxdist; vptr->y *= maxdist; vptr->z *= maxdist; } /* define and set object color */ cm_mapcolor( seg1, s1_OBJSTART, 255, 100, 100 ); color( s1_OBJSTART ); /* read in polygons */ for ( i=0; i<pcount; i++ ) { /* get edges in polygon */ temp = fscanf( gstream, "%d", &ecount ); if ( temp != 1 ) { free(vertex); fclose(gstream); return FALSE; } /* loop through edges for this polygon */ for ( j=0; j<ecount; j++ ) { temp = fscanf( gstream, "%d", &vindex ); if ( temp != 1 ) { free(vertex); fclose(gstream); return FALSE; } vindex--; if ( j < MAX_POLY_EDGES ) thispoly[j] = vertex[vindex]; } /* send out polygon */ if ( ecount <= MAX_POLY_EDGES ) poly( ecount, thispoly ); } /* close and finish */ free( vertex ); fclose( gstream ); return TRUE; } @//E*O*F boxobj.c// chmod u=rw,g=r,o=r boxobj.c echo x - boxview.c sed 's/^@//' > "boxview.c" <<'@//E*O*F boxview.c//' /* FILENAME: boxview.c AUTHOR: Kelvin Thompson, 10/87 DESCRIPTION: Central routines for boxview program. COPYRIGHT: This software is Copyright 1986,1987,1988 by Kelvin Thompson and carries GNU-like restrictions: Permission is granted to use, copy, modify, and redistribute this software for non- commercial purposes, as long as copies and derivative works carry these same restrictions. */ #define CENTRAL #include <stdio.h> #include <math.h> #include <gl.h> #include <device.h> #include <get.h> #include "ktypes.h" #include "idraw.h" /* programs in this file */ extern main(); extern void init_iris(); extern void init_globs(); extern void st_draw(); extern void readystate(); /* programs in 'rotate.c' */ extern void st_axis(); /* programs in 'wm.c' */ extern WINDOW *open_wdw(); /* programs in 'view.c' */ extern VIEW *open_view(); /* local globals */ UNS16 objplanes; /* ********************* * * * main * * * ********************* DESCRIPTION: */ main ( argc, argv ) int argc; char **argv; { /* initialize */ init_iris(); init_globs(); init_manip(); init_view(); init_rot(); init_obj( argc, argv ); /* open main window */ w0ptr = open_wdw( wminx, wmaxx, wminy, wmaxy ); v0ptr = open_view( w0ptr ); open_xh( v0ptr ); /* initialize states */ init_states(); readystate(); while ( TRUE ) { if ( !do_state() ) break; writemask( 0xffffffff ); swapbuffers(); } /* shut down */ close_wdw( w0ptr ); close_states(); gflush(); finish(); ginit(); gexit(); } /* ********************* * * * init_iris * * * ********************* DESCRIPTION: Initialize iris and and a couple of globals. GLOBALS: mexon -- boolean indicating that we're running under 'mex' */ /* color table */ #define LAST_ENTRY 0xfff typedef struct CLR_ENTRY { Colorindex idx; short r,g,b; } CLR_ENTRY; static CLR_ENTRY s0_entry[] = { { s0_2CURSOR, 255, 0, 0 }, { s0_3WDW, 200, 200, 200 }, { s0_2WDW, 255, 255, 255 }, { s0_AXES, 100, 100, 255 }, { s0_AXNAMES, 200, 0, 0 }, { s0_XH_EDGE, 180, 180, 0 }, { LAST_ENTRY, 0, 0, 0 } }; static CLR_ENTRY s1_entry[] = { { s1_BLACK, 0, 0, 0 }, { s1_BACKG, 0, 0, 0 }, { s1_VW_BACKG, 0, 0, 0 }, { s1_VW_LINES, 0, 0, 255 }, { s1_VW_GRABS, 250, 0, 0 }, { s1_VW_BUTT, 200, 0, 0 }, { s1_VW_AREA, 100, 100, 100 }, { s1_SPLAT, 200, 200, 0 }, { LAST_ENTRY, 0, 0, 0 } }; void init_iris ( ) { register i; register struct CLR_ENTRY *clr; int buffbits; unsigned maxcolor; /* mex preferences */ foreground(); prefposition( 0, XMAXSCREEN, 0, YMAXSCREEN ); /* start & init graphics */ getport( "idraw" ); greset(); /* see if we're running mex */ getsize( &wmaxx, &wmaxy ); mexon = ( wmaxx != 1024 || wmaxy != 1024 ); /* basic initialization */ color( BLACK ); clear(); onemap(); doublebuffer(); swapinterval(1); gconfig(); setvaluator( MOUSEX, (XMAXSCREEN+1)/2, 0, XMAXSCREEN ); setvaluator( MOUSEY, (YMAXSCREEN+1)/2, 0, YMAXSCREEN ); /* enqueue all keyboard buttons */ for ( i=BUT0; i<MAXKBDBUT; i++ ) qdevice( i ); /* load the grab font */ defrasterfont( GRAB_FONT_IDX, GRAB_MAX_HEIGHT, NUM_GRAB_CHARS+1, grabchar, NUM_GRAB_RASTS, grabrast ); /* allocate the bitplane segments */ buffbits = cm_reset(); objplanes = buffbits - 3; seg1 = cm_alloc( objplanes ) & 0xffff; maxcolor = cm_alloc( 3 ); seg0 = maxcolor & 0xffff; maxcolor = (1<<objplanes) - 1; /* color segment 1 */ for ( clr = s1_entry; clr->idx != LAST_ENTRY; clr++ ) cm_mapcolor( seg1, clr->idx, clr->r, clr->g, clr->b ); /* color segment 0 */ for ( clr = s0_entry; clr->idx != LAST_ENTRY; clr++ ) cm_mapcolor( seg0, clr->idx, clr->r, clr->g, clr->b ); /* cursor stuff */ setcursor( 0, cm_truecolor(seg0,s0_2CURSOR), 0xffff ); curson(); } /* ************************************ * * * init_globs * * * ************************************ DESCRIPTION: Initialize various globals. PREREQUSITES: Need to run 'init_iris' first. */ void init_globs ( ) { /* set up window bounds */ if ( FALSE && mexon ) /* mex presently uses full screen */ { getorigin( &wminx, &wminy ); wmaxx += wminx - 1; wmaxy += wminy - 1; } else if ( getmonitor() == NTSC ) { wminx = NTSC_XMIN; wminy = NTSC_YMIN; wmaxx = NTSC_XMAX; wmaxy = NTSC_YMAX; } else { wminx = VP_XMIN; wminy = VP_YMIN; wmaxx = VP_XMAX; wmaxy = VP_YMAX; } /* the screen-coord matrix */ map_rects( default_mtx, &screenrect, &ndcrect ); } /* ************************************ * * * st_draw * * * ************************************ DESCRIPTION: The main drawing state. ENTRY: ignored */ void st_draw ( val1, val2 ) { register pickcode; register UNS16 thisleft; static UNS16 prevleft=FALSE; if ( !getbutton(ESCKEY) ) { if ( (thisleft = getbutton(LEFTMOUSE)) && !prevleft ) { if ( !check_view(v0ptr) && !check_rot(v0ptr) && !check_xh(v0ptr) ) readystate(); } else readystate(); prevleft = thisleft; } } /* ************************************ * * * readystate * * * ************************************ DESCRIPTION: */ void readystate ( ) { use_view( v0ptr ); cm_color( seg1, s1_BACKG ); /* writemask( 0xffff ); */ /* color( 0 ); */ clear(); draw_obj(); draw_box(); draw_xh( v0ptr ); draw_view( v0ptr ); add_state( st_draw, 0, 0 ); } @//E*O*F boxview.c// chmod u=rw,g=r,o=r boxview.c echo x - manip.c sed 's/^@//' > "manip.c" <<'@//E*O*F manip.c//' /* FILENAME: manip.c DESCRIPTION: Subroutines for user manipulations. COPYRIGHT: This software is Copyright 1986,1987,1988 by Kelvin Thompson and carries GNU-like restrictions: Permission is granted to use, copy, modify, and redistribute this software for non- commercial purposes, as long as copies and derivative works carry these same restrictions. */ #include <gl.h> #include <device.h> #include "idraw.h" /* programs in this file */ extern void init_manip(); extern void make_boxes(); extern void draw_box(); extern check_pick(); /* local variables */ static Object box_obj; /* ************************************ * * * init_manip * * * ************************************ DESCRIPTION: Manipulation initializations. */ void init_manip ( ) { make_boxes(); } /* ************************************ * * * make_boxes * * * ************************************ DESCRIPTION: Make object(s) for the main manipulator box. */ void make_boxes ( ) { /* get the object ID */ box_obj = genobj(); /* the drawn box with axes */ makeobj( box_obj ); cm_color( seg0, s0_3WDW ); /* the extent box */ move( -1.0, -1.0, -1.0 ); draw( -1.0, 1.0, -1.0 ); draw( 1.0, 1.0, -1.0 ); draw( 1.0, -1.0, -1.0 ); draw( -1.0, -1.0, -1.0 ); move( -1.0, -1.0, 1.0 ); draw( -1.0, 1.0, 1.0 ); draw( 1.0, 1.0, 1.0 ); draw( 1.0, -1.0, 1.0 ); draw( -1.0, -1.0, 1.0 ); move( -1.0, -1.0, -1.0 ); draw( -1.0, -1.0, 1.0 ); move( -1.0, 1.0, -1.0 ); draw( -1.0, 1.0, 1.0 ); move( 1.0, -1.0, -1.0 ); draw( 1.0, -1.0, 1.0 ); move( 1.0, 1.0, -1.0 ); draw( 1.0, 1.0, 1.0 ); closeobj(); } /* ************************************ * * * draw_box * * * ************************************ DESCRIPTION: Draw the main manipulator box. */ void draw_box ( ) { callobj( box_obj ); } /* ************************************ * * * check_pick * * * ************************************ DESCRIPTION: See if we pick anything that is drawn. ENTRY: generate -- Pointer to a function which will generate the objects to be matched. param -- parameter passed to this function EXIT: Returns last matched 'passthrough' code. PREREQUISITES: Need to set viewport first. */ check_pick ( wdw, xform, generate, param ) WINDOW *wdw; Matrix xform; void (*generate)(); { register long count; register outcode; register betwflag; register short *codeptr; RECT mousebox; static Matrix pickmatx=I_INIT; /* get the box for the mouse */ if ( ! getmousebox( wdw, &mousebox ) ) return 0; /* figure the transform */ qmap_rects( pickmatx, &mousebox, &ndcrect ); /* check for hits */ pushmatrix(); loadmatrix( pickmatx ); multmatrix( xform ); feedback( fb_buff, FB_MAX ); (*generate)( param ); count = endfeedback( fb_buff ); popmatrix(); /* consolidate into a result */ outcode = 0; betwflag = FALSE; for ( codeptr = fb_buff; (outcode==0) && (count>0); --count ) switch ( *codeptr++ ) { case 8: /* passthrough */ if ( betwflag ) { outcode = *codeptr; betwflag = FALSE; } codeptr++; --count; break; case 16: /* move command */ case 17: /* draw command */ case 18: /* pnt command */ case 48: /* pmv command */ case 49: /* pdr command */ case 51: /* pclos command */ betwflag = TRUE; codeptr += 2; count -= 2; break; case 56: /* xfpt command */ betwflag = TRUE; codeptr += 4; count -= 4; break; default: betwflag = TRUE; break; } return outcode; } @//E*O*F manip.c// chmod u=rw,g=r,o=r manip.c echo x - rotate.c sed 's/^@//' > "rotate.c" <<'@//E*O*F rotate.c//' /* FILENAME: rotate.c (version II) DESCRIPTION: Various programs dealing with rotations. COPYRIGHT: This software is Copyright 1986,1987,1988 by Kelvin Thompson and carries GNU-like restrictions: Permission is granted to use, copy, modify, and redistribute this software for non- commercial purposes, as long as copies and derivative works carry these same restrictions. */ #include <math.h> #include <gl.h> #include <device.h> #include "idraw.h" #define DRAWSPLAT FALSE #define DRAWCELL FALSE /* programs in this file */ extern void init_rot(); extern check_rot(); extern void pick_rot(); extern void st_axis(); extern void st_rotate(); extern void gen_splat(); extern void drawsplat(); extern void drawcell(); extern void draw_rot(); extern void make_wbox(); extern void gen_wbox(); /* programs in 'xform.c' */ extern void rot_x(),rot_y(),rot_z(); /* other programs */ extern void st_draw(); static Object wbox_obj; typedef struct SPLATCELL { float a,b; float ang; } SPLATCELL; /* tweakable parameters */ #define NUM_TESTS 45 #define SPLAT_ANG (PI/5.3) #define NEG_START 0.0 #define POS_START 0.0 #define RANGE 1.4 /* basic parameters */ #define NUM_AXES 3 #define NUM_CORNERS 4 #define NUM_DIRS 3 /* derived parameters */ #define NUM_SPLATS (NUM_TESTS|1) /* make it odd */ #define SPLAT_SEP (SPLAT_ANG/(NUM_SPLATS-2.0)) /* corner constructs */ #define CORNER(a,b) (((a&1)?2:0) | ((b&1)?1:0)) static SPLATCELL cornsplat[NUM_CORNERS] = { { -1.0, -1.0, -0.75*PI }, { -1.0, 1.0, 0.75*PI }, { 1.0, -1.0, -0.25*PI }, { 1.0, 1.0, 0.25*PI } }; /* direction symbols */ #define NO_DIR 0 #define POS_DIR 1 #define NEG_DIR 2 /* axis symbols */ #define X_AXIS TOKCOD_X #define Y_AXIS TOKCOD_Y #define Z_AXIS TOKCOD_Z /* splat arrays */ static SPLATCELL splat[NUM_CORNERS][NUM_DIRS][NUM_SPLATS]; static Object splatobj[NUM_AXES][NUM_CORNERS][NUM_DIRS]; /* state of rotate action */ typedef struct ROTSTATE { void (*func)(); float ang; UNS8 axis; UNS8 corner; UNS8 dir; } ROTSTATE; static ROTSTATE rstate; /* ********************* * * * init_rot * * * ********************* DESCRIPTION: Initialize rotation stuff. */ void init_rot ( ) { register corner,i,dir; float relang,absang; float aa,bb; /* first splat for each direction and corner is zero offset angle */ for ( corner=0; corner<NUM_CORNERS; corner++ ) for ( i=0; i<NUM_DIRS; i++ ) { splat[corner][i][0] = cornsplat[corner]; splat[corner][i][0].ang = 0.0; } /* initialize rest of splat array */ for ( i=1; i<NUM_SPLATS; i++ ) { /* neutral direction */ relang = ((i&1)?-1:1) * ( (SPLAT_SEP*0.5) + ((i-1)>>1) * SPLAT_SEP ); for ( corner=0; corner<NUM_CORNERS; corner++ ) { absang = cornsplat[corner].ang + relang; splat[corner][NO_DIR][i].ang = relang; splat[corner][NO_DIR][i].a = SQRT_2 * cos(absang); splat[corner][NO_DIR][i].b = SQRT_2 * sin(absang); } /* negative direction */ relang = NEG_START - (i-1) * SPLAT_SEP; for ( corner=0; corner<NUM_CORNERS; corner++ ) { absang = cornsplat[corner].ang + relang; splat[corner][NEG_DIR][i].ang = relang; splat[corner][NEG_DIR][i].a = SQRT_2 * cos(absang); splat[corner][NEG_DIR][i].b = SQRT_2 * sin(absang); } /* positive direction */ relang = POS_START + (i-1) * SPLAT_SEP; for ( corner=0; corner<NUM_CORNERS; corner++ ) { absang = cornsplat[corner].ang + relang; splat[corner][POS_DIR][i].ang = relang; splat[corner][POS_DIR][i].a = SQRT_2 * cos(absang); splat[corner][POS_DIR][i].b = SQRT_2 * sin(absang); } } /* initialize splat objects */ for ( corner=0; corner<NUM_CORNERS; corner++ ) for ( dir=0; dir<NUM_DIRS; dir++ ) { /* X axis */ makeobj( splatobj[X_AXIS][corner][dir] = genobj() ); for ( i=0; i<NUM_SPLATS; i++ ) { aa = splat[corner][dir][i].a; bb = splat[corner][dir][i].b; move( -RANGE, aa, bb ); draw( RANGE, aa, bb ); passthrough( i+1 ); } closeobj(); /* Y axis */ makeobj( splatobj[Y_AXIS][corner][dir] = genobj() ); for ( i=0; i<NUM_SPLATS; i++ ) { aa = splat[corner][dir][i].a; bb = splat[corner][dir][i].b; move( bb, -RANGE, aa ); draw( bb, RANGE, aa ); passthrough( i+1 ); } closeobj(); /* Z axis */ makeobj( splatobj[Z_AXIS][corner][dir] = genobj() ); for ( i=0; i<NUM_SPLATS; i++ ) { aa = splat[corner][dir][i].a; bb = splat[corner][dir][i].b; move( aa, bb, -RANGE ); draw( aa, bb, RANGE ); passthrough( i+1 ); } closeobj(); } make_wbox(); } /* ************************************ * * * check_rot * * * ************************************ DESCRIPTION: Check rotation objects for a hit. EXIT: Returns TRUE when we find something, FALSE otherwise. */ check_rot ( vptr ) register VIEW *vptr; { register UNS16 pickcode; register WINDOW *wdw; register out; wdw = vptr->wdw; viewport( wdw->edge.a.x, wdw->edge.b.x, wdw->edge.a.y, wdw->edge.b.y ); pickcode = check_pick( vptr->wdw, &vptr->total, gen_wbox ); switch ( pickcode & TOKTYP_MASK ) { case TOKTYP_ROT: /* reactive rotation */ pick_rot( pickcode & TOKCOD_MASK ); draw_rot( vptr ); out = TRUE; break; default: /* can't interpret -- punt */ out = FALSE; break; } return out; } /* ********************* * * * pick_rot * * * ********************* DESCRIPTION: Perform actions after picking a rotate bar. ENTRY: Code for selected object. */ void pick_rot ( code ) UNS16 code; { static void (*rotfunc[NUM_AXES])() = { rot_x, rot_y, rot_z }; rstate.axis = code & TOKCOD_DIR; rstate.dir = NO_DIR; rstate.corner = (code & TOKPT(1,1)) >> 2; rstate.func = rotfunc[rstate.axis]; rstate.ang = 0.0; add_state( st_rotate, 0, 0 ); } /* ************************************ * * * st_axis * * * ************************************ DESCRIPTION: The axis rotation state. ENTRY: axis -- Axis of rotation. dum -- ignored dummy parameter */ void st_axis ( axis, dum ) UNS8 axis; { if ( !getbutton(LEFTMOUSE) ) readystate(); else { switch ( axis ) { case TOKCOD_X: rot_x( & v0ptr->box_to_rot, 2.0*PI/200.0 ); break; case TOKCOD_Y: rot_y( & v0ptr->box_to_rot, 2.0*PI/200.0 ); break; case TOKCOD_Z: rot_z( & v0ptr->box_to_rot, 2.0*PI/200.0 ); break; } draw_rot( v0ptr ); add_state( st_axis, axis, 0 ); } } /* ********************* * * * st_rotate * * * ********************* DESCRIPTION: Reactive rotation ENTRY: dum1,dum2 -- ignored */ void st_rotate ( dum1, dum2 ) { register i; register SPLATCELL *splatptr; register float ang; UNS16 pickcode; /* go back to waiting state if no mouse button */ if ( !getbutton(LEFTMOUSE) ) readystate(); else { # if DRAWSPLAT drawsplat(); # endif pickcode = check_pick( v0ptr->wdw, &v0ptr->total, gen_splat ); if ( pickcode == 0 ) { if ( rstate.dir != NO_DIR ) (*rstate.func)( & v0ptr->box_to_rot, rstate.ang ); rstate.dir = NO_DIR; } else { # if DRAWCELL drawcell( pickcode-1 ); # endif rstate.ang = ang = splat[rstate.corner][rstate.dir][pickcode-1].ang; if ( ang == 0.0 ) rstate.dir = NO_DIR; else { (*rstate.func)( & v0ptr->box_to_rot, ang ); rstate.dir = (ang>0.0) ? POS_DIR : NEG_DIR; } } draw_rot( v0ptr ); add_state( st_rotate, 0, 0 ); } } /* ************************************ * * * gen_splat * * * ************************************ DESCRIPTION: ENTRY: */ void gen_splat ( ) { callobj( splatobj[rstate.axis][rstate.corner][rstate.dir] ); } #if DRAWSPLAT /* ********************* * * * drawsplat * * * ********************* DESCRIPTION: ENTRY: */ void drawsplat ( ) { register i; register SPLATCELL *splatptr; cm_color( seg1, s1_SPLAT ); switch ( rstate.axis ) { case X_AXIS: for ( i = 0, splatptr = splat[rstate.corner][rstate.dir]; i < NUM_SPLATS; i++, splatptr++ ) { move( -RANGE, splatptr->a, splatptr->b ); draw( RANGE, splatptr->a, splatptr->b ); } break; case Y_AXIS: for ( i = 0, splatptr = splat[rstate.corner][rstate.dir]; i < NUM_SPLATS; i++, splatptr++ ) { move( splatptr->b, -RANGE, splatptr->a ); draw( splatptr->b, RANGE, splatptr->a ); } break; case Z_AXIS: for ( i = 0, splatptr = splat[rstate.corner][rstate.dir]; i < NUM_SPLATS; i++, splatptr++ ) { move( splatptr->a, splatptr->b, -RANGE ); draw( splatptr->a, splatptr->b, RANGE ); } break; } } #endif #if DRAWCELL /* ********************* * * * drawcell * * * ********************* DESCRIPTION: ENTRY: */ void drawcell ( idx ) UNS16 idx; { register SPLATCELL *splatptr; splatptr = & splat[rstate.corner][rstate.dir][idx]; finish(); @@@color( RED ); switch ( rstate.axis ) { case X_AXIS: move( -RANGE, splatptr->a, splatptr->b ); draw( RANGE, splatptr->a, splatptr->b ); break; case Y_AXIS: move( splatptr->b, -RANGE, splatptr->a ); draw( splatptr->b, RANGE, splatptr->a ); break; case Z_AXIS: move( splatptr->a, splatptr->b, -RANGE ); draw( splatptr->a, splatptr->b, RANGE ); break; } } #endif /* ************************************ * * * make_wbox * * * ************************************ DESCRIPTION: ENTRY: */ void make_wbox ( ) { wbox_obj = genobj(); /* the marked box with axes (for feedback) */ makeobj( wbox_obj ); /* do the edges of the box */ move( -1.0, -1.0, -1.0 ); draw( -1.0, 1.0, -1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Y | TOKPT(0,0) ); draw( 1.0, 1.0, -1.0 ); passthrough( TOKTYP_ROT | TOKCOD_X | TOKPT(1,0) ); draw( 1.0, -1.0, -1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Y | TOKPT(0,1) ); draw( -1.0, -1.0, -1.0 ); passthrough( TOKTYP_ROT | TOKCOD_X | TOKPT(0,0) ); move( -1.0, -1.0, 1.0 ); draw( -1.0, 1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Y | TOKPT(1,0) ); draw( 1.0, 1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_X | TOKPT(1,1) ); draw( 1.0, -1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Y | TOKPT(1,1) ); draw( -1.0, -1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_X | TOKPT(0,1) ); move( -1.0, -1.0, -1.0 ); draw( -1.0, -1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Z | TOKPT(0,0) ); move( -1.0, 1.0, -1.0 ); draw( -1.0, 1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Z | TOKPT(0,1) ); move( 1.0, -1.0, -1.0 ); draw( 1.0, -1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Z | TOKPT(1,0) ); move( 1.0, 1.0, -1.0 ); draw( 1.0, 1.0, 1.0 ); passthrough( TOKTYP_ROT | TOKCOD_Z | TOKPT(1,1) ); #if 0 /* do the axes */ move( 0.0, 0.0, 0.0 ); draw( 1.5, 0.0, 0.0 ); passthrough( TOK_XAXIS ); move( 0.0, 0.0, 0.0 ); draw( 0.0, 1.5, 0.0 ); passthrough( TOK_YAXIS ); move( 0.0, 0.0, 0.0 ); draw( 0.0, 0.0, 1.5 ); passthrough( TOK_ZAXIS ); #endif closeobj(); } /* ************************************ * * * gen_wbox * * * ************************************ DESCRIPTION: ENTRY: */ void gen_wbox ( ) { callobj( wbox_obj ); } /* ************************************ * * * draw_rot * * * ************************************ DESCRIPTION: */ void draw_rot ( vptr ) VIEW *vptr; { use_view( vptr ); cm_color( seg1, s1_BACKG ); clear(); draw_obj(); draw_box(); draw_xh( vptr ); } @//E*O*F rotate.c// chmod u=rw,g=r,o=r rotate.c echo x - view.c sed 's/^@//' > "view.c" <<'@//E*O*F view.c//' /* FILENAME: view.c DESCRIPTION: Programs for manipulating viewing geometry. COPYRIGHT: This software is Copyright 1986,1987,1988 by Kelvin Thompson and carries GNU-like restrictions: Permission is granted to use, copy, modify, and redistribute this software for non- commercial purposes, as long as copies and derivative works carry these same restrictions. */ #include <gl.h> #include <device.h> #include "idraw.h" /* programs in this file */ extern void init_view(); extern VIEW *open_view(); extern void use_view(); extern void calc_vwtot(); extern void gen_view(); extern void draw_view(); extern void draw_vmanip(); extern void draw_vbutt(); extern check_view(); extern void runwind(); extern void runwend(); extern void runeye(); extern void runorg(); extern void donevmanip(); extern void draw_main(); /* programs in 'wm.c' */ extern WINDOW *open_wdw(); #define VW_SIZX 100 #define VW_SIZY 80 #define VW_RATIO ((float)VW_SIZY/(float)VW_SIZX) #define VW_BUTTRAD 8 static VIEW *now_vptr; static VIEWGEOM prevgeom; static float prev30,prev31,prev33; /* ************************************ * * * init_view * * * ************************************ DESCRIPTION: */ void init_view ( ) { } /* ************************************ * * * open_view * * * ************************************ DESCRIPTION: EXIT: */ VIEW *open_view ( wdw ) register WINDOW *wdw; { register VIEW *vptr; /* allocate & link */ vptr = (VIEW *)malloc( sizeof(VIEW) ); vptr->wdw = wdw; /* viewing parameters */ vptr->g.R = VP_R; vptr->g.D = VP_D; vptr->g.wx = VP_WX; vptr->g.wy = vptr->g.wx * (float)(wdw->edge.b.y - wdw->edge.a.y + 1) / (float)(wdw->edge.b.x - wdw->edge.a.x + 1); /* matricies */ vptr->box_to_rot.a = I; set_view( &vptr->rot_to_ndc, vptr->g.R, vptr->g.D, vptr->g.wx, vptr->g.wy ); vptr->total.a = vptr->rot_to_ndc.a; calc_vwtot( vptr ); /* button's edges */ vptr->butt.a.x = wdw->edge.a.x; vptr->butt.a.y = wdw->edge.a.y; vptr->butt.b.x = vptr->butt.a.x + VW_BUTTRAD; vptr->butt.b.y = vptr->butt.a.y + VW_BUTTRAD; /* view-manipulation window */ vptr->vw = open_wdw( wdw->edge.a.x, wdw->edge.a.x+VW_SIZX, wdw->edge.a.y, wdw->edge.a.y+VW_SIZY ); vptr->viewon = FALSE; return vptr; } /* ************************************ * * * use_view * * * ************************************ DESCRIPTION: ENTRY: */ void use_view ( vptr ) register VIEW *vptr; { use_wdw( vptr->wdw ); loadmatrix( & vptr->rot_to_ndc ); multmatrix( & vptr->box_to_rot ); getmatrix( & vptr->total ); } /* ************************************ * * * reuse_view * * * ************************************ DESCRIPTION: ENTRY: */ void reuse_view ( vptr ) register VIEW *vptr; { use_wdw( vptr->wdw ); loadmatrix( & vptr->total ); } /* ************************************ * * * check_view * * * ************************************ DESCRIPTION: ENTRY: EXIT: */ check_view ( vptr ) register VIEW *vptr; { register long mx,my; register pickcode; VEC3 vec1,vec2; SCRNRECT srect; pickcode = 0; mx = getvaluator( MOUSEX ); my = getvaluator( MOUSEY ); /* see if we're toggling the view window */ if ( vptr->butt.a.x <= mx && mx <= vptr->butt.b.x && vptr->butt.a.y <= my && my <= vptr->butt.b.y ) { vptr->viewon = ! vptr->viewon; readystate(); pickcode = TRUE; } /* see if we're trying to change the view */ else if ( vptr->viewon ) { /* check for a pick */ vp_wdw( vptr->vw ); loadmatrix( &vptr->vwtot ); now_vptr = vptr; pickcode = check_pick( vptr->vw, &vptr->vwtot, gen_view ); /* see if we hit any view manipulators */ if ( (pickcode & TOKTYP_MASK) != TOKTYP_VW ) { pickcode = 0; } else { /* remember the previous geometry */ prevgeom = vptr->g; switch ( pickcode ) { case TOK_VORG: /* try to map part of the X-axis to screen coords */ vec1.x = 0.0; vec1.y = 0.0; vec1.z = 0.0; vec2.x = vptr->g.D - vptr->g.R; vec2.y = 0.0; vec2.z = 0.0; if ( !getslidepts( &vec1, &vec2, &srect ) ) goto badpick; /* remember stuff */ prev30 = vptr->vwtot.m[3][0]; prev31 = vptr->vwtot.m[3][1]; prev33 = vptr->vwtot.m[3][3]; /* slide */ doslide( &srect, runorg, donevmanip ); break; case TOK_VEYE: /* try to map part of the X-axis to screen coords */ vec1.x = -vptr->g.R; vec1.y = 0.0; vec1.z = 0.0; vec2.x = vptr->g.D - vptr->g.R; vec2.y = 0.0; vec2.z = 0.0; if ( !getslidepts( &vec1, &vec2, &srect ) ) goto badpick; /* slide */ doslide( &srect, runeye, donevmanip ); break; case TOK_VWTOP: /* try to map part of the X-axis to screen coords */ vec1.x = vptr->g.D - vptr->g.R; vec1.y = 0.0; vec1.z = 0.0; vec2.x = vec1.x; vec2.y = vptr->g.wy; vec2.z = 0.0; if ( !getslidepts( &vec1, &vec2, &srect ) ) goto badpick; /* slide */ doslide( &srect, runwend, donevmanip ); break; case TOK_VWBOT: /* try to map part of the X-axis to screen coords */ vec1.x = vptr->g.D - vptr->g.R; vec1.y = 0.0; vec1.z = 0.0; vec2.x = vec1.x; vec2.y = -vptr->g.wy; vec2.z = 0.0; if ( !getslidepts( &vec1, &vec2, &srect ) ) goto badpick; /* slide */ doslide( &srect, runwend, donevmanip ); break; case TOK_VWIND: /* try to map part of the X-axis to screen coords */ vec1.x = -vptr->g.R; vec1.y = 0.0; vec1.z = 0.0; vec2.x = 0.0; vec2.y = 0.0; vec2.z = 0.0; if ( !getslidepts( &vec1, &vec2, &srect ) ) goto badpick; /* slide */ doslide( &srect, runwind, donevmanip ); break; default: badpick: ringbell(); readystate(); break; } } } return pickcode; } /* ************************************ * * * draw_view * * * ************************************ DESCRIPTION: ENTRY: */ void draw_view ( vptr ) register VIEW *vptr; { if ( vptr->viewon ) draw_vmanip( vptr ); draw_vbutt( vptr ); } /* ************************************ * * * draw_vmanip * * * ************************************ DESCRIPTION: Draw view manipulation structures. ENTRY: */ void draw_vmanip ( vptr ) register VIEW *vptr; { register float temp; /* set up the view window */ use_wdw( vptr->vw ); loadmatrix( & vptr->vwtot ); cm_color( seg1, s1_VW_BACKG ); clear(); /* draw the clipping box */ cm_color( seg1, s1_VW_AREA ); circf( 0.0, 0.0, SQRT_2 ); /* draw the axis */ cm_color( seg1, s1_VW_LINES ); move2( -100.0, 0.0 ); draw2( 100.0, 0.0 ); /* draw the window plane */ temp = vptr->g.D - vptr->g.R; move2( temp, -vptr->g.wy ); draw2( temp, vptr->g.wy ); /* draw the fostrum edges */ move2( -vptr->g.R, 0.0 ); rdr2( vptr->g.D * 100.0, -vptr->g.wy * 100.0 ); move2( -vptr->g.R, 0.0 ); rdr2( vptr->g.D * 100.0, vptr->g.wy * 100.0 ); /* draw the selectable markers */ font( GRAB_FONT_IDX ); cm_color( seg1, s1_VW_GRABS ); cmov2( -vptr->g.R, 0.0 ); charstr( "\001" ); cmov2( 0.0, 0.0 ); charstr( "\001" ); cmov2( temp, -vptr->g.wy ); charstr( "\001" ); cmov2( temp, 0.0 ); charstr( "\001" ); cmov2( temp, vptr->g.wy ); charstr( "\001" ); } /* ************************************ * * * draw_vbutt * * * ************************************ DESCRIPTION: ENTRY: */ void draw_vbutt ( vptr ) register VIEW *vptr; { viewport( 0, XMAXSCREEN, 0, YMAXSCREEN ); loadmatrix( default_mtx ); cm_color( seg1, s1_VW_BUTT ); rectfi( vptr->butt.a.x, vptr->butt.a.y, vptr->butt.b.x, vptr->butt.b.y ); } /* ************************************ * * * calc_vwtot * * * ************************************ DESCRIPTION: ENTRY: */ #define VW_PAD 0.1 void calc_vwtot ( vptr ) register VIEW *vptr; { register float wantdx,wantdy,factor; RECT ext; /* calculate the rectangle we want to see */ ext.a.x = -(1.0+VW_PAD) * vptr->g.R; ext.b.x = VW_PAD * vptr->g.R; ext.b.y = (1.0+VW_PAD) * vptr->g.wy; ext.a.y = -ext.b.y; /* calculate width, height, and ratio */ wantdx = ext.b.x - ext.a.x; wantdy = ext.b.y - ext.a.y; /* expand the rect to make its ratio fit */ if ( wantdy / wantdx > VW_RATIO ) { /* window too tall -- need to make wider */ factor = wantdy / (wantdx * VW_RATIO); ext.a.x += (1.0 - factor) * 0.5 * wantdx; ext.b.x = ext.a.x + wantdx * factor; } else { /* window too narrow -- need to make taller */ factor = (wantdx * VW_RATIO) / wantdy; ext.a.y += (1.0 - factor) * 0.5 * wantdy; ext.b.y = ext.a.y + wantdy * factor; } map_rects( &vptr->vwtot, &ext, &ndcrect ); } /* ************************************ * * * gen_view * * * ************************************ DESCRIPTION: */ void gen_view ( ) { register float temp; register VIEW *vptr; vptr = now_vptr; temp = vptr->g.D - vptr->g.R; pnt2( -vptr->g.R, 0.0 ); passthrough( TOK_VEYE ); pnt2( 0.0, 0.0 ); passthrough( TOK_VORG ); pnt2( temp, -vptr->g.wy ); passthrough( TOK_VWBOT ); pnt2( temp, 0.0 ); passthrough( TOK_VWIND ); pnt2( temp, vptr->g.wy ); passthrough( TOK_VWTOP ); } /* ************************************ * * * runwind * * * ************************************ DESCRIPTION: ENTRY: */ void runwind ( tt ) register float tt; { register VIEW *vptr; /* initialize */ vptr = now_vptr; /* adjust 'tt' */ if ( tt < 0.1 ) tt = 0.1; else if ( 0.9 < tt ) tt = 0.9; /* adjust the parameters */ vptr->g.D = tt * prevgeom.R; set_view( &vptr->rot_to_ndc, vptr->g.R, vptr->g.D, vptr->g.wx, vptr->g.wy ); /* draw the main 3-box */ draw_main( vptr ); } /* ************************************ * * * donevmanip * * * ************************************ DESCRIPTION: ENTRY: */ void donevmanip ( tt ) register float tt; { calc_vwtot( now_vptr ); } /* ************************************ * * * runwend * * * ************************************ DESCRIPTION: ENTRY: */ void runwend ( tt ) register float tt; { register VIEW *vptr; /* initialize */ vptr = now_vptr; /* adjust 'tt' */ if ( tt < 0.1 ) tt = 0.1; else if ( 2.0 < tt ) tt = 2.0; /* adjust the parameters */ vptr->g.wy = tt * prevgeom.wy; vptr->g.wx = tt * prevgeom.wx; set_view( &vptr->rot_to_ndc, vptr->g.R, vptr->g.D, vptr->g.wx, vptr->g.wy ); /* draw the main 3-box */ draw_main( vptr ); } /* ************************************ * * * runeye * * * ************************************ DESCRIPTION: ENTRY: */ void runeye ( tt ) register float tt; { register VIEW *vptr; /* initialize */ vptr = now_vptr; /* adjust 'tt' */ if ( tt < -2.0 ) tt = -2.0; else if ( tt > 0.9 ) tt = 0.9; /* adjust the parameters */ vptr->g.R = prevgeom.R - tt * prevgeom.D; vptr->g.D = prevgeom.D - (prevgeom.R - vptr->g.R); set_view( &vptr->rot_to_ndc, vptr->g.R, vptr->g.D, vptr->g.wx, vptr->g.wy ); /* draw the main 3-box */ draw_main( vptr ); } /* ************************************ * * * runorg * * * ************************************ DESCRIPTION: ENTRY: */ void runorg ( tt ) register float tt; { register VIEW *vptr; register float dx; /* initialize */ vptr = now_vptr; /* adjust 'tt' */ if ( tt < -2.0 ) tt = -2.0; else if ( tt > 0.9 ) tt = 0.9; /* adjust the viewing geometry */ vptr->g.R = prevgeom.R - tt * (prevgeom.R - prevgeom.D); set_view( &vptr->rot_to_ndc, vptr->g.R, vptr->g.D, vptr->g.wx, vptr->g.wy ); /* adjust the transform for the view window */ dx = prevgeom.R - vptr->g.R; vptr->vwtot.m[3][0] = prev30 - dx * vptr->vwtot.m[0][0]; vptr->vwtot.m[3][1] = prev31 - dx * vptr->vwtot.m[0][1]; vptr->vwtot.m[3][3] = prev33 - dx * vptr->vwtot.m[0][3]; /* draw the main 3-box */ draw_main( vptr ); } /* ************************************ * * * draw_main * * * ************************************ DESCRIPTION: ENTRY: */ void draw_main ( vptr ) VIEW *vptr; { use_view( vptr ); cm_color( seg1, s1_BACKG ); clear(); draw_obj(); draw_box(); draw_vmanip( vptr ); } @//E*O*F view.c// chmod u=rw,g=r,o=r view.c echo x - xh.c sed 's/^@//' > "xh.c" <<'@//E*O*F xh.c//' /* FILENAME: xh.c DESCRIPTION: Deal with the crosshairs COPYRIGHT: This software is Copyright 1986,1987,1988 by Kelvin Thompson and carries GNU-like restrictions: Permission is granted to use, copy, modify, and redistribute this software for non- commercial purposes, as long as copies and derivative works carry these same restrictions. */ #include <stdio.h> #include <gl.h> #include <device.h> #include "idraw.h" /* programs in this file */ extern void init_xh(); extern void open_xh(); extern void draw_xh(); extern check_xh(); extern void st_xhmov2(); extern void map2d3d(); /*extern unsigned mostest(); */ /* programs in other files */ extern void st_axis(); #define EDGE_FLAG (TOKCOD_p << 1) #define MOUSE_MAX 512 #define FABS(x) fabs(x) typedef struct MOUSEFLAT { VIEW *vptr; int xsign,ysign; } MOUSEFLAT; /* ************************************ * * * init_xh * * * ************************************ DESCRIPTION: Initialize crosshairs. */ void init_xh ( ) { } /* ************************************ * * * open_xh * * * ************************************ DESCRIPTION: Open crosshairs. ENTRY: vptr -- Pointer to VIEW struct to hold crosshair info. */ void open_xh ( vptr ) register VIEW *vptr; { vptr->xhon = TRUE; vptr->xhdir = FALSE; vptr->xhpos.x = 0.0; vptr->xhpos.y = 0.0; vptr->xhpos.z = 0.0; } /* ************************************ * * * draw_xh * * * ************************************ DESCRIPTION: Draw the 3-D crosshairs. ENTRY: EXIT: */ void draw_xh ( vptr ) register VIEW *vptr; { if ( vptr->xhon ) { /* crosshair color */ cm_color( seg0, s0_AXES ); /* X hair */ move( -1.0, vptr->xhpos.y, vptr->xhpos.z ); draw( 1.0, vptr->xhpos.y, vptr->xhpos.z ); /* Y hair */ move( vptr->xhpos.x, -1.0, vptr->xhpos.z ); draw( vptr->xhpos.x, 1.0, vptr->xhpos.z ); /* Z hair */ move( vptr->xhpos.x, vptr->xhpos.y, -1.0 ); draw( vptr->xhpos.x, vptr->xhpos.y, 1.0 ); /* edges */ if ( vptr->xhdir ) { cm_color( seg0, s0_XH_EDGE ); switch ( vptr->xhdir & TOKCOD_DIR ) { case TOKCOD_X: move( vptr->xhpos.x, -1.0, -1.0 ); draw( vptr->xhpos.x, 1.0, -1.0 ); draw( vptr->xhpos.x, 1.0, 1.0 ); draw( vptr->xhpos.x, -1.0, 1.0 ); draw( vptr->xhpos.x, -1.0, -1.0 ); break; case TOKCOD_Y: move( -1.0, vptr->xhpos.y, -1.0 ); draw( -1.0, vptr->xhpos.y, 1.0 ); draw( 1.0, vptr->xhpos.y, 1.0 ); draw( 1.0, vptr->xhpos.y, -1.0 ); draw( -1.0, vptr->xhpos.y, -1.0 ); break; case TOKCOD_Z: move( -1.0, -1.0, vptr->xhpos.z ); draw( 1.0, -1.0, vptr->xhpos.z ); draw( 1.0, 1.0, vptr->xhpos.z ); draw( -1.0, 1.0, vptr->xhpos.z ); draw( -1.0, -1.0, vptr->xhpos.z ); break; } } /* labels */ font( 0 ); cm_color( seg0, s0_AXNAMES ); cmov( 1.0, vptr->xhpos.y, vptr->xhpos.z ); charstr( "X" ); cmov( vptr->xhpos.x, 1.0, vptr->xhpos.z ); charstr( "Y" ); cmov( vptr->xhpos.x, vptr->xhpos.y, 1.0 ); charstr( "Z" ); } } /* ************************************ * * * gen_xh * * * ************************************ DESCRIPTION: Generate feedback instructions for 3D crosshairs. ENTRY: */ void gen_xh ( vptr ) register VIEW *vptr; { move( 0.0, vptr->xhpos.y, vptr->xhpos.z ); draw( -1.0, vptr->xhpos.y, vptr->xhpos.z ); passthrough( TOK_XH_Xn ); move( 0.0, vptr->xhpos.y, vptr->xhpos.z ); draw( 1.0, vptr->xhpos.y, vptr->xhpos.z ); passthrough( TOK_XH_Xp ); move( vptr->xhpos.x, 0.0, vptr->xhpos.z ); draw( vptr->xhpos.x, -1.0, vptr->xhpos.z ); passthrough( TOK_XH_Yn ); move( vptr->xhpos.x, 0.0, vptr->xhpos.z ); draw( vptr->xhpos.x, 1.0, vptr->xhpos.z ); passthrough( TOK_XH_Yp ); move( vptr->xhpos.x, vptr->xhpos.y, 0.0 ); draw( vptr->xhpos.x, vptr->xhpos.y, -1.0 ); passthrough( TOK_XH_Zn ); move( vptr->xhpos.x, vptr->xhpos.y, 0.0 ); draw( vptr->xhpos.x, vptr->xhpos.y, 1.0 ); passthrough( TOK_XH_Zp ); } /* ************************************ * * * check_xh * * * ************************************ DESCRIPTION: See if mouse over crosshairs. ENTRY: EXIT: Returns status code. */ check_xh ( vptr ) register VIEW *vptr; { register UNS16 pickcode; UNS16 pos; register WINDOW *wdw; register out; short xinit,yinit; static MOUSEFLAT thisflat; wdw = vptr->wdw; viewport( wdw->edge.a.x, wdw->edge.b.x, wdw->edge.a.y, wdw->edge.b.y ); pickcode = check_pick( vptr->wdw, &vptr->total, gen_xh, vptr ); if ( (pickcode & TOKTYP_MASK) != TOKTYP_XH ) { out = FALSE; } else { /* init */ pos = pickcode & TOKCOD_p; vptr->xhdir = EDGE_FLAG | (pickcode & TOKCOD_DIRp); /* redraw screen */ cursoff(); draw_rot( vptr ); /* figure mapping of mouse to 3d crosshairs */ thisflat.vptr = vptr; thisflat.xsign = 1; thisflat.ysign = 1; map2d3d( & thisflat ); /* modifies 'thisflat' */ /* reset the mouse scaling */ switch ( vptr->xhdir & TOKCOD_DIRp ) { case TOKCOD_Xp: xinit = vptr->xhpos.y * MOUSE_MAX; yinit = vptr->xhpos.z * MOUSE_MAX; break; case TOKCOD_Xn: xinit = vptr->xhpos.z * MOUSE_MAX; yinit = vptr->xhpos.y * MOUSE_MAX; break; case TOKCOD_Yp: xinit = vptr->xhpos.z * MOUSE_MAX; yinit = vptr->xhpos.x * MOUSE_MAX; break; case TOKCOD_Yn: xinit = vptr->xhpos.x * MOUSE_MAX; yinit = vptr->xhpos.z * MOUSE_MAX; break; case TOKCOD_Zp: xinit = vptr->xhpos.x * MOUSE_MAX; yinit = vptr->xhpos.y * MOUSE_MAX; break; case TOKCOD_Zn: xinit = vptr->xhpos.y * MOUSE_MAX; yinit = vptr->xhpos.x * MOUSE_MAX; break; } xinit *= thisflat.xsign; yinit *= thisflat.ysign; setvaluator( MOUSEX, xinit, -MOUSE_MAX, MOUSE_MAX ); setvaluator( MOUSEY, yinit, -MOUSE_MAX, MOUSE_MAX ); /* set new state */ add_state( st_xhmov2, &thisflat, 0 ); out = TRUE; } return out; } /* ************************************ * * * st_xhmov2 * * * ************************************ DESCRIPTION: Move the crosshair position in 2D. ENTRY: axis -- code for frozen axis */ void st_xhmov2 ( thisflat, dum ) register MOUSEFLAT *thisflat; { register VIEW *vptr; register float xpos,ypos; /* init */ vptr = thisflat->vptr; if ( ! getbutton(LEFTMOUSE) ) { VEC4 xhwld,xhscn; XFORM toscreen; short xx,yy; /* reset variables */ vptr->xhdir = FALSE; /* */ map_rects( &toscreen, &ndcrect, &vptr->wdw->bounds ); mmul( &toscreen, &vptr->total, &toscreen ); xhwld.x = vptr->xhpos.x; xhwld.y = vptr->xhpos.y; xhwld.z = vptr->xhpos.z; xhwld.w = 1.0; vmul( &xhscn, &xhwld, &toscreen ); xx = xhscn.x / xhscn.w; yy = xhscn.y / xhscn.w; /* reset mouse scaling */ setvaluator( MOUSEX, xx, 0, XMAXSCREEN ); setvaluator( MOUSEY, yy, 0, YMAXSCREEN ); curson(); /* go to base state */ readystate(); } else { /* get 2D real mouse position */ xpos = thisflat->xsign * getvaluator( MOUSEX ) * (1.0/(float)MOUSE_MAX); ypos = thisflat->ysign * getvaluator( MOUSEY ) * (1.0/(float)MOUSE_MAX); /* change the position */ switch ( vptr->xhdir & TOKCOD_DIRp ) { case TOKCOD_Xp: vptr->xhpos.z = ypos; vptr->xhpos.y = xpos; break; case TOKCOD_Xn: vptr->xhpos.z = xpos; vptr->xhpos.y = ypos; break; case TOKCOD_Yp: vptr->xhpos.z = xpos; vptr->xhpos.x = ypos; break; case TOKCOD_Yn: vptr->xhpos.z = ypos; vptr->xhpos.x = xpos; break; case TOKCOD_Zp: vptr->xhpos.x = xpos; vptr->xhpos.y = ypos; break; case TOKCOD_Zn: vptr->xhpos.x = ypos; vptr->xhpos.y = xpos; break; } draw_rot( v0ptr ); add_state( st_xhmov2, thisflat, 0 ); } } /* ************************************ * * * map2d3d * * * ************************************ DESCRIPTION: Fill 'vptr->xhdir' and '?sign' in a MOUSEFLAT struct to determine how the mouse moves the 3D crosshairs. ENTRY: */ #define SLPD(ax,dir) FABS(axslp[ax][dir]) #define MOSTER(ax1,ax2,dir) \ ( \ ( SLPD(ax1,dir) > SLPD(ax2,dir) ) \ ? ( (axslp[ax1][dir] > 0.0) ? (ax1) | TOKCOD_p : (ax1) ) \ : ( (axslp[ax2][dir] > 0.0) ? (ax2) | TOKCOD_p : (ax2) ) \ ) void map2d3d ( fptr ) register MOUSEFLAT *fptr; { register VIEW *vptr; register XFORM *total; UNS16 upaxis,rtaxis; Matrix axslp; /* axis slopes */ /* init */ vptr = fptr->vptr; total = & vptr->total; vptr->xhdir &= ~TOKCOD_p; /* discover arrangement of axes on screen */ axslopes( total, axslp ); switch ( vptr->xhdir & TOKCOD_DIR ) { case TOKCOD_Z: rtaxis = MOSTER( XX, YY, XX ); upaxis = MOSTER( XX, YY, YY ); if ( (rtaxis & TOKCOD_DIR) == XX ) vptr->xhdir |= TOKCOD_p; break; case TOKCOD_X: rtaxis = MOSTER( YY, ZZ, XX ); upaxis = MOSTER( YY, ZZ, YY ); if ( (rtaxis & TOKCOD_DIR) == YY ) vptr->xhdir |= TOKCOD_p; break; case TOKCOD_Y: rtaxis = MOSTER( XX, ZZ, XX ); upaxis = MOSTER( XX, ZZ, YY ); if ( (rtaxis & TOKCOD_DIR) == ZZ ) vptr->xhdir |= TOKCOD_p; break; } fptr->xsign = (rtaxis & TOKCOD_p) ? 1 : -1; fptr->ysign = (upaxis & TOKCOD_p) ? 1 : -1; } @//E*O*F xh.c// chmod u=rw,g=r,o=r xh.c echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 257 905 6488 boxobj.c 289 786 5896 boxview.c 186 523 4071 manip.c 602 1530 12654 rotate.c 662 1719 13891 view.c 455 1231 10431 xh.c 2451 6694 53431 total !!! wc boxobj.c boxview.c manip.c rotate.c view.c xh.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0 #------------------- cut this line and below ---------------------- -- -- Kelvin Thompson, Lone Rider of the Apocalypse kelvin@cs.utexas.edu {...,uunet}!cs.utexas.edu!kelvin