home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vr386 / keyboard.c < prev    next >
C/C++ Source or Header  |  1996-03-19  |  41KB  |  1,866 lines

  1. /* Keyboard routines and menus for VRC release */
  2.  
  3. /* Original simple keyboard was written by Bernie Roehl, July 1992 */
  4.  
  5. // MASSIVELY rewritten, along with entire menu and navigation
  6. // system, by Dave Stampe for Release 5 (VRC), Nov. 92.
  7.  
  8. // some changes made to support horizon and key monitor, 12/24/93
  9.  
  10. // Completely rearranged, substantial mods, ported to VR-386 API 9/1/94
  11.  
  12.  
  13. /*
  14.  This code is part of the VR-386 project, created by Dave Stampe.
  15.  VR-386 is a desendent of REND386, created by Dave Stampe and
  16.  Bernie Roehl.  Almost all the code has been rewritten by Dave
  17.  Stampre for VR-386.
  18.  
  19.  Copyright (c) 1994 by Dave Stampe:
  20.  May be freely used to write software for release into the public domain
  21.  or for educational use; all commercial endeavours MUST contact Dave Stampe
  22.  (dstampe@psych.toronto.edu) for permission to incorporate any part of
  23.  this software or source code into their products!  Usually there is no
  24.  charge for under 50-100 items for low-cost or shareware products, and terms
  25.  are reasonable.  Any royalties are used for development, so equipment is
  26.  often acceptable payment.
  27.  
  28.  ATTRIBUTION:  If you use any part of this source code or the libraries
  29.  in your projects, you must give attribution to VR-386 and Dave Stampe,
  30.  and any other authors in your documentation, source code, and at startup
  31.  of your program.  Let's keep the freeware ball rolling!
  32.  
  33.  DEVELOPMENT: VR-386 is a effort to develop the process started by
  34.  REND386, improving programmer access by rewriting the code and supplying
  35.  a standard API.  If you write improvements, add new functions rather
  36.  than rewriting current functions.  This will make it possible to
  37.  include you improved code in the next API release.  YOU can help advance
  38.  VR-386.  Comments on the API are welcome.
  39.  
  40.  CONTACT: dstampe@psych.toronto.edu
  41. */
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>  /* for atol(), only for debugging! */
  45. #include <dos.h>
  46. #include <time.h>    /* time(), ctime() */
  47. #include <string.h>
  48. #include <math.h>
  49. #include <alloc.h>
  50.  
  51. #include "config.h"
  52. #include "pointer.h"
  53. #include "vr_api.h"
  54. #include "intmath.h"
  55. #include "segment.h"
  56. #include "splits.h"
  57. #include "pcdevice.h"    // last_render_time()
  58. #include "vrconst.h"
  59.  
  60. extern char *fix_fname(char *fname);
  61.  
  62. extern manip_2D_avail;
  63.  
  64. extern void set_horizon(int ncolors, int colors[16], int bandsize);
  65.  
  66. extern int do_screen_clear, do_horizon;
  67. extern int show_location, show_compass, show_framerate;
  68.  
  69. extern LIGHT *amb_light, *light1, *light2;
  70.  
  71. static int sstepsize = 10;    /* speed multipliers */
  72. static int astepsize = 2;
  73.  
  74. long anglestep = 160000L;
  75. long spacestep = 10L;
  76.  
  77. int spinmode = 0;
  78. extern int flymode;
  79. int floormode = 0;
  80. extern int animatemode;
  81.  
  82. extern int old_angle_order;  /* in wparse.c */
  83.  
  84. /******************* MENU TEXT **************/
  85.  
  86. static 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. static 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. static 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.     "Screen clear",
  168.     "Horizon",
  169.     "Ambient light",
  170.     "Directional light",
  171.     "Position display",
  172.     "Compass display",
  173.     "Frame rate display",
  174.     NULL };
  175.  
  176. static char *mousemenu[] = {
  177.     "Move",
  178.     "Rotate",
  179.     "Twirl",
  180.     "Grasp",
  181.     "Ungrasp",
  182.     NULL
  183. };
  184.  
  185. static char *objmenu[] = {
  186.     "Load object",
  187.     "Save object",
  188.     "Information",
  189.     "Delete object",
  190.     "Unselect all",
  191.     "First representation",
  192.     "Next representation",
  193.     NULL
  194. };
  195.  
  196. static char *figmenu[] = {
  197.     "Load figure",
  198.     "Information",
  199.     "Select all",
  200.     "Unselect all",
  201.     "Hack off",
  202.     "Join to",
  203.     "Attach viewpoint",
  204.     "Detach viewpoint",
  205.     NULL
  206. };
  207.  
  208.  
  209.  
  210. /*************** MORE FEATURES *************/
  211.  
  212. static int save_pcx_file(void)
  213. {
  214.   char filename[100];
  215.   char far *buffer;
  216.   FILE *out;
  217.   BOOL was_visible;
  218.  
  219.   screen_refresh(current_camera);
  220.   askfor("File to save to? ", filename, 15);
  221.   if (filename[0] == '\0') return 1;
  222.   if ((out = fopen(filename, "wb")) == NULL)
  223.     {
  224.       errprintf("Could not open file");
  225.       cursor_show();
  226.       return 3;
  227.     }
  228.   was_visible = cursor_hide();
  229.   save_pcx(out, current_video_page);
  230.   if(was_visible) cursor_show();
  231.   fclose(out);
  232.   return 0;
  233. }
  234.  
  235.  
  236.  
  237. extern PDRIVER *cursor_device;
  238.  
  239. static int resize_viewport(void)
  240. {
  241.   int top, left, bottom, right;
  242.   unsigned buttons;
  243.  
  244.   if(stereo_type!=MONOSCOPIC && stereo_type!= SWITCHED) return -1;
  245.  
  246.   save_screen();
  247.  
  248.   popmsg("Click top-left and drag");
  249.  
  250.   cursor_show();
  251.   do {
  252.     move_2D(cursor_device, &left, &top, &buttons);
  253.     if(kbhit())
  254.       {
  255.     getch();
  256.     screen_refresh(current_camera);
  257.     return 1;
  258.       }
  259.      } while (buttons == 0);
  260.  
  261.    while (buttons)
  262.      {
  263.        while (!move_2D(cursor_device, &right, &bottom, &buttons));
  264.        restore_screen();
  265.        user_draw_box(left, top, right, bottom, 15);
  266.      }
  267.    cursor_hide();
  268.  
  269.    if (right - left > 10)
  270.      {
  271.        left = left & (~0x0007); /* always on an 8-pixel boundary */
  272.        right = (right & (~0x0007)) + 7;
  273.      }
  274.    else return -1;
  275.  
  276.    if (bottom - top < 10) return -1;
  277.    set_camera_window(current_camera, left, top, right, bottom);
  278.  
  279.    if (stereo_type == SWITCHED) /* makes sense for Sega only (no shift) */
  280.      {
  281.        STEREO *s = current_camera->stereo;
  282.        s->pixel_width = right-left+1;
  283.        s->window[LEFT_EYE].l = left;
  284.        s->window[LEFT_EYE].t = top;
  285.        s->window[LEFT_EYE].r = right;
  286.        s->window[LEFT_EYE].b = bottom;
  287.        s->window[RIGHT_EYE].l = left;
  288.        s->window[RIGHT_EYE].t = top;
  289.        s->window[RIGHT_EYE].r = right;
  290.        s->window[RIGHT_EYE].b = bottom;
  291.      }
  292.  
  293.    compute_camera_factors(current_camera);
  294.  
  295.    display_changed++;
  296.    cursor_hide();
  297.    reset_screens();
  298.    return 0;
  299. }
  300.  
  301.  
  302.  
  303.  
  304. /*************** STATUS DISPLAYS ETC. ************/
  305.  
  306.  
  307.  
  308. static void center(char *s, int w)    // centers text string
  309. {
  310.   int n;
  311.  
  312.   if (strlen(s) == 0) return;
  313.   n = (w - strlen(s)) /2;
  314.   memmove(&s[n], s, strlen(s)+1);
  315.   memset(s, ' ', n);
  316. }
  317.  
  318. static int nobjs, nverts, npolys;
  319.  
  320. static void gather_data(OBJECT *obj)
  321. {
  322.   int nv = 0, np = 0;
  323.  
  324.   get_obj_info(obj, &nv, &np);
  325.   ++nobjs;
  326.   nverts += nv;
  327.   npolys += np;
  328. }
  329.  
  330.  
  331. static disp_status(POSE *p)
  332. {
  333.   char *text[10], a[80], b[80], c[80], d[80], e[80], f[80], g[80], h[80];
  334.   int w, i;
  335.   VIEW *v = current_camera->mono;
  336.  
  337.   text[0] = a;
  338.   text[1] = "";
  339.   text[2] = b;
  340.   text[3] = c;
  341.   text[4] = d;
  342.   text[5] = e;
  343.   text[6] = f;
  344.   text[7] = g;
  345.   text[8] = h;
  346.   text[9] = NULL;
  347.   sprintf(a, "STATUS");
  348.  
  349.   sprintf(b, "X = %ld  Y = %ld  Z = %ld", p->x, p->y, p->z);
  350.   w = strlen(b);
  351.  
  352.   if (old_angle_order)
  353.     sprintf(c, "Pan = %ld   Tilt = %ld   Roll = %ld  ", p->ry/65536L, p->rx/65536L, p->rz/65536L);
  354.   else
  355.     sprintf(c, "Tilt = %ld   Pan = %ld   Roll = %ld  ", p->rx/65536L, p->ry/65536L, p->rz/65536L);
  356.   if (strlen(c) > w) w = strlen(c);
  357.   sprintf(d, "Zoom = %2.2f", scale2float(get_camera_zoom(current_camera)));
  358.   if (strlen(d) > w) w = strlen(d);
  359.   sprintf(e, "Hither = %ld  Yon = %ld", get_camera_hither(current_camera), get_camera_yon(current_camera));
  360.   if (strlen(e) > w) w = strlen(e);
  361.  
  362.   nobjs = 0, nverts = 0, npolys = 0;
  363.   do_for_all_objects(gather_data);
  364.   sprintf(f, "%d object%s, %d vertice%s, %d poly%s",nobjs,(nobjs == 1) ? "" : "s",
  365.                             nverts, (nverts == 1) ? "" : "s",
  366.                             npolys, (npolys == 1) ? "" : "s");
  367.  
  368.   sprintf(g, "Ambient light: %d", get_light_intensity(amb_light));
  369.  
  370.   sprintf(h, "Memory Free: %ld", coreleft());
  371.  
  372.   if (strlen(f) > w) w = strlen(f);
  373.   if (strlen(g) > w) w = strlen(g);
  374.   if (strlen(h) > w) w = strlen(h);
  375.  
  376.   for (i = 0; text[i]; ++i) center(text[i], w);
  377.  
  378.   save_screen();
  379.   poptext(text);
  380.   return 0;
  381. }
  382.  
  383.  
  384. void disp_palette(void)        // show 256-color palette
  385. {
  386.   int i, j;
  387.   BOOL was_visible = cursor_hide();
  388.  
  389.   save_screen();
  390.   for (i = 0; i < 16; i++)
  391.     for (j = 0; j < 16; j++)
  392.         user_box(j*10,i*8,j*10+9,i*8+8,i*16+j);
  393.   if(was_visible) cursor_show();
  394. }
  395.  
  396.  
  397. /*************** VIEW MENU *************/
  398.  
  399. void process_a_key(WORD key);
  400.  
  401. static void view_menu(void)
  402. {
  403.   char buff[100], *p;
  404.   FILE *out;
  405.   char d;
  406.   COORD l;
  407.  
  408.   save_screen();
  409.   switch (menu(viewmenu))
  410.     {
  411.       case 'I':
  412.         process_a_key('I');
  413.         break;
  414.       case 'R':
  415.         process_a_key (HOME);
  416.         position_changed++;
  417.         break;
  418.       case 'P':
  419.         process_a_key('^');
  420.         break;
  421.       case 'F':
  422.         flymode = !flymode;
  423.         popmsg(flymode ? "Fly mode" : "Ground mode");
  424.         tdelay(350);
  425.         break;
  426.       case 'L':
  427.         floormode = !floormode;
  428.         popmsg(floormode ? "Floors used" : "Floors ignored");
  429.         tdelay(350);
  430.         break;
  431.       case 'H':
  432.         askfor("Enter hither value:", buff, 10);
  433.         if (buff[0])
  434.           {
  435.             COORD h = atof(buff);
  436.             set_camera_hither(current_camera, h);
  437.           }
  438.         display_changed++;
  439.         break;
  440.       case 'Y':
  441.         askfor("Enter yon value:", buff, 10);
  442.         if (buff[0])
  443.           {
  444.             COORD y = atof(buff);
  445.             set_camera_yon(current_camera, y);
  446.           }
  447.         display_changed++;
  448.         break;
  449.       case 'G':/* goto XYZ */
  450.         askfor("X,Y,Z: ", buff, 25);
  451.         if (buff[0])
  452.             sscanf(buff, "%ld,%ld,%ld", &body_pose->x, &body_pose->y, &body_pose->z);
  453.         position_changed++;
  454.         break;
  455.       case 'A':/* look at angle */
  456.         {
  457.           long p, t, r;
  458.           askfor("Pan,rx,rz:", buff, 22);
  459.           if (buff[0])
  460.             {
  461.               sscanf(buff, "%ld,%ld,%ld", &p, &t, &r);
  462.               body_pose->ry = p*65536L;
  463.               body_pose->rx = t*65536L;
  464.               body_pose->rz = r*65536L;
  465.             }
  466.           position_changed++;
  467.         }
  468.         break;
  469.       case 'M':
  470.         askfor("Move step: ", buff, 15);
  471.         if (buff[0]) spacestep = atoi(buff);
  472.         position_changed++;
  473.         break;
  474.       case 'T':
  475.         askfor("Turn angle step: ", buff, 15);
  476.         if (buff[0]) anglestep = atof(buff) * 65536L;
  477.         position_changed++;
  478.         break;
  479.       case 'V':
  480.         resize_viewport();
  481.         display_changed++;
  482.         break;
  483.       case 'O':
  484.         disp_options();
  485.         break;
  486.       case 'S':
  487.         process_a_key('S');
  488.         break;
  489.      default:
  490.         break;
  491.    }
  492.  restore_screen();
  493. }
  494.  
  495.  
  496. static void stereo_info(void)
  497. {
  498.   char b1[50]="", b2[50]="", b3[50]="", b4[50]="", b5[50]="", b6[50]="";
  499.   char b7[50]="", b8[50]="", b9[50]="";
  500.   char *b[10];
  501.   STEREO *st = current_camera->stereo;
  502.   STWINDOW *swl = &(current_camera->stereo->window[LEFT_EYE]);
  503.   STWINDOW *swr = &(current_camera->stereo->window[RIGHT_EYE]);
  504.   float xo, xa, conv, ws;
  505.  
  506.   if(stereo_type==MONOSCOPIC) return;
  507.  
  508.   xa = (swl->xoff-swr->xoff)/2.0;
  509.   ws = st->world_scaling/65536.0;
  510.   xo=(st->phys_eye_spacing * st->phys_screen_dist * st->pixel_width) /
  511.         (2.0 * st->phys_screen_width * st->phys_convergence);
  512.   conv=(st->phys_eye_spacing * st->phys_screen_dist * st->pixel_width) /
  513.         (2.0 * st->phys_screen_width * (xo+xa));
  514.  
  515.   b[0] = b1;
  516.   sprintf(b1, "      Stereo Parameters");
  517.   b[1] = b2;
  518.   sprintf(b2, "screen distance:       %ld", st->phys_screen_dist);
  519.   b[2] = b3;
  520.   sprintf(b3, "screen width:          %ld", st->phys_screen_width);
  521.   b[3] = b4;
  522.   sprintf(b4, "pixel width:           %ld", st->pixel_width);
  523.   b[4] = b5;
  524.   sprintf(b5, "eye spacing:           %ld", st->phys_eye_spacing);
  525.   b[5] = b6;
  526.   sprintf(b6, "convergence distance:  %ld", st->phys_convergence);
  527.   b[6] = b7;
  528.   sprintf(b7, "world scaling:         %0.2f", ws);
  529.   b[7] = b8;
  530.   sprintf(b8, "added X offset:        %0.0f", xa);
  531.   b[8] = b9;
  532.   sprintf(b9, "effective convergence: %0.0f", conv);
  533.   b[9] = NULL;
  534.  
  535.   save_screen();
  536.   poptext(b);
  537.   get_response(1);
  538.   restore_screen();
  539. }
  540.  
  541.  
  542. /************* PROCESS SUPPORT ***********/
  543.  
  544. static int nselected = 0;
  545.  
  546. static FILE *save_file = NULL;
  547.  
  548. static int nsaved = 0;
  549.  
  550. static void save_it(OBJECT *obj)
  551. {
  552.   if(nselected<2) save_plg(obj, save_file, 0); /* only one: save object coords */
  553.   else save_plg(obj, save_file, 1);        /* else save world coords */
  554. }
  555.  
  556. static long mxosize = 0;
  557.  
  558. static void maxsize_it(OBJECT *obj)    // find maximum size of figure
  559. {
  560.   long s;
  561.   if(obj)
  562.     {
  563.       s = get_object_bounds(obj, NULL, NULL, NULL);
  564.       if(s>mxosize) mxosize = s;
  565.     }
  566. }
  567.  
  568.  
  569. static int numsegs, numverts, numpolys;
  570. static long centx, centy, centz;
  571. static OBJECT *last_figure;                   // last moveable and visible
  572.                     // object (split list)
  573.  
  574. static void count_moveable(OBJECT *obj)
  575. {
  576.   ++nselected;
  577.   get_object_bounds(obj, ¢x, ¢y, ¢z);
  578.   if(is_object_moveable(obj))
  579.     {
  580.       int nv, np;
  581.       get_obj_info(obj, &nv, &np);
  582.       numverts += nv;
  583.       numpolys += np;
  584.       last_figure = obj;
  585.       numsegs++;
  586.     }
  587. }
  588.  
  589.  
  590. static void count_all(OBJECT *obj)
  591. {
  592.   int nv, np;
  593.   get_object_bounds(obj, ¢x, ¢y, ¢z);
  594.   get_obj_info(obj, &nv, &np);
  595.   numverts += nv;
  596.   numpolys += np;
  597.   nselected++;
  598. }
  599.  
  600.  
  601.  
  602. static void zap_obj(OBJECT *obj)
  603. {
  604.   delete_visobj(obj);   // preserve segment so animation doesnt crash
  605. }
  606.  
  607.  
  608. extern OBJECT *body_seg;
  609. extern OBJECT *head_seg;
  610. extern OBJECT *wrist_seg;
  611.  
  612.  
  613. static void grab_it(OBJECT *obj)    // attach to body
  614. {
  615.   if(is_object_child_of(body_seg, obj)) return;  // can't grab body part!
  616.   attach_object(obj, body_seg, 1);
  617. }
  618.  
  619.  
  620. static void ungrab_it(OBJECT *obj)    // detach from body
  621. {
  622.   if(is_object_child_of(body_seg, obj))
  623.   detach_object(obj,1);
  624. }
  625.  
  626.  
  627. //////// MOVEMENT CALLBACKS
  628.  
  629. static long ptx, pty, ptz;
  630. static long oldx, oldy, oldz, oldcx, oldcy, oldcz, dx, dy, dz;
  631.  
  632. static void move_it(OBJECT *obj)
  633. {
  634.   if(is_object_moveable(obj))
  635.     {
  636.       POSE p;
  637.       get_object_pose(obj, &p);
  638.       p.x += ptx - oldx;
  639.       p.y += pty - oldy;
  640.       p.z += ptz - oldz;
  641.       p.rx = p.ry = p.rz = DONTCARE;
  642.       set_object_pose(obj, &p);
  643.       update_object(obj);
  644.     }
  645. }
  646.  
  647. static void twirl_it(OBJECT *obj)
  648. {
  649.   if(is_object_moveable(obj))
  650.     {
  651.       POSE p;
  652.       get_object_pose(obj, &p);
  653.       p.rx += ptx;
  654.       p.ry += pty;
  655.       p.rz += ptz;
  656.       p.x = p.y = p.z = DONTCARE;
  657.       set_object_pose(obj, &p);
  658.       update_object(obj);
  659.     }
  660. }
  661.  
  662. static void rot_it(OBJECT *obj)
  663. {
  664.   if(is_object_moveable(obj))
  665.     {
  666.       POSE p;
  667.       get_object_pose(obj, &p);
  668.       p.rx += ptx;
  669.       p.ry += pty;
  670.       p.rz += ptz;
  671.       p.x = p.y = p.z = DONTCARE;
  672.       set_object_pose(obj, &p);
  673.       update_object(obj);
  674.     }
  675. }
  676.  
  677.  
  678. static void hack_it(OBJECT *obj)
  679. {
  680.   if(is_object_moveable(obj))
  681.     {
  682.       detach_object(obj, 1);
  683.       update_object(obj);
  684.     }
  685. }
  686.  
  687.  
  688. static OBJECT *newparent = NULL;
  689.  
  690. static void join_it(OBJECT *obj)
  691. {
  692.   if(is_object_moveable(obj))
  693.     {
  694.       attach_object(obj, newparent, 1);
  695.       update_object(obj);
  696.     }
  697. }
  698.  
  699.  
  700. static void next_it(OBJECT *obj)
  701. {
  702.   select_next_representation(obj);
  703. }
  704.  
  705.  
  706. static void first_it(OBJECT *obj)
  707. {
  708.   select_first_representation(obj);
  709. }
  710.  
  711.  
  712. static int check_moveobj(void)
  713. {
  714.   nselected = 0;
  715.   last_figure = NULL;
  716.  
  717.   do_for_all_selected_moveable(count_moveable);
  718.   if (last_figure == NULL)
  719.     {
  720.       popmsg("No movable objects selected!");
  721.       tdelay(600);
  722.       return 1;
  723.     }
  724.   return 0;
  725. }
  726.  
  727.  
  728. static int check_obj(void)
  729. {
  730.   nselected = 0;
  731.   last_figure = NULL;
  732.  
  733.   do_for_all_selected(count_moveable);
  734.   if (nselected == 0)
  735.     {
  736.       popmsg("No objects selected!");
  737.       tdelay(600);
  738.       return 1;
  739.     }
  740.   return 0;
  741. }
  742.  
  743. static void seg_info(int fig)
  744. {
  745.   char b1[50]="", b2[50]="", b3[50]="", b4[50]="", b5[50]="", b6[50]="";
  746.   char *b[7];
  747.   POSE p;
  748.  
  749.   b[0] = b1;
  750.   b[1] = b2;
  751.   b[2] = b3;
  752.   b[3] = b4;
  753.   b[4] = b5;
  754.   b[5] = b6;
  755.   b[6] = NULL;
  756.   nselected = 0;
  757.   last_figure = NULL;
  758.   do_for_all_selected(count_moveable);
  759.   sprintf(b6, "Object center:%ld, %ld, %ld", centx, centy, centz);
  760.   nobjs = nverts = npolys = 0;
  761.   if(fig && last_figure)
  762.     {
  763.       numsegs = numverts = numpolys = 0;
  764.       do_for_selected_related_objects(last_figure, count_moveable);
  765.       sprintf(b1, "%d seg%s, %d vert%s, %d poly%s",
  766.             numsegs, (numsegs == 1) ? "" : "s",
  767.             numverts, (numverts == 1) ? "" : "s",
  768.             numpolys, (numpolys == 1) ? "" : "s" );
  769.     }
  770.   else
  771.     {
  772.       nselected = numverts = numpolys = 0;
  773.       do_for_all_selected(count_all);
  774.       sprintf(b1, "%d obj%s, %d vert%s, %d poly%s",
  775.             nselected, (nselected == 1) ? "" : "s",
  776.             numverts, (numverts == 1) ? "" : "s",
  777.             numpolys, (numpolys == 1) ? "" : "s" );
  778.     }
  779.   if(last_figure==NULL)
  780.     {
  781.       sprintf(b2," No moveable objects selected");
  782.       b[2] = b6;
  783.       b[3] = NULL;
  784.     }
  785.   else
  786.     {
  787.       get_object_world_pose(last_figure, &p);
  788.       sprintf(b2, "World pos'n: %ld %ld %ld", p.x, p.y, p.z);
  789.       sprintf(b3, "World angle: %4.1f %4.1f %4.1f", angle2float(p.rx), angle2float(p.ry),angle2float(p.rz));
  790.       if(last_figure==NULL || fig==0)
  791.     {
  792.       get_object_pose(last_figure, &p);
  793.       sprintf(b4, "Joint pos'n: %ld %ld %ld", p.x, p.y, p.z);
  794.       sprintf(b5, "Joint angle: %4.1f %4.1f %4.1f", angle2float(p.rx), angle2float(p.ry),angle2float(p.rz));
  795.     }
  796.       else
  797.     {
  798.       b[4] = b6;
  799.       b[3] = b[2];
  800.       b[2] = b[1];
  801.       b[5] = NULL;
  802.       sprintf(b5,"Root of figure:");
  803.       b[1] = b5;
  804.     }
  805.     }
  806.   poptext(b);
  807. }
  808.  
  809.  
  810.  
  811. /************* MOUSE MANIPULATION MENU ***********/
  812.  
  813. extern PDRIVER *cursor_device;
  814.  
  815. static POINTER pointer;
  816.  
  817. static void mouse_menu(void)
  818. {
  819.   void pointer_to_world();
  820.   char buff[100], *p;
  821.   char c, d;
  822.   unsigned buttons;
  823.   int click = 0;
  824.  
  825.   init_pointer(&pointer);
  826.  
  827.   save_screen();
  828.   switch(c = menu(mousemenu))
  829.     {
  830.       case 'M':
  831.       restore_screen();
  832.       if(check_moveobj()) break;
  833.       if (!manip_2D_avail) break;
  834.       pointer_read(cursor_device, &pointer);
  835.       pointer_to_world(&pointer, current_camera, &ptx, &pty, &ptz);
  836.       click = 0;
  837.       while (click == 0)
  838.         {
  839.           screen_refresh(current_camera);
  840.           oldx = ptx;
  841.           oldy = pty;
  842.           oldz = ptz;
  843.           click = PNEW_BUT & pointer_read(cursor_device, &pointer);
  844.           if (!(pointer.buttons & 1)) click = 0;
  845.           pointer_to_world(&pointer, current_camera, &ptx, &pty, &ptz);
  846.           do_for_all_selected_moveable(move_it);
  847.         }
  848.       screen_refresh(current_camera);
  849.           world_changed++;
  850.       break;
  851.       case 'R':
  852.       case 'T':
  853.       restore_screen();
  854.       if(check_moveobj()) break;
  855.       if (!manip_2D_avail) break;
  856.       pointer_read(cursor_device, &pointer);
  857.       oldcx = oldx = pointer.x;
  858.       oldcy = oldy = pointer.y;
  859.       oldcz = oldz = pointer.z;
  860.       while ((pointer.buttons & 0x01) == 0)
  861.         {
  862.           if (toupper(c) == 'R')
  863.         {
  864.           ptx = 32768L*(pointer.y - oldy);
  865.           pty = -32768L*(pointer.x - oldx);
  866.           ptz = -32768L*(pointer.z - oldz);
  867.         }
  868.           else
  869.         {
  870.           ptx = 3270L*(pointer.y - oldcy);
  871.           pty = -3270L*(pointer.x - oldcx);
  872.           ptz = -3270L*(pointer.z - oldcz);
  873.         }
  874.           rotate_to_view(current_camera, &ptx, &pty, &ptz);
  875.           if(toupper(c)=='R') do_for_all_selected_moveable(rot_it);
  876.           else do_for_all_selected_moveable(twirl_it);
  877.           oldx = pointer.x;
  878.           oldy = pointer.y;
  879.           oldz = pointer.z;
  880.           screen_refresh(current_camera);
  881.           pointer_read(cursor_device, &pointer);
  882.         }
  883.  
  884.       while (pointer.buttons & 0x01) pointer_read(cursor_device, &pointer);
  885.       screen_refresh(current_camera);
  886.       world_changed++;
  887.       break;
  888.     case 'G':
  889.       if(check_moveobj()) break;
  890.       do_for_all_selected_moveable(grab_it);
  891.       world_changed++;
  892.       break;
  893.     case 'U':
  894.       if(check_moveobj()) break;
  895.       do_for_all_selected_moveable(ungrab_it);
  896.       world_changed++;
  897.       break;
  898.     default:
  899.       break;
  900.     }
  901.   restore_screen();
  902. }
  903.  
  904.  
  905.  
  906.  
  907. static int obj_menu(void)
  908. {
  909.   char buff[100], *p;
  910.   FILE *in, *out;
  911.   char c, d;
  912.   long x, y, z;
  913.   int i;
  914.  
  915.   nselected = 0;
  916.   last_figure = NULL;
  917.  
  918.   save_screen();
  919.   switch (c=menu(objmenu))
  920.     {
  921.       case 'L':/* load PLG file */
  922.      askfor("File to load? ", buff, 22);
  923.      if (buff[0] == '\0') break;
  924.      strcpy(buff, fix_fname(buff));
  925.      add_ext(buff,"plg");
  926.      if ((in = fopen(buff, "r")) == NULL)
  927.        {
  928.          errprintf("Could not open file");
  929.        }
  930.      else
  931.        {
  932.          POSE p = ZERO_POSE;
  933.          OBJECT *obj;
  934.          long sx = 1, sy = 1, sz = 1;
  935. #ifdef ENABLE_RESIZE_ON_LOAD
  936.          askfor("Scale x,y,z: ", buff, 20);
  937.          if (buff[0])
  938.         sscanf(buff, "%ld,%ld,%ld", &sx, &sy, &sz);
  939. #endif
  940.  
  941.          while ((obj = load_plg_object(in, &p, 1, 1, 1, 0)) != NULL)
  942.           {
  943.         if (make_fixed_object_moveable(obj,NULL))  // moveable object
  944.           {                                   // now put nicely ahead
  945.             mxosize = 0;
  946.             do_for_visible_child_objects(obj, maxsize_it);
  947.             camera_point_ahead(current_camera, 500+mxosize*4, &p.x, &p.y, &p.z);
  948.             set_object_pose(obj, &p);
  949.             update_object(obj);
  950.             add_object_to_world(obj);    // adds to world if not in it
  951.           }
  952.         else
  953.           {
  954.             errprintf("Warning -- out of memory!");
  955.             world_changed++;
  956.           }
  957.            }
  958.          fclose(in);
  959.        }
  960.      world_changed++;
  961.      break;
  962.  
  963.       case 'S':
  964.      restore_screen();
  965.      if(check_obj()) break;
  966.      if (askfor("Enter filename: ", buff, 20) == 0x1B) break;
  967.      if (buff[0] == '\0')
  968.        {
  969.          world_changed++;
  970.          break;
  971.        }
  972.      nobjs = 0;
  973.      add_ext(buff,"plg");
  974.      if ((save_file = fopen(buff, "w")) == NULL)
  975.        {
  976.          errprintf("Could not create file");
  977.          world_changed++;
  978.          break;
  979.        }
  980.      nsaved = 0;
  981.      do_for_all_selected(save_it);
  982.      fclose(save_file);
  983.      save_file = NULL;
  984.      screen_refresh(current_camera);
  985.      sprintf(buff, "Saved %d object%s", nselected, (nselected > 1) ? "s" : "");
  986.      popmsg(buff);
  987.      get_response(1);
  988.      world_changed++;
  989.      fclose(out);
  990.      break;
  991.       case 'I':
  992.      {
  993.        seg_info(0);
  994.        get_response(1);
  995.        break;
  996.      }
  997.       case 'D':
  998.      restore_screen();
  999.      if(check_obj()) break;
  1000.      sprintf(buff, "Delete %d object%s!  Are you sure?",
  1001.      nselected, (nselected > 1) ? "s" : "");
  1002.      popmsg(buff);
  1003.      i = get_response(1);
  1004.      if (toupper(i) != 'Y') break;
  1005.      restore_screen();
  1006.      do_for_all_selected(zap_obj);
  1007.      world_changed++;
  1008.      break;
  1009.       case 'U':
  1010.      do_for_all_selected(unhighlight_object);
  1011.      world_changed++;
  1012.      break;
  1013.       case 'F':
  1014.      if(check_obj()) break;
  1015.      do_for_all_selected(first_it);
  1016.      world_changed++;
  1017.      break;
  1018.       case 'N':
  1019.      if(check_obj()) break;
  1020.      do_for_all_selected(next_it);
  1021.      world_changed++;
  1022.      break;
  1023.       default:     break;
  1024.     }
  1025.   restore_screen();
  1026.   return 0;
  1027. }
  1028.  
  1029.  
  1030. /************** FIGURE MENU *************/
  1031.  
  1032. static int fig_menu(void)
  1033. {
  1034.   char buff[100], *p;
  1035.   FILE *in, *out;
  1036.   char c, d;
  1037.   long x, y, z;
  1038.   int mx, my;
  1039.  
  1040.   save_screen();
  1041.   switch (menu(figmenu))
  1042.     {
  1043.       case 'L':
  1044.     askfor("Figure file to read? ", buff, 15);
  1045.     if (buff[0] == '\0') break;
  1046.     add_ext(buff,"fig");
  1047.     if ((in = fopen(buff, "r")) == NULL)
  1048.       {
  1049.         errprintf("Could not open figure file");
  1050.       }
  1051.     else
  1052.       {
  1053.         OBJECT *obj;
  1054.         POSE p = DONTCARE_POSE;
  1055.  
  1056.         obj = load_figure_as_object(in, default_objlist, NULL, 0, 1, 1, 1);
  1057.         if (!obj)
  1058.           {
  1059.         errprintf("%s",seg_error(NULL));
  1060.         world_changed++;
  1061.           }
  1062.         else
  1063.           {
  1064.         add_objlist_to_world(default_objlist);
  1065.         mxosize = 0;
  1066.         do_for_visible_child_objects(obj, maxsize_it);
  1067.         camera_point_ahead(current_camera, 1000+mxosize, &p.x, &p.y, &p.z);
  1068.         set_object_pose(obj, &p);
  1069.         update_object(obj);
  1070.           }
  1071.       }
  1072.     world_changed++;
  1073.     break;
  1074.       case 'I':
  1075.     seg_info(1);
  1076.     get_response(1);
  1077.     break;
  1078.       case 'S':
  1079.     if(check_moveobj()) break;
  1080.     do_for_visible_related_objects(last_figure, highlight_object); /* and down again */
  1081.     break;
  1082.       case 'U':
  1083.     do_for_all_selected_moveable(unhighlight_object);
  1084.     world_changed++;
  1085.     break;
  1086.       case 'H':
  1087.     if(check_moveobj()) break;
  1088.     screen_refresh(current_camera);
  1089.     do_for_all_selected_moveable(hack_it);
  1090.     world_changed++;
  1091.     break;
  1092.       case 'J':
  1093.     if (check_moveobj()) break;
  1094.     if (!can_point_2D()) break;
  1095.     if (!manip_2D_avail) break;
  1096.     popmsg("Click on new parent");
  1097.     tdelay(500);
  1098.     restore_screen();
  1099.     newparent = NULL;
  1100.     while(!newparent)
  1101.       {
  1102.         if(kbhit()) break;
  1103.         newparent = move_and_find_object_2D(cursor_device, NULL);
  1104.         if(!is_object_moveable(newparent)) newparent = NULL;
  1105.       }
  1106.     if(!newparent) break;
  1107.     do_for_all_selected_moveable(join_it);
  1108.     world_changed++;
  1109.     break;
  1110.       case 'A':
  1111.     if(check_moveobj()) break;
  1112.     connect_body(last_figure);
  1113.     world_changed++;
  1114.     break;
  1115.       case 'D':
  1116.     disconnect_body ();
  1117.     if(!flymode)
  1118.       {
  1119.         body_pose->rz = 0;
  1120.       }
  1121.     world_changed++;
  1122.     break;
  1123.       default:
  1124.     break;
  1125.     }
  1126.   restore_screen();
  1127.   return 0;
  1128. }
  1129.  
  1130.  
  1131.  
  1132. /***************** DISPLAY OPTIONS MENU ***************/
  1133.  
  1134. static int disp_options(void)
  1135. {
  1136.   char buff[20];
  1137.  
  1138.   switch(menu(optmenu))
  1139.     {
  1140.       case 'M':
  1141.         animatemode = !animatemode;
  1142.         break;
  1143.       case 'S':
  1144.         do_screen_clear = !do_screen_clear;
  1145.         popmsg(do_screen_clear ? "Will clear" : "Won't clear");
  1146.         set_horizon(1,NULL,0);
  1147.         tdelay(600);               // so menu is erased
  1148.         restore_screen();
  1149.         if (!do_screen_clear) set_horizon(0,NULL,0);
  1150.         else
  1151.           {
  1152.             if (do_horizon) set_horizon(2,NULL,0);
  1153.             else  set_horizon(1,NULL,0);
  1154.           }
  1155.         display_changed++;
  1156.         break;
  1157.       case 'D':
  1158.          {
  1159.         int s = (get_light_type(light1)==POINT_LIGHT) ? SPOT_LIGHT : POINT_LIGHT;
  1160.         set_light_type(light1, s);
  1161.         popmsg(s==SPOT_LIGHT ? "Spotlight" : "Point Source");
  1162.         tdelay(600);
  1163.         world_changed++;
  1164.         break;
  1165.          }
  1166.       case 'H':
  1167.         do_horizon = !do_horizon;
  1168.         if (do_horizon) set_horizon(2,NULL,0);
  1169.         else  set_horizon(1,NULL,0);
  1170.         popmsg(do_horizon ? "Horizon" : "No Horizon");
  1171.         tdelay(600);
  1172.         display_changed++;
  1173.         break;
  1174.       case 'A':
  1175.         askfor("Ambient light: ", buff, 15);
  1176.         set_light_intensity(amb_light, atoi(buff));
  1177.         world_changed++;
  1178.         break;
  1179.       case 'P':
  1180.         show_location = !show_location;
  1181.         reset_screens();
  1182.         display_changed++;
  1183.         break;
  1184.       case 'C':
  1185.         show_compass = !show_compass;
  1186.         reset_screens();
  1187.         display_changed++;
  1188.         break;
  1189.       case 'F':
  1190.         show_framerate = !show_framerate;
  1191.         reset_screens();
  1192.         display_changed++;
  1193.         break;
  1194.       default:
  1195.         break;
  1196.     }
  1197.   restore_screen();
  1198.   return 0;
  1199. }
  1200.  
  1201.  
  1202. /*************** PAINTING MENU OPERATIONS **********/
  1203.  
  1204. static unsigned stype[] = { 0, 0x1000, 0x2000, 0x3000 };
  1205.  
  1206. static unsigned paint = 1;
  1207. static unsigned surface = 0x1000;
  1208. static unsigned paintcolor = 1;
  1209.  
  1210. static void surf_it(OBJECT *obj)
  1211. {
  1212.   masked_recolor_object_surface(obj, surface, 0x3000, 0);
  1213. }
  1214.  
  1215. static void color_it(OBJECT *obj)
  1216. {
  1217.   masked_recolor_object_surface(obj, paint, 0x3FFF, 0);
  1218. }
  1219.  
  1220.  
  1221. static unsigned int get_surface(void)
  1222. {
  1223.   save_screen();
  1224.   switch (menu(surfmenu))
  1225.     {
  1226.       case 'A':
  1227.         surface = stype[0];
  1228.         break;
  1229.       case 'C':
  1230.         surface = stype[1];
  1231.         break;
  1232.       case 'M':
  1233.         surface = stype[2];
  1234.         break;
  1235.       case 'G':
  1236.         surface = stype[3];
  1237.         break;
  1238.       default:
  1239.         return 1;
  1240.     }
  1241.   if (surface == 0) paint = paintcolor;
  1242.   else paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
  1243.   restore_screen();
  1244.   while (bioskey(1)) bioskey(0); /* flush keyboard buffer */
  1245.   return 0;
  1246. }
  1247.  
  1248.  
  1249. static int painting(void)
  1250. {
  1251.   int x, y, c, i;
  1252.   unsigned buttons;
  1253.   char buff[100];
  1254.  
  1255.   if (!can_point_2D()) return 3;
  1256.   save_screen();
  1257.  
  1258.   switch (menu(paintmenu))
  1259.     {
  1260.       case 'S':/* select surface */
  1261.      get_surface();
  1262.      break;
  1263.  
  1264.       case 'C':/* select color */
  1265.      if (!can_point_2D()) break;
  1266.      if (!manip_2D_avail) break;
  1267.      disp_palette();
  1268.      do {
  1269.           move_till_click(cursor_device, 1, &x, &y);
  1270.         }
  1271.          while (y>128 || x>160);
  1272.      paintcolor = 16*(y/8) + x/10;
  1273.      if (surface == 0)
  1274.         paint = paintcolor;
  1275.      else
  1276.         paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
  1277.      world_changed++;
  1278.      break;
  1279.  
  1280.       case 'G':
  1281.       restore_screen();
  1282.       while (1)
  1283.         {
  1284.           int poly;
  1285.           WORD buttons;
  1286.           OBJECT *obj;
  1287.  
  1288.           if (kbhit()) break;
  1289.           obj = move_and_find_object_2D(cursor_device, &buttons);
  1290.           if (obj)
  1291.         {
  1292.           poly = screen_found_poly();
  1293.           if(buttons & 0x01)
  1294.             {
  1295.               get_poly_info(obj, poly, &c, NULL);
  1296.               c &= 0x7FFF;
  1297.               sprintf(buff,"Poly Color: 0x%04x", c);
  1298.                       save_screen();
  1299.               popmsg(buff);
  1300.               while(1)
  1301.             {
  1302.               int button;
  1303.               mouse_read(cursor_device,NULL,NULL,&button);
  1304.               if(!button) break;
  1305.             }
  1306.               restore_screen();
  1307.               surface = c & 0x7000;
  1308.               paintcolor = c & 0xFFF;
  1309.               paint = c;
  1310.             }
  1311.           else break;
  1312.         }
  1313.         }
  1314.       while (kbhit()) getch();
  1315.       world_changed++;
  1316.       break;
  1317.  
  1318.       case 'P':
  1319.       restore_screen();
  1320.       while (1)
  1321.         {
  1322.           int poly;
  1323.           WORD buttons;
  1324.           OBJECT *obj;
  1325.  
  1326.           if (kbhit()) break;
  1327.           obj = move_and_find_object_2D(cursor_device, &buttons);
  1328.           if (obj)
  1329.         {
  1330.           poly = screen_found_poly();
  1331.           if(buttons & 0x01)
  1332.             {
  1333.               set_poly_color(obj, poly, paint);
  1334.               screen_refresh(current_camera);
  1335.             }
  1336.           else if (buttons & 0x02)
  1337.             {
  1338.               get_poly_info(obj, poly, &c, NULL);
  1339.               c &= 0x7FFF;
  1340.               sprintf(buff,"Poly Color: 0x%04x", c);
  1341.               save_screen();
  1342.               popmsg(buff);
  1343.               while(1)
  1344.             {
  1345.               int button;
  1346.               mouse_read(cursor_device,NULL,NULL,&button);
  1347.               if(!button) break;
  1348.             }
  1349.               restore_screen();
  1350.               surface = c & 0x7000;
  1351.               paintcolor = c & 0xFFF;
  1352.               paint = c;
  1353.             }
  1354.         }
  1355.         }
  1356.       while (kbhit()) getch();
  1357.       world_changed++;
  1358.       break;
  1359.  
  1360.       case 'R':
  1361.       restore_screen();
  1362.       if(get_surface()) break;
  1363.       do_for_all_selected(surf_it);
  1364.       world_changed++;
  1365.       break;
  1366.  
  1367.       case 'A':
  1368.       do_for_all_selected(color_it);
  1369.       world_changed++;
  1370.       break;
  1371.       default:
  1372.       break;
  1373.     }
  1374.   restore_screen();
  1375.   return 0;
  1376. }
  1377.  
  1378.  
  1379. /****************** MAIN MENU *************/
  1380.  
  1381. static int main_menu(void)
  1382. {
  1383.   switch(menu(mainmenu))
  1384.     {
  1385.       case 'Q':
  1386.      process_a_key('Q');
  1387.      break;
  1388.       case 'I':
  1389.      process_a_key('I');
  1390.      break;
  1391.       case 'H':
  1392.      process_a_key('H');
  1393.      break;
  1394.       case 'O':
  1395.      process_a_key('O');
  1396.      break;
  1397.       case 'P':
  1398.      process_a_key('P');
  1399.      break;
  1400.       case 'F':
  1401.      process_a_key('F');
  1402.      break;
  1403.       case 'M':
  1404.      process_a_key('M');
  1405.      break;
  1406.       case 'D':
  1407.      disp_options();
  1408.      break;
  1409.       case 'V':
  1410.      view_menu();
  1411.      break;
  1412.       default:
  1413.      break;
  1414.     }
  1415.   restore_screen();
  1416.   return 0;
  1417. }
  1418.  
  1419.  
  1420.  
  1421.  
  1422. /******************* SPINNING VIEW COMPUTE **************/
  1423.  
  1424.  
  1425. static l_x = 1000, l_y = 15000, l_z = -5000; /* light source */
  1426.  
  1427. long center_d = 10000;
  1428. long center_x = 0;
  1429. long center_y = 0;
  1430. long center_z = 0;
  1431. long latitude = 0;
  1432. long longitude = 0;
  1433. long center_roll = 0;
  1434.  
  1435. static long light_d = 1000000;
  1436.  
  1437. void spin_mode_compute() /* for spin mode: recompute viewpoint based on */
  1438. {                             /* view angle and distance so object centered  */
  1439.   MATRIX m,n;
  1440.   POSE p = DONTCARE_POSE;
  1441.  
  1442.   long x = 0;
  1443.   long y = 0;
  1444.   long z = -center_d;
  1445.  
  1446.   latitude = body_pose->ry;     // angles of vision
  1447.   longitude = body_pose->rx;
  1448.   center_roll = body_pose->rz;
  1449.  
  1450.   std_matrix(n,longitude,latitude,center_roll,0,0,0);
  1451.   matrix_point(n,&x,&y,&z);
  1452.   body_pose->x = x + center_x;  // shift to distance from view center
  1453.   body_pose->y = y + center_y;
  1454.   body_pose->z = z + center_z;
  1455.  
  1456.   if(get_light_type(light1)==POINT_LIGHT)    // some attempt for
  1457.     {                                        // interesting lighting
  1458.       x = l_x;
  1459.       y = l_y;
  1460.       z = l_z;
  1461.       matrix_point(n,&x,&y,&z);
  1462.       p.x = x;
  1463.       p.y = x;
  1464.       p.z = x;
  1465.       position_pointlight(light1, &p);
  1466.     }
  1467.   else
  1468.     {
  1469.       p.rx = longitude + float2angle(45);
  1470.       p.ry = latitude + float2angle(45);
  1471.       p.rz = 0;
  1472.       rotate_spotlight(light1, &p);
  1473.     }
  1474. }
  1475.  
  1476.  
  1477. /********************** KEY INTERPERTER *****************/
  1478.  
  1479. void view_menu(void), mouse_menu(void), stereo_info(void);
  1480.  
  1481. extern BOOL process_motion_keys(unsigned key);
  1482.  
  1483. BOOL process_display_keys(unsigned c)    // processes and display setup keys
  1484. {
  1485.   int i, j;
  1486.  
  1487.   switch (c)
  1488.     {
  1489.     case CTRLLEFT:
  1490.         i = +1;
  1491.         goto set_shift;
  1492.     case CTRLRIGHT:
  1493.         i = -1;
  1494.       set_shift:
  1495.         if (current_camera->stereo->window[LEFT_EYE].orientation&XFLIP)
  1496.            current_camera->stereo->window[LEFT_EYE].xoff += i;
  1497.         else
  1498.            current_camera->stereo->window[LEFT_EYE].xoff -= i;
  1499.  
  1500.         if (current_camera->stereo->window[RIGHT_EYE].orientation&XFLIP)
  1501.            current_camera->stereo->window[RIGHT_EYE].xoff -= i;
  1502.         else
  1503.            current_camera->stereo->window[RIGHT_EYE].xoff += i;
  1504.  
  1505.         compute_camera_factors(current_camera);
  1506.         display_changed++;
  1507.         break;
  1508.     case '+':
  1509.         if (stereo_type == MONOSCOPIC)
  1510.           {
  1511.             SCALE z = get_camera_zoom(current_camera);
  1512.             z *= 1.1;
  1513.             if(z<65536L*0.5) z = 65536L*0.5;
  1514.             if(z>65536L*16.0) z = 65536L*16.0;
  1515.             set_camera_zoom(current_camera,z);
  1516.           }
  1517.         else
  1518.           {
  1519.             if(current_camera->stereo->phys_screen_dist>30)
  1520.             current_camera->stereo->phys_screen_dist *= 1.05;
  1521.             else current_camera->stereo->phys_screen_dist *= 1.25;
  1522.           }
  1523.         compute_camera_factors(current_camera);
  1524.         display_changed++;
  1525.         break;
  1526.     case '-':
  1527.         if (stereo_type == MONOSCOPIC)
  1528.           {
  1529.             SCALE z = get_camera_zoom(current_camera);
  1530.             z /= 1.1;
  1531.             if(z<65536L*0.5) z = 65536L*0.5;
  1532.             if(z>65536L*16.0) z = 65536L*16.0;
  1533.             set_camera_zoom(current_camera,z);
  1534.             compute_camera_factors(current_camera);
  1535.             display_changed++;
  1536.             break;
  1537.           }
  1538.         else
  1539.           {
  1540.             current_camera->stereo->phys_screen_dist /= 1.05;
  1541.             if(current_camera->stereo->phys_screen_dist<5)
  1542.                current_camera->stereo->phys_screen_dist = 5;
  1543.           }
  1544.          compute_camera_factors(current_camera);
  1545.          display_changed++;
  1546.          break;
  1547.     case '@':
  1548.         if (stereo_type != MONOSCOPIC)
  1549.           {
  1550.             current_camera->stereo->phys_eye_spacing /= 1.05;
  1551.             if(current_camera->stereo->phys_eye_spacing<5)
  1552.             current_camera->stereo->phys_eye_spacing = 5;
  1553.             compute_camera_factors(current_camera);
  1554.             display_changed++;
  1555.           }
  1556.         break;
  1557.     case '!':
  1558.         if (stereo_type != MONOSCOPIC)
  1559.           {
  1560.             if(current_camera->stereo->phys_eye_spacing>30)
  1561.                current_camera->stereo->phys_eye_spacing *= 1.05;
  1562.             else
  1563.                current_camera->stereo->phys_eye_spacing *= 1.25;
  1564.             compute_camera_factors(current_camera);
  1565.             display_changed++;
  1566.           }
  1567.         break;
  1568.     default:
  1569.         return FALSE;
  1570.     }
  1571.  return TRUE;
  1572. }
  1573.  
  1574.  
  1575. BOOL process_info_keys(unsigned c)    // processes daata-display keys
  1576. {
  1577.   int i, j;
  1578.  
  1579.   switch (c)
  1580.     {
  1581.     case 'H':
  1582.         save_screen();
  1583.         poptext(helptext);
  1584.         get_response(1);
  1585.         restore_screen();
  1586.         break;
  1587.     case 'I':
  1588.           {
  1589.         POSE p;
  1590.         get_camera_worldpose(current_camera,&p);
  1591.         save_screen();
  1592.         disp_status(&p);
  1593.         get_response(1);
  1594.         restore_screen();
  1595.         break;
  1596.           }
  1597.     case '$':
  1598.         stereo_info();
  1599.         break;
  1600.     case 'C':
  1601.         save_screen();
  1602.         disp_palette();
  1603.         get_response(1);
  1604.         restore_screen();
  1605.         break;
  1606.     default:
  1607.         return FALSE;
  1608.     }
  1609.   return TRUE;
  1610. }
  1611.  
  1612.  
  1613. TELEPORT *fnkeyposn[10] =
  1614.     { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
  1615. TELEPORT *fnkeyhome[10];
  1616.  
  1617. WORD current_teleport = 0;    // where to go home to
  1618.  
  1619. extern OBJECT *body_vehicle_object;
  1620.  
  1621.  
  1622. BOOL process_teleport_keys(unsigned c)    // processes teleport and home keys
  1623. {
  1624.   int i, j;
  1625.  
  1626.   switch (c)
  1627.     {
  1628.     case F1:
  1629.     case F2:
  1630.     case F3:
  1631.     case F4:
  1632.     case F5:
  1633.     case F6:
  1634.     case F7:
  1635.     case F8:
  1636.     case F9:
  1637.     case F10:
  1638.          {
  1639.         i = (c- F1) >> 8;
  1640.         if(i==current_teleport) break;
  1641.                     // record current position for return
  1642.         teleport_set_here(fnkeyposn[current_teleport], body_pose);
  1643.         teleport_set_vehicle(fnkeyposn[current_teleport],
  1644.                      body_vehicle_object,NULL);
  1645.         current_teleport = i;    // set home number
  1646.         if(fnkeyposn[i])
  1647.           {
  1648.             teleport_to(fnkeyposn[i]);
  1649.           }
  1650.         else
  1651.           {
  1652.             fnkeyposn[i] = create_teleport();  // records current state
  1653.             fnkeyhome[i] = create_teleport();
  1654.           }
  1655.         position_changed++;
  1656.         break;
  1657.           }
  1658.     case HOME:
  1659.         if(fnkeyposn[current_teleport])
  1660.           {
  1661.             teleport_to(fnkeyhome[current_teleport]);
  1662.           }
  1663.         position_changed++;
  1664.         break;
  1665.  
  1666.     default:
  1667.         return FALSE;
  1668.     }
  1669.   return TRUE;
  1670. }
  1671.  
  1672.  
  1673. BOOL process_system_keys(unsigned c)    // processes quit, etc
  1674. {
  1675.   int i, j;
  1676.  
  1677.   switch (c)
  1678.     {
  1679.     case 'A':
  1680.         animatemode = !animatemode;
  1681.         break;
  1682.     case TAB:
  1683.         if(animatemode==0) animatemode = -1;
  1684.         break;
  1685.  
  1686.     case '^':
  1687.         save_pcx_file();
  1688.         break;
  1689.  
  1690.     case 'Q':
  1691.     case ESC:
  1692.         popmsg("Really quit?");
  1693.         i = get_response(1);
  1694.         if (toupper(i)=='Y') running = 0;
  1695.         else restore_screen();
  1696.         break;
  1697.     default:
  1698.         return FALSE;
  1699.     }
  1700.   return TRUE;
  1701. }
  1702.  
  1703. extern int mouse_nav;
  1704.  
  1705. static int movemults[] = { 1,2,3,5,7,10,13,17,22,28};  // speed, angles
  1706. static int angmults[] =  { 1,1,1,1,2,2,2,3,4,5};       // 0-9 scale factors
  1707.  
  1708.  
  1709. BOOL process_extmove_keys(unsigned c)    // processes daata-display keys
  1710. {
  1711.   int i, j;
  1712.  
  1713.   switch (c)
  1714.     {
  1715.  
  1716.     case '*':   /* level view */
  1717.         body_pose->rx = body_pose->rz = 0;
  1718.         display_changed++;
  1719.         break;
  1720.  
  1721.     case 'U':
  1722.         body_pose->ry += 180*65536L;
  1723.         position_changed++;
  1724.         break;
  1725.  
  1726.     case '0':
  1727.         sstepsize = movemults[9];
  1728.         astepsize = angmults[9];
  1729.         break;
  1730.     case '1':
  1731.     case '2':
  1732.     case '3':
  1733.     case '4':
  1734.     case '5':
  1735.     case '6':
  1736.     case '7':
  1737.     case '8':
  1738.     case '9':
  1739.         sstepsize = movemults[c - '1'];
  1740.         astepsize = angmults[c - '1'];
  1741.         break;
  1742.  
  1743.     case 'S':
  1744.         if(spinmode) spinmode = 0;
  1745.         else
  1746.           {
  1747.             OBJECT *newobj = NULL;
  1748.             float dist;
  1749.  
  1750.             save_screen();
  1751.             if (can_point_2D() && manip_2D_avail)
  1752.               {
  1753.             restore_screen();
  1754.             popmsg("Click on object to spin about");
  1755.             tdelay(500);
  1756.             restore_screen();
  1757.             while(!newobj)
  1758.               {
  1759.                 newobj = move_and_find_object_2D(cursor_device,NULL);
  1760.                 if(kbhit()) break;
  1761.               }
  1762.             if(!newobj) break;
  1763.             get_object_bounds(newobj, ¢er_x, ¢er_y, ¢er_z);
  1764.               }
  1765.             center_d = magnitude32(center_x - body_pose->x,
  1766.                        center_y - body_pose->y,
  1767.                        center_z - body_pose->z );
  1768.             spinmode = 1;
  1769.           }
  1770.         break;
  1771.  
  1772.     case 'J':
  1773.         mouse_nav = !mouse_nav;     // toggle mouse joy
  1774.         if(manip_2D_avail)
  1775.           cursor_enable(!mouse_nav);  // cursor on/off
  1776.         break;
  1777.  
  1778.  
  1779.     default:
  1780.         return FALSE;
  1781.     }
  1782.   return TRUE;
  1783. }
  1784.  
  1785.  
  1786. BOOL process_menu_keys(unsigned c)    // processes menu-entry keys
  1787. {
  1788.   int i, j;
  1789.  
  1790.   switch (c)
  1791.     {
  1792.     case 'X':
  1793.         main_menu();
  1794.         break;
  1795.     case 'D':
  1796.         disp_options();
  1797.         restore_screen();
  1798.         break;
  1799.     case 'O':
  1800.         obj_menu();
  1801.         break;
  1802.     case 'F':
  1803.         fig_menu();
  1804.         break;
  1805.     case 'P':
  1806.         painting();
  1807.         break;
  1808.     case 'M':
  1809.         mouse_menu();
  1810.         break;
  1811.     case 'V':
  1812.         view_menu();
  1813.         break;
  1814.     default:
  1815.         return FALSE;
  1816.     }
  1817.   return TRUE;
  1818. }
  1819.  
  1820.  
  1821. /************ API KEY HANDLER **************/
  1822.  
  1823. void process_a_key(unsigned c)    // processes key <c>
  1824. {
  1825.   int i, j;
  1826.  
  1827.   if(c<0x7f)
  1828.      if(isalpha(c))
  1829.     c = toupper(c);
  1830.  
  1831.   if(process_motion_keys(c)) return;
  1832.   if(process_display_keys(c)) return;
  1833.   if(process_info_keys(c)) return;
  1834.   if(process_teleport_keys(c)) return;
  1835.   if(process_system_keys(c)) return;
  1836.   if(process_extmove_keys(c)) return;
  1837.   if(process_menu_keys(c)) return;
  1838. }
  1839.  
  1840.  
  1841. void key_process()    // reads, processes keys
  1842. {
  1843.   unsigned c;
  1844.  
  1845.   if (!bioskey(1)) return;
  1846.   c = getkey();            // read a key
  1847.   while(bioskey(1)) getkey();   // dump others
  1848.  
  1849.   process_a_key(c);
  1850. }
  1851.  
  1852.  
  1853. /************ API JOYSTICK HANDLER **************/
  1854.  
  1855.  
  1856. void joystick_process()
  1857. {
  1858.   if(do_joy_navigate(body_pose,
  1859.         spinmode, spacestep*sstepsize, astepsize*anglestep, flymode))
  1860.       position_changed ++;
  1861.  
  1862.   if (position_changed && spinmode)         // SPECIAL: spin mode move xlat
  1863.             spin_mode_compute();
  1864. }
  1865.  
  1866.