home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / source / devel5 / keyboard.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-14  |  43.5 KB  |  2,093 lines

  1. /* Keyboard routines */
  2.  
  3. /* Written by Bernie Roehl, July 1992 */
  4.  
  5. /* Copyright 1992 by Dave Stampe and Bernie Roehl.
  6.    May be freely used to write software for release into the public domain;
  7.    all commercial endeavours MUST contact Bernie Roehl and Dave Stampe
  8.    for permission to incorporate any part of this software into their
  9.    products!
  10.  
  11.      ATTRIBUTION:  If you use any part of this source code or the libraries
  12.      in your projects, you must give attribution to REND386, Dave Stampe,
  13.      and Bernie Roehl in your documentation, source code, and at startup
  14.      of your program.  Let's keep the freeware ball rolling!
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>  /* for atol(), only for debugging! */
  19. #include <dos.h>
  20. #include <time.h>    /* time(), ctime() */
  21. #include <string.h>
  22. #include <math.h>
  23. #include <alloc.h>
  24.  
  25. #include "config.h"
  26. #include "rend386.h"
  27. #include "intmath.h"
  28. #include "plg.h"
  29. #include "segio.h"
  30. #include "pointer.h"
  31. #include "userint.h"
  32. #include "splits.h"
  33. #include "cursor.h"
  34.  
  35.  
  36. extern char goodbye();
  37.  
  38. extern char *fix_fname(char *fname);
  39.  
  40. extern STEREO default_stereo;
  41. extern manip_2D_avail;
  42.  
  43. extern int sl_xflip, sl_xoff;
  44. extern long sl_left, sl_top, sl_right, sl_bottom;
  45. extern int sr_xflip, sr_xoff;
  46. extern long sr_left, sr_top, sr_right, sr_bottom;
  47. extern float sl_xrot, sr_xrot;
  48.  
  49. int use_old_keys = 0;
  50. extern long latitude,longitude,center_roll;
  51. extern long center_x,center_y,center_z,center_d;
  52.  
  53. extern char *progname;
  54.  
  55. extern OBJECT *where_split_screen_pt(int *pol, int *vert, int x, int y);
  56.  
  57. extern int redraw, review, reframe, running, do_horizon;
  58. extern OBJLIST *objlist;
  59. extern int stereo_type;
  60. extern int fancy_background, reflection_pool, show_logo, do_screen_clear;
  61. extern VIEW default_view, orig_view, *current_view, *current_home_view;
  62. extern VIEW real_view;
  63. extern STEREO default_stereo;
  64. extern SPLIT *split_tree;
  65. extern unsigned lastkey;
  66. extern unsigned paint;
  67. extern int show_location, show_compass, show_framerate;
  68.  
  69.  
  70. static int sstepsize = 10;    /* speed multipliers */
  71. static int astepsize = 2;
  72.  
  73.  
  74. long anglestep = 160000L;
  75. long spacestep = 10L;
  76.  
  77. int spinmode = 0;
  78. int flymode = 0;
  79. int floormode = 0;
  80. int animatemode = 1;
  81.  
  82. extern int old_angle_order;  /* in wparse.c */
  83.  
  84. /******************* MENU TEXT **************/
  85.  
  86. char *helptext[] = {
  87.     "X calls up MAIN MENU",
  88.     "O calls up OBJECT MENU",
  89.     "P calls up PAINT MENU",
  90.     "F calls up FIGURE MENU",
  91.     "V calls up VIEW MENU",
  92.     "M calls up MANIPULATE MENU",
  93.     "D calls up DISPLAY OPTIONS MENU",
  94.     "ARROWS drive around",
  95.     "RIGHT SHIFT+ARROWS look around",
  96.     "LEFT SHIFT+ARROWS  move up, sideways",
  97.     "CTRL+ARROWS  set stereo offset",
  98.     "J toggles mouse motion, U u-turns",
  99.     "+ and - changes zoom",
  100.     "R repeats last arrow key move 100x",
  101.     "0-9 set step or angle size",
  102.     "F1-F10 select viewpoint",
  103.     "HOME returns to starting point",
  104.     "Q or ESC quits, ? or H shows help",
  105.     "I displays view information",
  106.     "S sets/resets object spin mode",
  107.     "C displays color palette",
  108.     "A toggles animation on/off",
  109.     NULL
  110. };
  111.  
  112. char *mainmenu[] = {
  113.     "Help",
  114.     "Information",
  115.     "View menu",
  116.     "Paint menu",
  117.     "Display menu",
  118.     "Object menu",
  119.     "Figure menu",
  120.     "Mouse menu",
  121.     "Quit",
  122.     NULL
  123. };
  124.  
  125. char *viewmenu[] = {
  126.     "Information",
  127.     "Spin about object",
  128.     "Fly mode toggle",
  129.     "fLoor mode toggle",
  130.     "Return to start",
  131.     "Move step size",
  132.     "Turn step set",
  133.     "Go to (x,y,z) location",
  134.     "look Angle ",
  135.     "View window size",
  136.     "Hither clipping depth",
  137.     "Yon clipping depth",
  138.     "PCX screen dump",
  139.     "Options",
  140. #ifdef ENABLE_STATE_SAVELOAD
  141.     "Write state to file",
  142.     "eXecute world file",
  143. #endif
  144.     NULL
  145. };
  146.  
  147. static char *paintmenu[] = {
  148.     "Select Surface",
  149.     "Choose Color",
  150.     "Get poly color",
  151.     "Paint Polys",
  152.     "paint All",
  153.     "Resurface",
  154.     NULL
  155. };
  156.  
  157. static char *surfmenu[] = {
  158.     "Absolute",
  159.     "Cosine-lit",
  160.     "Metal",
  161.     "Glass",
  162.     NULL
  163. };
  164.  
  165. static char *optmenu[] = {
  166.     "aniMation on/off",
  167.     "Background",
  168.     "Reflection",
  169.     "Screen clear",
  170.     "Horizon",
  171.     "Ambient light",
  172.     "Directional light",
  173.     "Position display",
  174.     "Compass display",
  175.     "Frame rate display",
  176.     NULL };
  177.  
  178. static char *mousemenu[] = {
  179.     "Move",
  180.     "Rotate",
  181.     "Twirl",
  182.     "Grasp",
  183.     "Ungrasp",
  184.     NULL
  185. };
  186.  
  187. static char *objmenu[] = {
  188.     "Load object",
  189.     "Save object",
  190.     "Information",
  191.     "Delete object",
  192.     "Unselect all",
  193.     "First representation",
  194.     "Next representation",
  195.     NULL
  196. };
  197.  
  198. static char *figmenu[] = {
  199.     "Load figure",
  200.     "Information",
  201.     "Select all",
  202.     "Unselect all",
  203.     "Hack off",
  204.     "Join to",
  205.     "Attach viewpoint",
  206.     "Detach viewpoint",
  207.     NULL
  208. };
  209.  
  210.  
  211. /************************ KEY SUPPORT **************/
  212.  
  213. #define F1  0x3B00
  214. #define F2  0x3C00
  215. #define F3  0x3D00
  216. #define F4  0x3E00
  217. #define F5  0x3F00
  218. #define F6  0x4000
  219. #define F7  0x4100
  220. #define F8  0x4200
  221. #define F9  0x4300
  222. #define F10 0x4400
  223.  
  224. #define HOME      0x4700
  225. #define END       0x4F00
  226. #define PGUP      0x4900
  227. #define PGDN      0x5100
  228.  
  229. #define LEFT      0x4B00
  230. #define RIGHT     0x4D00
  231. #define UP        0x4800
  232. #define DOWN      0x5000
  233.  
  234. #define SHLEFT    0x4B01
  235. #define SHRIGHT   0x4D01
  236. #define SHUP      0x4801
  237. #define SHDOWN    0x5001
  238. #define ASHLEFT   0x3401
  239. #define ASHRIGHT  0x3601
  240. #define ASHUP     0x3801
  241. #define ASHDOWN   0x3201
  242.  
  243. #define LSHLEFT   0x4B02
  244. #define LSHRIGHT  0x4D02
  245. #define LSHUP     0x4802
  246. #define LSHDOWN   0x5002
  247. #define ALSHLEFT  0x3402
  248. #define ALSHRIGHT 0x3602
  249. #define ALSHUP    0x3802
  250. #define ALSHDOWN  0x3202
  251.  
  252. #define SHPGUP    0x4901
  253. #define SHPGDN    0x5101
  254.  
  255. #define CTRLLEFT  0x7300
  256. #define CTRLRIGHT 0x7400
  257.  
  258. #define CTRLHOME  0x7700
  259. #define CTRLEND   0x7500
  260. #define CTRLPGUP  0x8400
  261. #define CTRLPGDN  0x7600
  262.  
  263. #define ESC       0x001B
  264. #define TAB       0x0009
  265.  
  266. /*************** STATUS DISPLAYS ETC. ************/
  267.  
  268.  
  269. void compute_vpoint(long *x, long *y, long *z, long dist)
  270. {
  271.     MATRIX n;
  272.  
  273.     *x = 0;
  274.     *y = 0;
  275.     *z = dist;
  276.  
  277.     view_to_matrix(&real_view, n);
  278.  
  279.     matrix_point(n,x,y,z);
  280. }
  281.  
  282. static void center(char *s, int w)
  283. {
  284.     int n;
  285.  
  286.     if (strlen(s) == 0) return;
  287.     n = (w - strlen(s)) /2;
  288.     memmove(&s[n], s, strlen(s)+1);
  289.     memset(s, ' ', n);
  290. }
  291.  
  292. static int nobjs, nverts, npolys;
  293.  
  294. void gather_data(OBJECT *obj)
  295. {
  296.     int nv = 0, np = 0;
  297.  
  298.     get_obj_info(obj, &nv, &np);
  299.     ++nobjs;
  300.     nverts += nv;
  301.     npolys += np;
  302. }
  303.  
  304. extern VIEW real_view;
  305.  
  306. disp_status(VIEW *v)
  307. {
  308.     char *text[10], a[80], b[80], c[80], d[80], e[80], f[80], g[80], h[80];
  309.     int w, i;
  310.     long x, y, z;
  311.     real_viewpoint(v, &x, &y, &z);
  312.  
  313.     text[0] = a;
  314.     text[1] = "";
  315.     text[2] = b;
  316.     text[3] = c;
  317.     text[4] = d;
  318.     text[5] = e;
  319.     text[6] = f;
  320.     text[7] = g;
  321.     text[8] = h;
  322.     text[9] = NULL;
  323.     sprintf(a, "STATUS");
  324.  
  325.     sprintf(b, "X = %ld  Y = %ld  Z = %ld", x, y, z);
  326.     w = strlen(b);
  327.  
  328.     if (old_angle_order)
  329.         sprintf(c, "Pan = %ld   Tilt = %ld   Roll = %ld  ", v->pan/65536L, v->tilt/65536L, v->roll/65536L);
  330.     else
  331.         sprintf(c, "Tilt = %ld   Pan = %ld   Roll = %ld  ", v->tilt/65536L, v->pan/65536L, v->roll/65536L);
  332.  
  333.     if (strlen(c) > w) w = strlen(c);
  334.     sprintf(d, "Zoom = %2.2f", v->zoom/65536.0);
  335.     if (strlen(d) > w) w = strlen(d);
  336.     sprintf(e, "Hither = %ld  Yon = %ld", v->hither, v->yon);
  337.     if (strlen(e) > w) w = strlen(e);
  338.  
  339.     nobjs = 0, nverts = 0, npolys = 0;
  340.     walk_split_tree(split_tree, gather_data);
  341.     sprintf(f, "%d object%s, %d vertice%s, %d poly%s", nobjs,
  342.     (nobjs == 1) ? "" : "s", nverts, (nverts == 1) ? "" : "s",
  343.     npolys, (npolys == 1) ? "" : "s");
  344.     sprintf(g, "Ambient light: %d", current_view->ambient);
  345.     sprintf(h, "Memory Free: %ld", coreleft());
  346.  
  347.     if (strlen(f) > w) w = strlen(f);
  348.     if (strlen(g) > w) w = strlen(g);
  349.     if (strlen(h) > w) w = strlen(h);
  350.  
  351.     for (i = 0; text[i]; ++i) center(text[i], w);
  352.     poptext(text);
  353.     reframe = 1;
  354.     redraw = 1;
  355.     return 0;
  356. }
  357.  
  358.  
  359. void disp_palette(void)
  360. {
  361.     int i, j, page;
  362.     page = cursor_hide();
  363.     for (i = 0; i < 16; i++)
  364.         for (j = 0; j < 16; j++)
  365.             user_box(j*10,i*8,j*10+9,i*8+8,i*16+j);
  366.     cursor_show(page);
  367.     reframe = 1;
  368. }
  369.  
  370. void add_ext(char *name, char *ext)
  371. {
  372.     char *c;
  373.     if(strchr(name, '.')) return;
  374.     c = strchr(name, 0);
  375.     *c++ = '.';
  376.     *c++ = *ext++;
  377.     *c++ = *ext++;
  378.     *c++ = *ext++;
  379.     *c = 0;
  380. }
  381.  
  382. /*************** JOYSTICK NAVIGATION ***************/
  383.  
  384. extern long last_render_time;
  385.  
  386. static int b_spinmap[4] = { 
  387.     1, 1, 1, 3 };
  388.  
  389. do_joy(joystick_data *joy)
  390. {
  391.     int x,y,b;
  392.     long dist;
  393.     long ang;
  394.     int sscale;
  395.     long mx=0, my=0, mz=0;
  396.     MATRIX n;
  397.  
  398.     x = joy->x;
  399.     y = joy->y;
  400.     b = joy->buttons;
  401.     dist = spacestep*sstepsize;
  402.     ang = astepsize*anglestep;
  403.     sscale = last_render_time;
  404.  
  405.  
  406.     if (abs(x) < 10 && abs(y) < 10) return 0;
  407.  
  408.     if (x > 10) x -= 10;
  409.     else
  410.     {
  411.         if (x > -10) x = 0;
  412.         else x += 10;
  413.     }
  414.     if (y > 10) y -= 10;
  415.     else
  416.     {
  417.         if (y > -10) y = 0;
  418.         else y += 10;
  419.     }
  420.     if(spinmode) b=b_spinmap[b];
  421.     ;
  422.     switch (b)
  423.     {
  424.     case 0:/* no buttons down */
  425.         current_view->pan += (x * ang)/600*sscale;
  426.         mz = -(y * dist * sscale)/120L;
  427.         review = redraw = 1;
  428.         break;
  429.  
  430.     case 1:/* first button down */
  431.         current_view->tilt -= (y * ang)/400*sscale;
  432.         current_view->pan += (x * ang)/300*sscale;
  433.         review = redraw = 1;
  434.         break;
  435.  
  436.     case 2:/* second button down */
  437.         mx = -(x * dist * sscale)/120L;
  438.         my = -(y * dist * sscale)/120L;
  439.         review = redraw = 1;
  440.         break;
  441.  
  442.     case 3:/* both buttons down */
  443.         current_view->roll += (x * ang)/1000*sscale;
  444.         current_view->zoom += (y*65536L) /4000*sscale;
  445.         if (stereo_type != MONOSCOPIC)
  446.         {
  447.             compute_stereo_data(&default_stereo, LEFT_EYE, sl_xflip, sl_xoff,
  448.             65536.0*sl_xrot, sl_left, sl_top, sl_right, sl_bottom);
  449.             compute_stereo_data(&default_stereo, RIGHT_EYE, sr_xflip, sr_xoff,
  450.             65536.0*sr_xrot, sr_left, sr_top, sr_right, sr_bottom);
  451.         }
  452.         review = redraw = 1;
  453.         break;
  454.  
  455.     default:
  456.         break;
  457.     }
  458.     if(b!=1)
  459.     {
  460.         if(flymode)
  461.             std_matrix(n,current_view->tilt,current_view->pan,current_view->roll, 0, 0, 0);
  462.         else std_matrix(n, 0, current_view->pan, 0, 0, 0, 0);
  463.         matrix_point(n, &mx, &my, &mz);
  464.         current_view->ex += mx;
  465.         current_view->ey += my;
  466.         current_view->ez += mz;
  467.     }
  468.     return 0;
  469. }
  470.  
  471. /******************* SPINNING VIEW COMPUTE **************/
  472.  
  473. static l_x = 1000, l_y = 15000, l_z = -5000; /* light source */
  474.  
  475. long center_d = 10000;
  476. long center_x = 0;
  477. long center_y = 0;
  478. long center_z = 0;
  479. long latitude = 0;
  480. long longitude = 0;
  481. long center_roll = 0;
  482.  
  483. static long light_d = 1000000;
  484.  
  485. void polar_compute(void) /* for spin mode: recompute viewpoint based on */
  486. { /* view angle and distance so object centered  */
  487.     MATRIX m,n;
  488.  
  489.     long x = 0;
  490.     long y = 0;
  491.     long z = -center_d;
  492.  
  493.     latitude = current_view->pan;
  494.     longitude = current_view->tilt;
  495.     center_roll = current_view->roll;
  496.  
  497.     std_matrix(n,longitude,latitude,center_roll,0,0,0);
  498.     matrix_point(n,&x,&y,&z);
  499.     current_view->ex = x + center_x;
  500.     current_view->ey = y + center_y;
  501.     current_view->ez = z + center_z;
  502.  
  503.     x = l_x;
  504.     y = l_y;
  505.     z = l_z;
  506.  
  507.     matrix_point(n,&x,&y,&z);
  508.     current_view->lx = x;
  509.     current_view->ly = y;
  510.     current_view->lz = z;
  511. }
  512.  
  513.  
  514.  
  515.  
  516. /********************** KEY INTERPERTER *****************/
  517.  
  518. VIEW *all_views[10] = { 
  519.     &default_view,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
  520. VIEW *save_views[10] = { 
  521.     &orig_view ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
  522.  
  523. int mouse_nav = 0;
  524.  
  525. extern PDRIVER *cursor_device;
  526.  
  527. int lastarrowkey = 0;
  528. int oldkey = 0;
  529. static int movemults[] = {
  530.     1,2,3,5,7,10,13,17,22,28};
  531. static int angmults[] = {
  532.     1,1,1,1,2,2,2,3,4,5};
  533.  
  534. do_key(unsigned c)
  535. {
  536.     void joystick_calibration(joystick_data *), *what_area();
  537.     void view_menu(void), mouse_menu(void), stereo_info(void);
  538.     char buff[100];
  539.     FILE *in, *out;
  540.     long x, y, z;
  541.     long mx=0, my=0, mz=0;
  542.     int i, j;
  543.     MATRIX m,n;
  544.  
  545.     if (check_key(c)) return 0;
  546.     if(c<0x7f)if(isalpha(c)) c = toupper(c);
  547.     oldkey = c;
  548.  
  549.     switch (c)
  550.     {
  551.     case LEFT:
  552.     case SHLEFT:
  553.     case ASHLEFT:
  554.         current_view->pan -= astepsize * anglestep;
  555.         goto arrow_exit;
  556.     case RIGHT:
  557.     case SHRIGHT:
  558.     case ASHRIGHT:
  559.         current_view->pan += astepsize * anglestep;
  560.         goto arrow_exit;
  561.     case UP:
  562.         if (spinmode) current_view->tilt += astepsize * anglestep;
  563.         else
  564.             {
  565.             mz = 2;
  566.             /*current_view->ex += m_mult(sstepsize*spacestep*2, isine(current_view->pan));
  567.                    current_view->ez += m_mult(sstepsize*spacestep*2, icosine(current_view->pan)); */
  568.             goto move_arrow;
  569.         }
  570.         goto arrow_exit;
  571.     case DOWN:
  572.         if (spinmode) current_view->tilt -= astepsize * anglestep;
  573.         else
  574.             {
  575.             mz = -2;
  576.             /*       current_view->ex -= m_mult(sstepsize*spacestep*2, isine(current_view->pan));
  577.                    current_view->ez -= m_mult(sstepsize*spacestep*2, icosine(current_view->pan)); */
  578.             goto move_arrow;
  579.         }
  580.         goto arrow_exit;
  581. move_arrow:
  582.         {
  583.             MATRIX n;
  584.  
  585.             if(flymode)
  586.                 std_matrix(n,current_view->tilt,current_view->pan,current_view->roll, 0, 0, 0);
  587.             else std_matrix(n, 0, current_view->pan, 0, 0, 0, 0);
  588.             if(mx) mx *= sstepsize*spacestep;
  589.             if(my) my *= sstepsize*spacestep;
  590.             if(mz) mz *= sstepsize*spacestep;
  591.             matrix_point(n, &mx, &my, &mz);
  592.             current_view->ex += mx;
  593.             current_view->ey += my;
  594.             current_view->ez += mz;
  595.         }
  596. arrow_exit:
  597.         review = redraw = 1;
  598.         lastarrowkey = c;
  599.         break;
  600.  
  601.     case SHDOWN:
  602.     case ASHDOWN:
  603.         current_view->tilt += (astepsize * anglestep);
  604.         goto arrow_exit;
  605.     case SHUP:
  606.     case ASHUP:
  607.         current_view->tilt -= (astepsize * anglestep);
  608.         goto arrow_exit;
  609.  
  610.     case LSHLEFT:
  611.     case ALSHLEFT:
  612.         mx = -1;
  613.         /*current_view->ex -= m_mult(sstepsize*spacestep, icosine(current_view->pan));
  614.              current_view->ez += m_mult(sstepsize*spacestep, isine(current_view->pan));*/
  615.         goto move_arrow;
  616.     case LSHRIGHT:
  617.     case ALSHRIGHT:
  618.         mx = 1;
  619.         /* current_view->ex += m_mult(sstepsize*spacestep, icosine(current_view->pan));
  620.              current_view->ez -= m_mult(sstepsize*spacestep, isine(current_view->pan)); */
  621.         goto move_arrow;
  622.     case PGUP:
  623.     case LSHUP:
  624.     case ALSHUP:
  625.         my = 1;
  626.         /*     current_view->ey += spacestep*sstepsize ; */
  627.         goto move_arrow;
  628.     case LSHDOWN:
  629.     case ALSHDOWN:
  630.     case PGDN:
  631.         my = -1;
  632.         /*     current_view->ey -= spacestep*sstepsize ;  */
  633.         goto move_arrow;
  634.  
  635.     case CTRLPGUP:
  636.         current_view->roll -= astepsize * anglestep>>2;
  637.         goto arrow_exit;
  638.     case CTRLPGDN:
  639.         current_view->roll += astepsize * anglestep>>2;
  640.         goto arrow_exit;
  641.  
  642.     case CTRLLEFT:
  643.         if (sl_xflip) sl_xoff++;
  644.         else sl_xoff--;
  645.         if (sr_xflip) sr_xoff--;
  646.         else sr_xoff++;
  647.         goto stereo_recompute;
  648.     case CTRLRIGHT:
  649.         if (sl_xflip) sl_xoff--;
  650.         else sl_xoff++;
  651.         if (sr_xflip) sr_xoff++;
  652.         else sr_xoff--;
  653.         goto stereo_recompute;
  654.  
  655.     case '*':   /* level view */
  656.         current_view->tilt = current_view->roll = 0;
  657.         review = redraw = 1;
  658.         break;
  659.     case '+':
  660.         if (stereo_type == MONOSCOPIC)
  661.         {
  662.             current_view->zoom *= 1.1;
  663.             if(current_view->zoom > 16*65536L) current_view->zoom = 16*65536L;
  664.             review = redraw = 1;
  665.             break;
  666.         }
  667.         if(default_stereo.phys_screen_dist>30)
  668.             default_stereo.phys_screen_dist *= 1.05;
  669.         else default_stereo.phys_screen_dist *= 1.25;
  670.         goto stereo_recompute; /* save some code (Dave) */
  671.     case '-':
  672.         if (stereo_type == MONOSCOPIC)
  673.         {
  674.             current_view->zoom /= 1.1;
  675.             if(current_view->zoom < 32000L) current_view->zoom = 32000L;
  676.             review = redraw = 1;
  677.             break;
  678.         }
  679.         default_stereo.phys_screen_dist /= 1.05;
  680.         if(default_stereo.phys_screen_dist<5)
  681.             default_stereo.phys_screen_dist = 5;
  682.         goto stereo_recompute;
  683.  
  684.     case '!':
  685.         if (stereo_type != MONOSCOPIC)
  686.         {
  687.             default_stereo.phys_eye_spacing /= 1.05;
  688.             if(default_stereo.phys_eye_spacing<5)
  689.                 default_stereo.phys_eye_spacing = 5;
  690.             goto stereo_recompute;
  691.         }
  692.         break;
  693.     case '@':
  694.         if (stereo_type != MONOSCOPIC)
  695.         {
  696.             if(default_stereo.phys_eye_spacing>30)
  697.                 default_stereo.phys_eye_spacing *= 1.05;
  698.             else default_stereo.phys_eye_spacing *= 1.25;
  699.         }
  700.         else break;
  701.  
  702. stereo_recompute:
  703.         if (stereo_type != MONOSCOPIC)
  704.         {
  705.             compute_stereo_data(&default_stereo, LEFT_EYE, sl_xflip, sl_xoff,
  706.             65536.0*sl_xrot, sl_left, sl_top, sl_right, sl_bottom);
  707.             compute_stereo_data(&default_stereo, RIGHT_EYE, sr_xflip, sr_xoff,
  708.             65536.0*sr_xrot, sr_left, sr_top, sr_right, sr_bottom);
  709.         }
  710.         review = redraw = 1;
  711.         break;
  712.  
  713.     case '$':
  714.         stereo_info();
  715.         review = redraw = 1;
  716.                 set_goodbye();
  717.         while(!goodbye());
  718.         break;
  719.  
  720.     case 'U':
  721.         current_view->pan += 180*65536L;
  722.         review = redraw = 1;
  723.         break;
  724.  
  725.     case HOME:
  726.         *current_view = *current_home_view;
  727.         review = redraw = 1;
  728.         break;
  729.  
  730.     case '0':
  731.         sstepsize = movemults[9];
  732.         astepsize = angmults[9];
  733.         break;
  734.     case '1':
  735.     case '2':
  736.     case '3':
  737.     case '4':
  738.     case '5':
  739.     case '6':
  740.     case '7':
  741.     case '8':
  742.     case '9':
  743.         sstepsize = movemults[c - '1'];
  744.         astepsize = angmults[c - '1'];
  745.         break;
  746.  
  747.     case 'Q':
  748.     case ESC:
  749.         popmsg("Really quit?");
  750.         set_goodbye();
  751.         while((i=goodbye())==0);
  752.         if (toupper(i)=='Y') running = 0;
  753.         else reframe = redraw = 1;
  754.         break;
  755.  
  756.     case 'R':
  757.         if (lastarrowkey)
  758.             for (i = 0; i < 100; i++)
  759.             {
  760.                 do_key(lastarrowkey);
  761.                 refresh_display();
  762.                 if(kbhit()) break;
  763.             }
  764.         break;
  765.  
  766.     case 'I':
  767.         disp_status(&real_view);
  768.         set_goodbye();
  769.         while(!goodbye());
  770.         reframe = redraw = 1;
  771.         break;
  772.     case 'C':
  773.         disp_palette();
  774.         set_goodbye();
  775.         while(!goodbye());
  776.         reframe = redraw = 1;
  777.         break;
  778.     case 'H':
  779.     case '?':
  780.         poptext(helptext);
  781.         set_goodbye();
  782.         while(!goodbye());
  783.         reframe = redraw = 1;
  784.         break;
  785.     case 'X':
  786.         main_menu();
  787.         reframe = redraw = 1;
  788.         break;
  789.     case 'D':
  790.         disp_options();
  791.         reframe = redraw = 1;
  792.         break;
  793.     case 'O':
  794.         obj_menu();
  795.         reframe = redraw = 1;
  796.         break;
  797.     case 'F':
  798.         fig_menu();
  799.         reframe = redraw = 1;
  800.         break;
  801.     case 'P':
  802.         painting();
  803.         reframe = review = redraw = 1;
  804.         break;
  805.     case 'M':
  806.         mouse_menu();
  807.         reframe = review = redraw = 1;
  808.         break;
  809.     case 'V':
  810.         view_menu();
  811.         reframe = review = redraw = 1;
  812.         break;
  813.     case 'J':
  814.         mouse_nav = !mouse_nav;
  815.         break;
  816.     case 'A':
  817.         animatemode = !animatemode;
  818.         break;
  819.     case TAB:
  820.         if(animatemode==0) animatemode = -1;
  821.         break;
  822.     case 'S':
  823.         if(spinmode) spinmode = 0;
  824.         else
  825.             {
  826.             OBJECT *newobj;
  827.             float dist;
  828.             if (can_point_2D() && manip_2D_avail)
  829.             {
  830.                 int mx, my;
  831.                 refresh_display();
  832.                 popmsg("Click on object to spin about");
  833.                 tdelay(500);
  834.                 reframe = 1;
  835.                 refresh_display();
  836.                 move_till_click(cursor_device, 1, &mx, &my);
  837.                 newobj = where_split_screen_pt(NULL, NULL, mx, my);
  838.                 if(newobj)
  839.                     get_object_bounds(newobj, ¢er_x, ¢er_y, ¢er_z);
  840.             }
  841.             dist = (float)(center_x - current_view->ex) *
  842.                 (float)(center_x - current_view->ex) +
  843.                 (float)(center_y - current_view->ey) *
  844.                 (float)(center_y - current_view->ey) +
  845.                 (float)(center_z - current_view->ez) *
  846.                 (float)(center_z - current_view->ez);
  847. #ifdef SQRTL
  848.             center_d = sqrtl(dist);
  849. #else
  850.             center_d = (long) floor(sqrt((double) dist));
  851. #endif
  852.             spinmode = 1;
  853.         }
  854.         reframe = redraw = 1;
  855.         break;
  856.     case '^':
  857.         save_pcx_file();
  858.         break;
  859.     case F1:
  860.     case F2:
  861.     case F3:
  862.     case F4:
  863.     case F5:
  864.     case F6:
  865.     case F7:
  866.     case F8:
  867.     case F9:
  868.     case F10:
  869.         i = (c- F1) >> 8;
  870.         if(all_views[i])
  871.         {
  872.             current_view = all_views[i];
  873.             current_home_view = save_views[i];
  874.         }
  875.         if (stereo_type != MONOSCOPIC)
  876.         {
  877.             compute_stereo_data(&default_stereo, LEFT_EYE, sl_xflip, sl_xoff,
  878.             65536.0*sl_xrot, sl_left, sl_top, sl_right, sl_bottom);
  879.             compute_stereo_data(&default_stereo, RIGHT_EYE, sr_xflip, sr_xoff,
  880.             65536.0*sr_xrot, sr_left, sr_top, sr_right, sr_bottom);
  881.         }
  882.         reframe = redraw = 1;
  883.         break;
  884.  
  885.     default:
  886.         break;
  887.     }
  888.     return 0;
  889. }
  890.  
  891.  
  892. /*************** VIEW MENU *************/
  893.  
  894. void view_menu(void)
  895. {
  896.     char buff[100], *p;
  897.     FILE *out;
  898.     char d;
  899.  
  900.     switch (menu(viewmenu))
  901.     {
  902.     case 'I':
  903.         do_key('I');
  904.         break;
  905.     case 'R':
  906.         do_key (HOME);
  907.         break;
  908.     case 'P':
  909.         do_key('^');
  910.         break;
  911.     case 'F':
  912.         flymode = !flymode;
  913.         popmsg(flymode ? "Fly mode" : "Ground mode");
  914.         tdelay(350);
  915.         break;
  916.     case 'L':
  917.         floormode = !floormode;
  918.         popmsg(floormode ? "Floors used" : "Floors ignored");
  919.         tdelay(350);
  920.         break;
  921.     case 'H':
  922.         askfor("Enter hither value:", buff, 10);
  923.         if (buff[0])
  924.             current_view->hither = atof(buff);
  925.         if (current_view->hither < 1) current_view->hither = 1;
  926.         review = 1;
  927.         reframe = redraw = 1;
  928.         break;
  929.     case 'Y':
  930.         askfor("Enter yon value:", buff, 10);
  931.         if (buff[0]) current_view->yon = atof(buff);
  932.         review = 1;
  933.         reframe = redraw = 1;
  934.         break;
  935.     case 'G':/* goto XYZ */
  936.         askfor("X,Y,Z: ", buff, 25);
  937.         if (buff[0])
  938.             sscanf(buff, "%ld,%ld,%ld", ¤t_view->ex, ¤t_view->ey, ¤t_view->ez);
  939.         reframe = review = redraw = 1;
  940.         break;
  941.     case 'A':/* look at angle */
  942.         {
  943.             long p, t, r;
  944.             askfor("Pan,tilt,roll:", buff, 22);
  945.             if (buff[0])
  946.                 sscanf(buff, "%ld,%ld,%ld", &p, &t, &r);
  947.             current_view->pan = p*65536L;
  948.             current_view->tilt = t*65536L;
  949.             current_view->roll = r*65536L;
  950.             reframe = review = redraw = 1;
  951.         }
  952.         break;
  953.     case 'M':
  954.         askfor("Move step: ", buff, 15);
  955.         if (buff[0]) spacestep = atoi(buff);
  956.         review = redraw = 1;
  957.         break;
  958.     case 'T':
  959.         askfor("Turn angle step: ", buff, 15);
  960.         if (buff[0]) anglestep = atof(buff) * 65536L;
  961.         review = redraw = 1;
  962.         break;
  963.     case 'V':
  964.         resize_viewport();
  965.         reframe = review = redraw = 1;
  966.         break;
  967.     case 'O':
  968.         disp_options();
  969.         reframe = redraw = 1;
  970.         break;
  971.     case 'S':
  972.         do_key('S');
  973.         break;
  974. #ifdef ENABLE_STATE_SAVELOAD
  975.     case 'W':
  976.         save_state();
  977.         review = redraw = 1;
  978.         break;
  979.     case 'X':
  980.         load_state();
  981.         review = redraw = 1;
  982.         break;
  983. #endif
  984.     default:
  985.         break;
  986.     }
  987. }
  988.  
  989.  
  990. void stereo_info(void)
  991. {
  992.     char b1[50]="", b2[50]="", b3[50]="", b4[50]="", b5[50]="", b6[50]="";
  993.     char b7[50]="", b8[50]="", b9[50]="";
  994.     char *b[10];
  995.     SEGMENT *s;
  996.     long x,y,z;
  997.  
  998.     float xo, xa, conv, ws;
  999.  
  1000.     if(stereo_type==MONOSCOPIC) return;
  1001.  
  1002.     xa = (sl_xoff-sr_xoff)/2.0;
  1003.     ws = default_stereo.world_scaling/65536.0;
  1004.     xo=(default_stereo.phys_eye_spacing*default_stereo.phys_screen_dist*default_stereo.pixel_width) /
  1005.         (2.0*default_stereo.phys_screen_width*default_stereo.phys_convergence);
  1006.     conv =(default_stereo.phys_eye_spacing*default_stereo.phys_screen_dist*default_stereo.pixel_width) /
  1007.         (2.0*default_stereo.phys_screen_width*(xo+xa));
  1008.  
  1009.     b[0] = b1;
  1010.     sprintf(b1, "Stereo Parameters");
  1011.     b[1] = b2;
  1012.     sprintf(b2, "screen distance: %ld", default_stereo.phys_screen_dist);
  1013.     b[2] = b3;
  1014.     sprintf(b3, "screen width:    %ld", default_stereo.phys_screen_width);
  1015.     b[3] = b4;
  1016.     sprintf(b4, "pixel width:     %ld", default_stereo.pixel_width);
  1017.     b[4] = b5;
  1018.     sprintf(b5, "eye spacing:     %ld", default_stereo.phys_eye_spacing);
  1019.     b[5] = b6;
  1020.     sprintf(b6, "convergence distance:    %ld", default_stereo.phys_convergence);
  1021.     b[6] = b7;
  1022.     sprintf(b7, "world scaling:   %3.1f", ws);
  1023.     b[7] = b8;
  1024.     sprintf(b8, "added horizontal offset: %4.0f", xa);
  1025.     b[8] = b9;
  1026.     sprintf(b9, "effective convergence:   %4.0f", conv);
  1027.     b[9] = NULL;
  1028.  
  1029.     poptext(b);
  1030. }
  1031.  
  1032.  
  1033. /************* PROCESS SUPPORT ***********/
  1034.  
  1035. int nselected = 0;
  1036. SEGMENT *last_figure;
  1037.  
  1038. FILE *save_file = NULL;
  1039.  
  1040. int nsaved = 0;
  1041.  
  1042. void save_it(OBJECT *obj)
  1043. {
  1044.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1045.     {
  1046.         if(nselected<2) save_plg(obj, save_file, 0); /* only one: save object coords */
  1047.         else save_plg(obj, save_file, 1); /* else save world coords */
  1048.     }
  1049. }
  1050.  
  1051. static long mxosize = 0;
  1052.  
  1053. void maxsize_it(OBJECT *obj)
  1054. {
  1055.     long s, j;
  1056.     if(obj)
  1057.     {
  1058.         s = get_object_bounds(obj, &j, &j, &j);
  1059.         if(s>mxosize) mxosize = s;
  1060.     }
  1061. }
  1062.  
  1063.  
  1064. void hilite_it(OBJECT *obj)
  1065. {
  1066.     set_obj_flags(obj, get_obj_flags(obj) | OBJ_HIGHLIGHTED);
  1067.     highlight_obj(obj);
  1068. }
  1069.  
  1070.  
  1071. void walk_segtree(SEGMENT *s, void (*f)())
  1072. {
  1073.     SEGMENT *p;
  1074.     OBJECT *obj;
  1075.     if ((obj = seg_get_object(s)) != NULL) f(obj);
  1076.     for (p = child_segment(s); p; p = sibling_segment(p))
  1077.         walk_segtree(p, f);
  1078. }
  1079.  
  1080. void select_tree(SEGMENT *s)
  1081. {
  1082.     SEGMENT *p;
  1083.     OBJECT *obj;
  1084.     if ((obj = seg_get_object(s)) != NULL) highlight_obj(obj);
  1085.     for (p = child_segment(s); p; p = sibling_segment(p))
  1086.         select_tree(p);
  1087. }
  1088.  
  1089. void count_tree(SEGMENT *s, int *nsegs, int *nverts, int *npolys)
  1090. {
  1091.     SEGMENT *p;
  1092.     OBJECT *obj;
  1093.     ++*nsegs;
  1094.     if ((obj = seg_get_object(s)) != NULL)
  1095.     {
  1096.         int nv, np;
  1097.         get_obj_info(obj, &nv, &np);
  1098.         *nverts += nv;
  1099.         *npolys += np;
  1100.     }
  1101.     for (p = child_segment(s); p; p = sibling_segment(p))
  1102.         count_tree(p, nsegs, nverts, npolys);
  1103. }
  1104.  
  1105. static void zap_obj(OBJECT *obj)
  1106. {
  1107.     remove_from_objlist(obj);
  1108.     delete_obj(obj);
  1109. }
  1110.  
  1111.  
  1112. extern SEGMENT *body_seg;
  1113. extern SEGMENT *head_seg;
  1114. extern SEGMENT *wrist_seg;
  1115.  
  1116. static int bodyfound;
  1117.  
  1118. static void checkbody(SEGMENT *s)
  1119. {
  1120.     SEGMENT *p; /* recursive test if view attached to object */
  1121.     if (s == body_seg)
  1122.     {
  1123.         bodyfound = 1;
  1124.         return;
  1125.     }
  1126.     for (p = child_segment(s); p; p = sibling_segment(p)) checkbody(p);
  1127. }
  1128.  
  1129. void grab_it(OBJECT *obj)
  1130. {
  1131.     SEGMENT *s, *r;
  1132.  
  1133.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1134.     {
  1135.         if((s=get_object_owner(obj))!=NULL) /* make sure no loops develop */
  1136.         {
  1137.             bodyfound = 0;
  1138.             checkbody(find_root_segment(s));
  1139.             if(bodyfound) return;
  1140.  
  1141.             while((r=parent_segment(s))!=NULL)
  1142.             {
  1143.                 if(r==body_seg) return;
  1144.                 s = r;
  1145.             }
  1146.             if(s==head_seg || s==wrist_seg) return; /* legal to detach? */
  1147.             attach_segment(s, body_seg);
  1148.         }
  1149.     }
  1150. }
  1151.  
  1152. void ungrab_it(OBJECT *obj)
  1153. {
  1154.     SEGMENT *s, *r;
  1155.  
  1156.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED) /* selected? */
  1157.     {
  1158.         if((s=get_object_owner(obj))!=NULL) /* segment? */
  1159.         {
  1160.             while((r=parent_segment(s))!=NULL)
  1161.             {
  1162.                 if(r==body_seg) goto got_it;
  1163.                 s = r;
  1164.             }
  1165.             return;
  1166. got_it:
  1167.             if(s==head_seg || s==wrist_seg) return; /* legal to detach? */
  1168.             detach_segment(s);
  1169.         }
  1170.     }
  1171. }
  1172.  
  1173. static long centx, centy, centz;
  1174.  
  1175. void count_selected(OBJECT *obj)
  1176. {
  1177.     long x, y, z;
  1178.     SEGMENT *s;
  1179.  
  1180.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1181.     {
  1182.         ++nselected;
  1183.         get_object_bounds(obj, ¢x, ¢y, ¢z);
  1184.         if((s=get_object_owner(obj))!=NULL)
  1185.         {
  1186.             last_figure = s;
  1187.             seg_getjointang(s,&x, &y, &z);
  1188.         }
  1189.     }
  1190. }
  1191.  
  1192.  
  1193. int nobjs = 0, nverts = 0, npolys = 0;
  1194.  
  1195. void gather_info(OBJECT *obj)
  1196. {
  1197.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1198.     {
  1199.         int nv, np;
  1200.         ++nobjs;
  1201.         get_obj_info(obj, &nv, &np);
  1202.         nverts += nv;
  1203.         npolys += np;
  1204.     }
  1205. }
  1206.  
  1207.  
  1208. long ptx, pty, ptz;
  1209. long oldx, oldy, oldz, oldcx, oldcy, oldcz, dx, dy, dz;
  1210.  
  1211. void move_it(OBJECT *obj)
  1212. {
  1213.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1214.     {
  1215.         SEGMENT *s;
  1216.         if ((s = get_object_owner(obj)) != NULL)
  1217.         {
  1218.             rel_move_segment(s, ptx - oldx, pty - oldy, ptz - oldz);
  1219.             update_segment(s);
  1220.         }
  1221.     }
  1222. }
  1223.  
  1224. void twirl_it(OBJECT *obj)
  1225. {
  1226.     int i;
  1227.     long rx, ry, rz;
  1228.  
  1229.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1230.     {
  1231.         SEGMENT *s;
  1232.         if ((s = get_object_owner(obj)) != NULL)
  1233.         {
  1234.             seg_getrxyz(s, &rx, &ry, &rz);
  1235.             abs_rot_segment(s, ptx+rx, pty+ry, ptz+rz, RYXZ);
  1236.             update_segment(s);
  1237.         }
  1238.     }
  1239. }
  1240.  
  1241. void rot_it(OBJECT *obj)
  1242. {
  1243.     int i;
  1244.  
  1245.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1246.     {
  1247.         SEGMENT *s;
  1248.         if ((s = get_object_owner(obj)) != NULL)
  1249.         {
  1250.             rel_rot_segment(s, ptx, pty, ptz, RYXZ);
  1251.             update_segment(s);
  1252.         }
  1253.     }
  1254. }
  1255.  
  1256.  
  1257. void unhi_it(OBJECT *obj)
  1258. {
  1259.     set_obj_flags(obj, get_obj_flags(obj) & ~OBJ_HIGHLIGHTED);
  1260.     unhighlight_obj(obj);
  1261. }
  1262.  
  1263. void hack_it(OBJECT *obj)
  1264. {
  1265.     SEGMENT *s;
  1266.     if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) &&
  1267.         (s = get_object_owner(obj)) != NULL)
  1268.     {
  1269.         detach_segment(s);
  1270.         update_segment(s);
  1271.     }
  1272. }
  1273.  
  1274. SEGMENT *newparent = NULL;
  1275.  
  1276. void join_it(OBJECT *obj)
  1277. {
  1278.     SEGMENT *s;
  1279.     if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED) &&
  1280.         (s = get_object_owner(obj)) != NULL)
  1281.     {
  1282.         attach_segment(s, newparent);
  1283.         update_segment(s);
  1284.     }
  1285. }
  1286.  
  1287. void nuke_it(OBJECT *obj)
  1288. {
  1289.     if ((get_obj_flags(obj) & OBJ_HIGHLIGHTED))
  1290.     {
  1291.         SEGMENT *s;
  1292.         if ((s = get_object_owner(obj)) != NULL)
  1293.             seg_set_object(s, NULL);
  1294.         remove_from_objlist(obj);
  1295.         delete_obj(obj);
  1296.     }
  1297. }
  1298.  
  1299. void next_it(OBJECT *obj)
  1300. {
  1301.     next_rep(obj);
  1302. }
  1303.  
  1304. void first_it(OBJECT *obj)
  1305. {
  1306.     first_rep(obj);
  1307. }
  1308.  
  1309. int check_moveobj(void)
  1310. {
  1311.     nselected = 0;
  1312.     last_figure = NULL;
  1313.  
  1314.     walk_split_tree(split_tree, count_selected);
  1315.     if (last_figure == 0)
  1316.     {
  1317.         popmsg("No movable objects selected!");
  1318.         tdelay(600);
  1319.         return 1;
  1320.     }
  1321.     return 0;
  1322. }
  1323.  
  1324. int check_obj(void)
  1325. {
  1326.     nselected = 0;
  1327.     last_figure = NULL;
  1328.  
  1329.     walk_split_tree(split_tree, count_selected);
  1330.     if (nselected == 0)
  1331.     {
  1332.         popmsg("No objects selected!");
  1333.         tdelay(600);
  1334.         return 1;
  1335.     }
  1336.     return 0;
  1337. }
  1338.  
  1339. void seg_info(int fig)
  1340. {
  1341.     char b1[50]="", b2[50]="", b3[50]="", b4[50]="", b5[50]="", b6[50]="";
  1342.     char *b[7];
  1343.     SEGMENT *s;
  1344.     long x,y,z;
  1345.  
  1346.     b[0] = b1;
  1347.     b[1] = b2;
  1348.     b[2] = b3;
  1349.     b[3] = b4;
  1350.     b[4] = b5;
  1351.     b[5] = b6;
  1352.     b[6] = NULL;
  1353.     nselected = 0;
  1354.     last_figure = NULL;
  1355.     walk_split_tree(split_tree, count_selected);
  1356.     sprintf(b6, "Object center:%ld, %ld, %ld", centx, centy, centz);
  1357.     if(fig && last_figure) last_figure = find_root_segment(last_figure);
  1358.     nobjs = nverts = npolys = 0;
  1359.     if(fig && last_figure)
  1360.     {
  1361.         count_tree(last_figure, &nobjs, &nverts, &npolys);
  1362.         sprintf(b1, "%d seg%s, %d vert%s, %d poly%s",
  1363.         nobjs, (nobjs == 1) ? "" : "s",
  1364.         nverts, (nverts == 1) ? "" : "s",
  1365.         npolys, (npolys == 1) ? "" : "s" );
  1366.     }
  1367.     else
  1368.     {
  1369.         walk_split_tree(split_tree, gather_info);
  1370.         sprintf(b1, "%d obj%s, %d vert%s, %d poly%s",
  1371.         nobjs, (nobjs == 1) ? "" : "s",
  1372.         nverts, (nverts == 1) ? "" : "s",
  1373.         npolys, (npolys == 1) ? "" : "s" );
  1374.     }
  1375.     if(last_figure==NULL)
  1376.     {
  1377.         sprintf(b2," No moveable objects selected");
  1378.         b[2] = b6;
  1379.         b[3] = NULL;
  1380.     }
  1381.     else
  1382.     {
  1383.         seg_getposxyz(last_figure, &x,&y,&z);
  1384.         sprintf(b2, "World pos'n: %ld %ld %ld", x, y, z);
  1385.         seg_getposang(last_figure, &x,&y,&z);
  1386.         sprintf(b3, "World angle: %4.1f %4.1f %4.1f", x/65536.0, y/65536.0, z/65536.0);
  1387.         if(last_figure==NULL || fig==0)
  1388.         {
  1389.             seg_getjointxyz(last_figure, &x,&y,&z);
  1390.             sprintf(b4, "Joint pos'n: %ld %ld %ld", x, y, z);
  1391.             seg_getjointang(last_figure, &x,&y,&z);
  1392.             sprintf(b5, "Joint angle: %4.1f %4.1f %4.1f", x/65536.0, y/65536.0, z/65536.0);
  1393.         }
  1394.         else
  1395.             {
  1396.             b[4] = b6;
  1397.             b[3] = b[2];
  1398.             b[2] = b[1];
  1399.             b[5] = NULL;
  1400.             sprintf(b5,"Root of figure:");
  1401.             b[1] = b5;
  1402.         }
  1403.     }
  1404.     poptext(b);
  1405. }
  1406.  
  1407.  
  1408.  
  1409. /************* MOUSE MANIPULATION MENU ***********/
  1410.  
  1411. extern PDRIVER *cursor_device;
  1412.  
  1413. POINTER pointer;
  1414. extern SEGMENT *light_seg, *light_seg2; /* used for moving lights */
  1415. extern long light2_x, light2_y ,light2_z;
  1416.  
  1417. void mouse_menu(void)
  1418. {
  1419.     void pointer_to_world();
  1420.     char buff[100], *p;
  1421.     char c, d;
  1422.     unsigned buttons;
  1423.     int click = 0;
  1424.  
  1425.     init_pointer(&pointer);
  1426.  
  1427.     switch(c = menu(mousemenu))
  1428.     {
  1429.     case 'M':
  1430.         refresh_display();
  1431.         if(check_moveobj()) break;
  1432.         if (!manip_2D_avail) break;
  1433.         pointer_read(cursor_device, &pointer);
  1434.         pointer_to_world(&pointer, &real_view, &ptx, &pty, &ptz);
  1435.         click = 0;
  1436.         while (click == 0)
  1437.         {
  1438.             if(light_seg2) seg_getposxyz(light_seg2, &light2_x, &light2_y, &light2_z);
  1439.             refresh_display();
  1440.             oldx = ptx;
  1441.             oldy = pty;
  1442.             oldz = ptz;
  1443.             click = PNEW_BUT & pointer_read(cursor_device, &pointer);
  1444.             if (!(pointer.buttons & 1)) click = 0;
  1445.             pointer_to_world(&pointer, &real_view, &ptx, &pty, &ptz);
  1446.             walk_split_tree(split_tree, move_it);
  1447.         }
  1448.         refresh_display();
  1449.         break;
  1450.     case 'R':
  1451.     case 'T':
  1452.         refresh_display();
  1453.         if(check_moveobj()) break;
  1454.         if (!manip_2D_avail) break;
  1455.         pointer_read(cursor_device, &pointer);
  1456.         oldcx = oldx = pointer.x;
  1457.         oldcy = oldy = pointer.y;
  1458.         oldcz = oldz = pointer.z;
  1459.         while ((pointer.buttons & 0x01) == 0)
  1460.         {
  1461.             if (toupper(c) == 'R')
  1462.             {
  1463.                 ptx = 32768L*(pointer.y - oldy);
  1464.                 pty = -32768L*(pointer.x - oldx);
  1465.                 ptz = -32768L*(pointer.z - oldz);
  1466.             }
  1467.             else
  1468.             {
  1469.                 ptx = 3270L*(pointer.y - oldcy);
  1470.                 pty = -3270L*(pointer.x - oldcx);
  1471.                 ptz = -3270L*(pointer.z - oldcz);
  1472.             }
  1473.             rotate_to_view(&real_view, &ptx, &pty, &ptz);
  1474.             if(toupper(c)=='R') walk_split_tree(split_tree, rot_it);
  1475.             else walk_split_tree(split_tree, twirl_it);
  1476.             oldx = pointer.x;
  1477.             oldy = pointer.y;
  1478.             oldz = pointer.z;
  1479.             refresh_display();
  1480.             pointer_read(cursor_device, &pointer);
  1481.         }
  1482.  
  1483.         while (pointer.buttons & 0x01) pointer_read(cursor_device, &pointer);
  1484.         refresh_display();
  1485.         break;
  1486.     case 'G':
  1487.         if(check_moveobj()) break;
  1488.         walk_split_tree(split_tree, grab_it);
  1489.         break;
  1490.     case 'U':
  1491.         if(check_moveobj()) break;
  1492.         walk_split_tree(split_tree, ungrab_it);
  1493.         break;
  1494.     default:
  1495.         break;
  1496.     }
  1497. }
  1498.  
  1499. static unsigned sortflag;
  1500.  
  1501. static void sortflag_it(OBJECT *obj)
  1502.     {
  1503.     set_object_sorting(obj, sortflag);
  1504.     }
  1505.  
  1506. int obj_menu(void)
  1507. {
  1508.     char buff[100], *p;
  1509.     FILE *in, *out;
  1510.     char c, d;
  1511.     long x, y, z;
  1512.         int i;
  1513.  
  1514.     nselected = 0;
  1515.     last_figure = NULL;
  1516.  
  1517.     switch (c=menu(objmenu))
  1518.     {
  1519.     case 'L':/* load PLG file */
  1520.         askfor("File to load? ", buff, 22);
  1521.         if (buff[0] == '\0')
  1522.         {
  1523.             redraw = 1;
  1524.             break;
  1525.         }
  1526.         strcpy(buff, fix_fname(buff));
  1527.         add_ext(buff,"plg");
  1528.         if ((in = fopen(buff, "r")) == NULL)
  1529.         {
  1530.             popmsg("Could not open file");
  1531.             set_goodbye();
  1532.             while(!goodbye());
  1533.         }
  1534.         else
  1535.             {
  1536.             OBJECT *obj;
  1537.             SEGMENT *s;
  1538.             long sx = 1, sy = 1, sz = 1;
  1539. #ifdef ENABLE_RESIZE_ON_LOAD
  1540.             askfor("Scale x,y,z: ", buff, 20);
  1541.             if (buff[0])
  1542.                 sscanf(buff, "%ld,%ld,%ld", &sx, &sy, &sz);
  1543.             if (sx == 0) sx = 1;  if (sy == 0) sy = 1;  if (sz == 0) sz = 1;
  1544. #endif
  1545.             set_loadplg_offset(0,0,0);
  1546.             set_loadplg_scale(sx, sy, sz);
  1547.             obj = load_multi_plg(in);
  1548.             if (load_err) {
  1549.                 popmsg(plg_errmsgs[-load_err]);
  1550.                 reframe = redraw = 1;
  1551.                 break;
  1552.             }
  1553.             select_representation(obj, 0L);
  1554.             add_obj_to_split_area(split_tree, obj);
  1555.             if ((s = new_seg(NULL)) == NULL)
  1556.             {
  1557.                 popmsg("Warning -- out of memory!");
  1558.                 set_goodbye();
  1559.                 while(!goodbye());
  1560.             }
  1561.             else
  1562.                 {
  1563.                 seg_set_object(s, obj);
  1564.                 set_object_owner(obj, s);
  1565.                 mxosize = 0;
  1566.                 walk_segtree(s, maxsize_it);
  1567.                 compute_vpoint(&x, &y, &z, 500+mxosize*2);
  1568.                 abs_move_segment(s, x, y, z);
  1569.                 update_segment(s);
  1570.             }
  1571.         /*    if (spacestep < get_object_bounds(obj, &x, &y, &z)/5L)
  1572.                 spacestep = get_object_bounds(obj, &x, &y, &z)/5L; */
  1573.             fclose(in);
  1574.         }
  1575.         reframe = redraw = 1;
  1576.         break;
  1577.     case 'S':
  1578.         refresh_display();
  1579.         if(check_obj()) break;
  1580.         if (askfor("Enter filename: ", buff, 20) == 0x1B) break;
  1581.         if (buff[0] == '\0')
  1582.         {
  1583.             reframe = redraw = 1;
  1584.             break;
  1585.         }
  1586.         nobjs = 0;
  1587.         add_ext(buff,"plg");
  1588.         if ((save_file = fopen(buff, "w")) == NULL)
  1589.         {
  1590.             popmsg("Could not create file");
  1591.             reframe = 1;
  1592.             set_goodbye();
  1593.             while(!goodbye());
  1594.             break;
  1595.         }
  1596.         nsaved = 0;
  1597.         walk_split_tree(split_tree, save_it);
  1598.         fclose(save_file);
  1599.         save_file = NULL;
  1600.         refresh_display();
  1601.         sprintf(buff, "Saved %d object%s", nselected, (nselected > 1) ? "s" : "");
  1602.         popmsg(buff);
  1603.         set_goodbye();
  1604.         while(!goodbye());
  1605.         fclose(out);
  1606.         break;
  1607.     case 'I':
  1608.         {
  1609.             seg_info(0);
  1610.             set_goodbye();
  1611.             while(!goodbye());
  1612.             break;
  1613.         }
  1614.     case 'D':
  1615.         refresh_display();
  1616.         if(check_obj()) break;
  1617.         sprintf(buff, "Delete %d object%s!  Are you sure?",
  1618.         nselected, (nselected > 1) ? "s" : "");
  1619.         popmsg(buff);
  1620.         reframe = 1;
  1621. /*        i = toupper(getch()); */
  1622.         set_goodbye();
  1623.         while(1)
  1624.          {
  1625.           i = goodbye();
  1626.           i = toupper(i);
  1627.           if(i) break;
  1628.          }
  1629. /*        while((i=toupper(goodbye())==0); */
  1630.         if (i != 'Y') break;
  1631.         refresh_display();
  1632.         walk_split_tree(split_tree, nuke_it);
  1633.         refresh_display();
  1634.         break;
  1635.     case 'U':
  1636.         walk_split_tree(split_tree, unhi_it);
  1637.         refresh_display();
  1638.         break;
  1639.     case 'F':
  1640.         if(check_obj()) break;
  1641.         walk_split_tree(split_tree, first_it);
  1642.         break;
  1643.     case 'N':
  1644.         if(check_obj()) break;
  1645.         walk_split_tree(split_tree, next_it);
  1646.         break;
  1647. #ifdef ENABLE_DEPTHALTER
  1648.     case 'T':
  1649.         {
  1650.         if (check_obj()) break;
  1651.         sortflag = 0x0000;
  1652.         popmsg("sort by Object or Poly?");
  1653.         set_goodbye();
  1654. /*        i = toupper(getch()); */
  1655. /*        while((i=toupper(goodbye())==0); */
  1656.         while(1)
  1657.          {
  1658.           i = goodbye();
  1659.           i = toupper(i);
  1660.           if(i) break;
  1661.          }
  1662.         if(i==1) goto gb;
  1663.         if (i == 'O') sortflag = BYOBJECT;
  1664.         if (!sortflag)
  1665.          {
  1666.           popmsg("sort by Deepest or Average?");
  1667. /*        i = toupper(getch()); */
  1668. /*          while((i=toupper(goodbye())==0); */
  1669.         while(1)
  1670.          {
  1671.           i = goodbye();
  1672.           i = toupper(i);
  1673.           if(i) break;
  1674.          }
  1675.           if(i==1) goto gb;
  1676.           if (i == 'A') sortflag |= AVERAGE;
  1677.          }
  1678.         walk_split_tree(split_tree, sortflag_it);
  1679.            gb:
  1680.         reframe = redraw = 1;
  1681.         }
  1682.         break;
  1683. #endif
  1684.     default:
  1685.         break;
  1686.     }
  1687.     return 0;
  1688. }
  1689.  
  1690.  
  1691. /************** FIGURE MENU *************/
  1692.  
  1693. int fig_menu(void)
  1694. {
  1695.     char buff[100], *p;
  1696.     FILE *in, *out;
  1697.     char c, d;
  1698.     long x, y, z;
  1699.     int mx, my;
  1700.  
  1701.     refresh_display();
  1702.  
  1703.     switch (menu(figmenu))
  1704.     {
  1705.     case 'L':
  1706.         askfor("Figure file to read? ", buff, 15);
  1707.         if (buff[0] == '\0')
  1708.         {
  1709.             reframe = redraw = 1;
  1710.             break;
  1711.         }
  1712.         add_ext(buff,"fig");
  1713.         if ((in = fopen(buff, "r")) == NULL)
  1714.         {
  1715.             popmsg("Could not open figure file");
  1716.             set_goodbye();
  1717.             while(!goodbye());
  1718.         }
  1719.         else
  1720.             {
  1721.             SEGMENT *s;
  1722.             int c;
  1723.             while ((c = getc(in)) != '{')
  1724.                 if (c == EOF)
  1725.                 {
  1726.                     popmsg("Early EOF!");
  1727.                       set_goodbye();
  1728.                     while(!goodbye());
  1729.                     break;
  1730.                 }
  1731.             set_readseg_objlist(objlist);
  1732.             readseg_err = 0;
  1733.             if ((s = readseg(in, NULL)) == NULL)
  1734.             {
  1735.                 popmsg(readseg_errmsgs[-readseg_err]);
  1736.                   set_goodbye();
  1737.                 while(!goodbye());
  1738.             }
  1739.             else
  1740.                 {
  1741.                 mxosize = 0;
  1742.                 walk_segtree(s, maxsize_it);
  1743.                 compute_vpoint(&x, &y, &z, 1000+mxosize);
  1744.                 abs_move_segment(s, x, y, z);
  1745.                 update_segment(s);
  1746.             }
  1747.         }
  1748.         reframe = redraw = 1;
  1749.         break;
  1750.     case 'I':
  1751.         seg_info(1);
  1752.         set_goodbye();
  1753.         while(!goodbye());
  1754.         break;
  1755.     case 'S':
  1756.         if(check_moveobj()) break;
  1757.         walk_segtree(find_root_segment(last_figure), hilite_it); /* and down again */
  1758.         break;
  1759.     case 'U':
  1760.         walk_split_tree(split_tree, unhi_it);
  1761.         refresh_display();
  1762.         break;
  1763.     case 'H':
  1764.         if(check_moveobj()) break;
  1765.         refresh_display();
  1766.         walk_split_tree(split_tree, hack_it);
  1767.         break;
  1768.     case 'J':
  1769.         if (check_moveobj()) break;
  1770.         if (!can_point_2D()) break;
  1771.         if (!manip_2D_avail) break;
  1772.         refresh_display();
  1773.         popmsg("Click on new parent");
  1774.         reframe = 1;
  1775.         refresh_display();
  1776.         newparent = NULL;
  1777.         do
  1778.             {
  1779.             OBJECT *newobj;
  1780.             move_till_click(cursor_device, 1, &mx, &my);
  1781.             newobj = where_split_screen_pt(NULL, NULL, mx, my);
  1782.             if (newobj)
  1783.                 if ((get_obj_flags(newobj) & OBJ_HIGHLIGHTED) == 0)
  1784.                     newparent = get_object_owner(newobj);
  1785.         }
  1786.         while (newparent == NULL);
  1787.         walk_split_tree(split_tree, join_it);
  1788.         break;
  1789.     case 'A':
  1790.         if(check_moveobj()) break;
  1791.         connect_body(current_view, last_figure);
  1792.         break;
  1793.     case 'D':
  1794.         disconnect_body (current_view);
  1795.         if(!flymode)
  1796.         {
  1797.             current_view->roll = 0;
  1798.         }
  1799.         break;
  1800.     default:
  1801.         break;
  1802.     }
  1803.     return 0;
  1804. }
  1805.  
  1806.  
  1807.  
  1808. /***************** DISPLAY OPTIONS MENU ***************/
  1809.  
  1810. int disp_options(void)
  1811. {
  1812.     char buff[20];
  1813.  
  1814.     switch(menu(optmenu))
  1815.     {
  1816.     case 'M':
  1817.         animatemode = !animatemode;
  1818.         break;
  1819.     case 'B':
  1820.         fancy_background = !fancy_background;
  1821.         break;
  1822.     case 'R':
  1823.         reflection_pool = !reflection_pool;
  1824.         current_view->bottom = reflection_pool ? 160 : 200;
  1825.         break;
  1826.     case 'S':
  1827.         do_screen_clear = !do_screen_clear;
  1828.         popmsg(do_screen_clear ? "Will clear" : "Won't clear");
  1829.         do_screen_clear = !do_screen_clear;
  1830.         tdelay(600);
  1831.         refresh_display();
  1832.         refresh_display();
  1833.         refresh_display();
  1834.         do_screen_clear = !do_screen_clear;
  1835.         break;
  1836.     case 'D':
  1837.         current_view->directional = !current_view->directional;
  1838.         popmsg(current_view->directional ? "Spotlight" : "Point Source");
  1839.         tdelay(600);
  1840.         break;
  1841.     case 'H':
  1842.         do_horizon = !do_horizon;
  1843.         if (!do_horizon) reset_screens();
  1844.         popmsg(do_horizon ? "Horizon" : "No Horizon");
  1845.         tdelay(600);
  1846.         break;
  1847.     case 'A':
  1848.         askfor("Ambient light: ", buff, 15);
  1849.         current_view->ambient = atoi(buff) & 0x7F;
  1850.         break;
  1851.     case 'P':
  1852.         show_location = !show_location;
  1853.         if (!show_location) reset_screens();
  1854.         break;
  1855.     case 'C':
  1856.         show_compass = !show_compass;
  1857.         if (!show_compass) reset_screens();
  1858.         break;
  1859.     case 'F':
  1860.         show_framerate = !show_framerate;
  1861.         if (!show_framerate) reset_screens();
  1862.         break;
  1863.     default:
  1864.         break;
  1865.     }
  1866.     return 0;
  1867. }
  1868.  
  1869.  
  1870. /*************** PAINTING MENU OPERATIONS **********/
  1871.  
  1872. static unsigned stype[] = { 
  1873.     0, 0x1000, 0x2000, 0x3000 };
  1874.  
  1875. unsigned paint = 1;
  1876. static unsigned surface = 0x1000;
  1877. static unsigned paintcolor = 1;
  1878.  
  1879. void surf_it(OBJECT *obj)
  1880. {
  1881.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1882.     {
  1883.         int nv, np, i;
  1884.         unsigned color;
  1885.         get_obj_info(obj, &nv, &np);
  1886.         for (i = 0; i < np; ++i)
  1887.         {
  1888.             get_poly_info(obj, i, &color, &nv, NULL, 0);
  1889.             set_poly_color(obj, i, (color & 0xCFFF) | (surface&0x3000) );
  1890.         }
  1891.     }
  1892. }
  1893.  
  1894. void color_it(OBJECT *obj)
  1895. {
  1896.     if (get_obj_flags(obj) & OBJ_HIGHLIGHTED)
  1897.     {
  1898.         int nv, np, i;
  1899.         get_obj_info(obj, &nv, &np);
  1900.         for (i = 0; i < np; ++i)
  1901.             set_poly_color(obj, i, 0x8000 | paint);
  1902.     }
  1903. }
  1904.  
  1905.  
  1906. unsigned int get_surface(void)
  1907. {
  1908.     reframe = 1;
  1909.     switch (menu(surfmenu))
  1910.     {
  1911.     case 'A':
  1912.         surface = stype[0];
  1913.         break;
  1914.     case 'C':
  1915.         surface = stype[1];
  1916.         break;
  1917.     case 'M':
  1918.         surface = stype[2];
  1919.         break;
  1920.     case 'G':
  1921.         surface = stype[3];
  1922.         break;
  1923.     default:
  1924.         return 1;
  1925.     }
  1926.     if (surface == 0) paint = paintcolor;
  1927.     else paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
  1928.     refresh_display();
  1929.     while (bioskey(1)) bioskey(0); /* flush keyboard buffer */
  1930.     return 0;
  1931. }
  1932.  
  1933.  
  1934. int painting(void)
  1935. {
  1936.     int x, y, c, i;
  1937.     unsigned buttons;
  1938.     char buff[100];
  1939.  
  1940.     if (!can_point_2D()) return 3;
  1941.  
  1942.     reframe = 1;
  1943.     switch (menu(paintmenu))
  1944.     {
  1945.     case 'S':/* select surface */
  1946.         get_surface();
  1947.         break;
  1948.  
  1949.     case 'C':/* select color */
  1950.         if (!can_point_2D()) break;
  1951.         if (!manip_2D_avail) break;
  1952.         disp_palette();
  1953.         reframe = 1;
  1954.         do {
  1955.             move_till_click(cursor_device, 1, &x, &y);
  1956.         }
  1957.         while (y>128 || x>160);
  1958.         paintcolor = 16*(y/8) + x/10;
  1959.         if (surface == 0)
  1960.             paint = paintcolor;
  1961.         else
  1962.             paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
  1963.         refresh_display();
  1964.         break;
  1965.  
  1966.     case 'G':
  1967.         refresh_display();
  1968.         do {
  1969.             if (kbhit()) break;
  1970.             while (move_2D(cursor_device, &x, &y, &buttons) == 0 && !kbhit());
  1971.             if (buttons & 0x01)
  1972.             {
  1973.                 OBJECT *obj;
  1974.                 int poly;
  1975.                 obj = where_split_screen_pt(&poly, NULL, x, y);
  1976.                 if (obj)
  1977.                 {
  1978.                     get_poly_info(obj, poly, &c, NULL, NULL, 0);
  1979.                     c &= 0x7FFF;
  1980.                     sprintf(buff,"Poly Color: 0x%04x", c);
  1981.                     popmsg(buff);
  1982.                     surface = c & 0xFF00;
  1983.                     paintcolor = c & 0xFF;
  1984.                     paint = c;
  1985.                 }
  1986.                 else popmsg ("No Poly Selected");
  1987.             }
  1988.             if(buttons!=1) refresh_display();
  1989.         }
  1990.         while (!(buttons&2));
  1991.         while (kbhit()) getch();
  1992.         break;
  1993.  
  1994.     case 'P':
  1995.         refresh_display();
  1996.         i = 0;
  1997.         while(1)
  1998.         {
  1999.             if (kbhit()) break;
  2000.             while (move_2D(cursor_device, &x, &y, &buttons) == 0 && !kbhit());
  2001.             if (buttons & 0x01)
  2002.             {
  2003.                 OBJECT *obj;
  2004.                 int poly;
  2005.                 obj = where_split_screen_pt(&poly, NULL, x, y);
  2006.                 if (obj)
  2007.                 {
  2008.                     set_poly_color(obj, poly, paint);
  2009.                     refresh_display();
  2010.                 }
  2011.             }
  2012.             else if (buttons & 0x02)
  2013.             {
  2014.                 OBJECT *obj;
  2015.                 int poly;
  2016.                 i = 1;
  2017.                 obj = where_split_screen_pt(&poly, NULL, x, y);
  2018.                 if (obj)
  2019.                 {
  2020.                     get_poly_info(obj, poly, &c, NULL, NULL, 0);
  2021.                     c &= 0x7FFF;
  2022.                     sprintf(buff,"Poly Color: 0x%04x", c);
  2023.                     popmsg(buff);
  2024.                     surface = c & 0xFF00;
  2025.                     paintcolor = c & 0xFF;
  2026.                     paint = c;
  2027.                 }
  2028.                 else popmsg ("No Poly Selected");
  2029.             }
  2030.             else if (i) refresh_display();
  2031.         }
  2032.         while (kbhit()) getch();
  2033.         break;
  2034.  
  2035.     case 'R':
  2036.         refresh_display();
  2037.         if(get_surface()) break;
  2038.         walk_split_tree(split_tree, surf_it);
  2039.         refresh_display();
  2040.         break;
  2041.  
  2042.     case 'A':
  2043.         walk_split_tree(split_tree, color_it);
  2044.         refresh_display();
  2045.         break;
  2046.     default:
  2047.         break;
  2048.     }
  2049.     return 0;
  2050. }
  2051.  
  2052.  
  2053. /****************** MAIN MENU *************/
  2054.  
  2055. int main_menu(void)
  2056. {
  2057.     switch(menu(mainmenu))
  2058.     {
  2059.     case 'Q':
  2060.         do_key('Q');
  2061.         break;
  2062.     case 'I':
  2063.         do_key('I');
  2064.         break;
  2065.     case 'H':
  2066.         do_key('H');
  2067.         break;
  2068.     case 'O':
  2069.         do_key('O');
  2070.         break;
  2071.     case 'P':
  2072.         do_key('P');
  2073.         break;
  2074.     case 'F':
  2075.         do_key('F');
  2076.         break;
  2077.     case 'M':
  2078.         do_key('M');
  2079.         break;
  2080.     case 'D':
  2081.         disp_options();
  2082.         break;
  2083.     case 'V':
  2084.         view_menu();
  2085.         break;
  2086.     default:
  2087.         break;
  2088.     }
  2089.     return 0;
  2090. }
  2091.  
  2092.  
  2093.