home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 16
/
CD_ASCQ_16_0994.iso
/
news
/
vr386
/
keyboard.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-19
|
41KB
|
1,866 lines
/* Keyboard routines and menus for VRC release */
/* Original simple keyboard was written by Bernie Roehl, July 1992 */
// MASSIVELY rewritten, along with entire menu and navigation
// system, by Dave Stampe for Release 5 (VRC), Nov. 92.
// some changes made to support horizon and key monitor, 12/24/93
// Completely rearranged, substantial mods, ported to VR-386 API 9/1/94
/*
This code is part of the VR-386 project, created by Dave Stampe.
VR-386 is a desendent of REND386, created by Dave Stampe and
Bernie Roehl. Almost all the code has been rewritten by Dave
Stampre for VR-386.
Copyright (c) 1994 by Dave Stampe:
May be freely used to write software for release into the public domain
or for educational use; all commercial endeavours MUST contact Dave Stampe
(dstampe@psych.toronto.edu) for permission to incorporate any part of
this software or source code into their products! Usually there is no
charge for under 50-100 items for low-cost or shareware products, and terms
are reasonable. Any royalties are used for development, so equipment is
often acceptable payment.
ATTRIBUTION: If you use any part of this source code or the libraries
in your projects, you must give attribution to VR-386 and Dave Stampe,
and any other authors in your documentation, source code, and at startup
of your program. Let's keep the freeware ball rolling!
DEVELOPMENT: VR-386 is a effort to develop the process started by
REND386, improving programmer access by rewriting the code and supplying
a standard API. If you write improvements, add new functions rather
than rewriting current functions. This will make it possible to
include you improved code in the next API release. YOU can help advance
VR-386. Comments on the API are welcome.
CONTACT: dstampe@psych.toronto.edu
*/
#include <stdio.h>
#include <stdlib.h> /* for atol(), only for debugging! */
#include <dos.h>
#include <time.h> /* time(), ctime() */
#include <string.h>
#include <math.h>
#include <alloc.h>
#include "config.h"
#include "pointer.h"
#include "vr_api.h"
#include "intmath.h"
#include "segment.h"
#include "splits.h"
#include "pcdevice.h" // last_render_time()
#include "vrconst.h"
extern char *fix_fname(char *fname);
extern manip_2D_avail;
extern void set_horizon(int ncolors, int colors[16], int bandsize);
extern int do_screen_clear, do_horizon;
extern int show_location, show_compass, show_framerate;
extern LIGHT *amb_light, *light1, *light2;
static int sstepsize = 10; /* speed multipliers */
static int astepsize = 2;
long anglestep = 160000L;
long spacestep = 10L;
int spinmode = 0;
extern int flymode;
int floormode = 0;
extern int animatemode;
extern int old_angle_order; /* in wparse.c */
/******************* MENU TEXT **************/
static char *helptext[] = {
"X calls up MAIN MENU",
"O calls up OBJECT MENU",
"P calls up PAINT MENU",
"F calls up FIGURE MENU",
"V calls up VIEW MENU",
"M calls up MANIPULATE MENU",
"D calls up DISPLAY OPTIONS MENU",
"ARROWS drive around",
"RIGHT SHIFT+ARROWS look around",
"LEFT SHIFT+ARROWS move up, sideways",
"CTRL+ARROWS set stereo offset",
"J toggles mouse motion, U u-turns",
"+ and - changes zoom",
"R repeats last arrow key move 100x",
"0-9 set step or angle size",
"F1-F10 select viewpoint",
"HOME returns to starting point",
"Q or ESC quits, ? or H shows help",
"I displays view information",
"S sets/resets object spin mode",
"C displays color palette",
"A toggles animation on/off",
NULL
};
static char *mainmenu[] = {
"Help",
"Information",
"View menu",
"Paint menu",
"Display menu",
"Object menu",
"Figure menu",
"Mouse menu",
"Quit",
NULL
};
static char *viewmenu[] = {
"Information",
"Spin about object",
"Fly mode toggle",
"fLoor mode toggle",
"Return to start",
"Move step size",
"Turn step set",
"Go to (x,y,z) location",
"look Angle ",
"View window size",
"Hither clipping depth",
"Yon clipping depth",
"PCX screen dump",
"Options",
#ifdef ENABLE_STATE_SAVELOAD
"Write state to file",
"eXecute world file",
#endif
NULL
};
static char *paintmenu[] = {
"Select Surface",
"Choose Color",
"Get poly color",
"Paint Polys",
"paint All",
"Resurface",
NULL
};
static char *surfmenu[] = {
"Absolute",
"Cosine-lit",
"Metal",
"Glass",
NULL
};
static char *optmenu[] = {
"aniMation on/off",
"Screen clear",
"Horizon",
"Ambient light",
"Directional light",
"Position display",
"Compass display",
"Frame rate display",
NULL };
static char *mousemenu[] = {
"Move",
"Rotate",
"Twirl",
"Grasp",
"Ungrasp",
NULL
};
static char *objmenu[] = {
"Load object",
"Save object",
"Information",
"Delete object",
"Unselect all",
"First representation",
"Next representation",
NULL
};
static char *figmenu[] = {
"Load figure",
"Information",
"Select all",
"Unselect all",
"Hack off",
"Join to",
"Attach viewpoint",
"Detach viewpoint",
NULL
};
/*************** MORE FEATURES *************/
static int save_pcx_file(void)
{
char filename[100];
char far *buffer;
FILE *out;
BOOL was_visible;
screen_refresh(current_camera);
askfor("File to save to? ", filename, 15);
if (filename[0] == '\0') return 1;
if ((out = fopen(filename, "wb")) == NULL)
{
errprintf("Could not open file");
cursor_show();
return 3;
}
was_visible = cursor_hide();
save_pcx(out, current_video_page);
if(was_visible) cursor_show();
fclose(out);
return 0;
}
extern PDRIVER *cursor_device;
static int resize_viewport(void)
{
int top, left, bottom, right;
unsigned buttons;
if(stereo_type!=MONOSCOPIC && stereo_type!= SWITCHED) return -1;
save_screen();
popmsg("Click top-left and drag");
cursor_show();
do {
move_2D(cursor_device, &left, &top, &buttons);
if(kbhit())
{
getch();
screen_refresh(current_camera);
return 1;
}
} while (buttons == 0);
while (buttons)
{
while (!move_2D(cursor_device, &right, &bottom, &buttons));
restore_screen();
user_draw_box(left, top, right, bottom, 15);
}
cursor_hide();
if (right - left > 10)
{
left = left & (~0x0007); /* always on an 8-pixel boundary */
right = (right & (~0x0007)) + 7;
}
else return -1;
if (bottom - top < 10) return -1;
set_camera_window(current_camera, left, top, right, bottom);
if (stereo_type == SWITCHED) /* makes sense for Sega only (no shift) */
{
STEREO *s = current_camera->stereo;
s->pixel_width = right-left+1;
s->window[LEFT_EYE].l = left;
s->window[LEFT_EYE].t = top;
s->window[LEFT_EYE].r = right;
s->window[LEFT_EYE].b = bottom;
s->window[RIGHT_EYE].l = left;
s->window[RIGHT_EYE].t = top;
s->window[RIGHT_EYE].r = right;
s->window[RIGHT_EYE].b = bottom;
}
compute_camera_factors(current_camera);
display_changed++;
cursor_hide();
reset_screens();
return 0;
}
/*************** STATUS DISPLAYS ETC. ************/
static void center(char *s, int w) // centers text string
{
int n;
if (strlen(s) == 0) return;
n = (w - strlen(s)) /2;
memmove(&s[n], s, strlen(s)+1);
memset(s, ' ', n);
}
static int nobjs, nverts, npolys;
static void gather_data(OBJECT *obj)
{
int nv = 0, np = 0;
get_obj_info(obj, &nv, &np);
++nobjs;
nverts += nv;
npolys += np;
}
static disp_status(POSE *p)
{
char *text[10], a[80], b[80], c[80], d[80], e[80], f[80], g[80], h[80];
int w, i;
VIEW *v = current_camera->mono;
text[0] = a;
text[1] = "";
text[2] = b;
text[3] = c;
text[4] = d;
text[5] = e;
text[6] = f;
text[7] = g;
text[8] = h;
text[9] = NULL;
sprintf(a, "STATUS");
sprintf(b, "X = %ld Y = %ld Z = %ld", p->x, p->y, p->z);
w = strlen(b);
if (old_angle_order)
sprintf(c, "Pan = %ld Tilt = %ld Roll = %ld ", p->ry/65536L, p->rx/65536L, p->rz/65536L);
else
sprintf(c, "Tilt = %ld Pan = %ld Roll = %ld ", p->rx/65536L, p->ry/65536L, p->rz/65536L);
if (strlen(c) > w) w = strlen(c);
sprintf(d, "Zoom = %2.2f", scale2float(get_camera_zoom(current_camera)));
if (strlen(d) > w) w = strlen(d);
sprintf(e, "Hither = %ld Yon = %ld", get_camera_hither(current_camera), get_camera_yon(current_camera));
if (strlen(e) > w) w = strlen(e);
nobjs = 0, nverts = 0, npolys = 0;
do_for_all_objects(gather_data);
sprintf(f, "%d object%s, %d vertice%s, %d poly%s",nobjs,(nobjs == 1) ? "" : "s",
nverts, (nverts == 1) ? "" : "s",
npolys, (npolys == 1) ? "" : "s");
sprintf(g, "Ambient light: %d", get_light_intensity(amb_light));
sprintf(h, "Memory Free: %ld", coreleft());
if (strlen(f) > w) w = strlen(f);
if (strlen(g) > w) w = strlen(g);
if (strlen(h) > w) w = strlen(h);
for (i = 0; text[i]; ++i) center(text[i], w);
save_screen();
poptext(text);
return 0;
}
void disp_palette(void) // show 256-color palette
{
int i, j;
BOOL was_visible = cursor_hide();
save_screen();
for (i = 0; i < 16; i++)
for (j = 0; j < 16; j++)
user_box(j*10,i*8,j*10+9,i*8+8,i*16+j);
if(was_visible) cursor_show();
}
/*************** VIEW MENU *************/
void process_a_key(WORD key);
static void view_menu(void)
{
char buff[100], *p;
FILE *out;
char d;
COORD l;
save_screen();
switch (menu(viewmenu))
{
case 'I':
process_a_key('I');
break;
case 'R':
process_a_key (HOME);
position_changed++;
break;
case 'P':
process_a_key('^');
break;
case 'F':
flymode = !flymode;
popmsg(flymode ? "Fly mode" : "Ground mode");
tdelay(350);
break;
case 'L':
floormode = !floormode;
popmsg(floormode ? "Floors used" : "Floors ignored");
tdelay(350);
break;
case 'H':
askfor("Enter hither value:", buff, 10);
if (buff[0])
{
COORD h = atof(buff);
set_camera_hither(current_camera, h);
}
display_changed++;
break;
case 'Y':
askfor("Enter yon value:", buff, 10);
if (buff[0])
{
COORD y = atof(buff);
set_camera_yon(current_camera, y);
}
display_changed++;
break;
case 'G':/* goto XYZ */
askfor("X,Y,Z: ", buff, 25);
if (buff[0])
sscanf(buff, "%ld,%ld,%ld", &body_pose->x, &body_pose->y, &body_pose->z);
position_changed++;
break;
case 'A':/* look at angle */
{
long p, t, r;
askfor("Pan,rx,rz:", buff, 22);
if (buff[0])
{
sscanf(buff, "%ld,%ld,%ld", &p, &t, &r);
body_pose->ry = p*65536L;
body_pose->rx = t*65536L;
body_pose->rz = r*65536L;
}
position_changed++;
}
break;
case 'M':
askfor("Move step: ", buff, 15);
if (buff[0]) spacestep = atoi(buff);
position_changed++;
break;
case 'T':
askfor("Turn angle step: ", buff, 15);
if (buff[0]) anglestep = atof(buff) * 65536L;
position_changed++;
break;
case 'V':
resize_viewport();
display_changed++;
break;
case 'O':
disp_options();
break;
case 'S':
process_a_key('S');
break;
default:
break;
}
restore_screen();
}
static void stereo_info(void)
{
char b1[50]="", b2[50]="", b3[50]="", b4[50]="", b5[50]="", b6[50]="";
char b7[50]="", b8[50]="", b9[50]="";
char *b[10];
STEREO *st = current_camera->stereo;
STWINDOW *swl = &(current_camera->stereo->window[LEFT_EYE]);
STWINDOW *swr = &(current_camera->stereo->window[RIGHT_EYE]);
float xo, xa, conv, ws;
if(stereo_type==MONOSCOPIC) return;
xa = (swl->xoff-swr->xoff)/2.0;
ws = st->world_scaling/65536.0;
xo=(st->phys_eye_spacing * st->phys_screen_dist * st->pixel_width) /
(2.0 * st->phys_screen_width * st->phys_convergence);
conv=(st->phys_eye_spacing * st->phys_screen_dist * st->pixel_width) /
(2.0 * st->phys_screen_width * (xo+xa));
b[0] = b1;
sprintf(b1, " Stereo Parameters");
b[1] = b2;
sprintf(b2, "screen distance: %ld", st->phys_screen_dist);
b[2] = b3;
sprintf(b3, "screen width: %ld", st->phys_screen_width);
b[3] = b4;
sprintf(b4, "pixel width: %ld", st->pixel_width);
b[4] = b5;
sprintf(b5, "eye spacing: %ld", st->phys_eye_spacing);
b[5] = b6;
sprintf(b6, "convergence distance: %ld", st->phys_convergence);
b[6] = b7;
sprintf(b7, "world scaling: %0.2f", ws);
b[7] = b8;
sprintf(b8, "added X offset: %0.0f", xa);
b[8] = b9;
sprintf(b9, "effective convergence: %0.0f", conv);
b[9] = NULL;
save_screen();
poptext(b);
get_response(1);
restore_screen();
}
/************* PROCESS SUPPORT ***********/
static int nselected = 0;
static FILE *save_file = NULL;
static int nsaved = 0;
static void save_it(OBJECT *obj)
{
if(nselected<2) save_plg(obj, save_file, 0); /* only one: save object coords */
else save_plg(obj, save_file, 1); /* else save world coords */
}
static long mxosize = 0;
static void maxsize_it(OBJECT *obj) // find maximum size of figure
{
long s;
if(obj)
{
s = get_object_bounds(obj, NULL, NULL, NULL);
if(s>mxosize) mxosize = s;
}
}
static int numsegs, numverts, numpolys;
static long centx, centy, centz;
static OBJECT *last_figure; // last moveable and visible
// object (split list)
static void count_moveable(OBJECT *obj)
{
++nselected;
get_object_bounds(obj, ¢x, ¢y, ¢z);
if(is_object_moveable(obj))
{
int nv, np;
get_obj_info(obj, &nv, &np);
numverts += nv;
numpolys += np;
last_figure = obj;
numsegs++;
}
}
static void count_all(OBJECT *obj)
{
int nv, np;
get_object_bounds(obj, ¢x, ¢y, ¢z);
get_obj_info(obj, &nv, &np);
numverts += nv;
numpolys += np;
nselected++;
}
static void zap_obj(OBJECT *obj)
{
delete_visobj(obj); // preserve segment so animation doesnt crash
}
extern OBJECT *body_seg;
extern OBJECT *head_seg;
extern OBJECT *wrist_seg;
static void grab_it(OBJECT *obj) // attach to body
{
if(is_object_child_of(body_seg, obj)) return; // can't grab body part!
attach_object(obj, body_seg, 1);
}
static void ungrab_it(OBJECT *obj) // detach from body
{
if(is_object_child_of(body_seg, obj))
detach_object(obj,1);
}
//////// MOVEMENT CALLBACKS
static long ptx, pty, ptz;
static long oldx, oldy, oldz, oldcx, oldcy, oldcz, dx, dy, dz;
static void move_it(OBJECT *obj)
{
if(is_object_moveable(obj))
{
POSE p;
get_object_pose(obj, &p);
p.x += ptx - oldx;
p.y += pty - oldy;
p.z += ptz - oldz;
p.rx = p.ry = p.rz = DONTCARE;
set_object_pose(obj, &p);
update_object(obj);
}
}
static void twirl_it(OBJECT *obj)
{
if(is_object_moveable(obj))
{
POSE p;
get_object_pose(obj, &p);
p.rx += ptx;
p.ry += pty;
p.rz += ptz;
p.x = p.y = p.z = DONTCARE;
set_object_pose(obj, &p);
update_object(obj);
}
}
static void rot_it(OBJECT *obj)
{
if(is_object_moveable(obj))
{
POSE p;
get_object_pose(obj, &p);
p.rx += ptx;
p.ry += pty;
p.rz += ptz;
p.x = p.y = p.z = DONTCARE;
set_object_pose(obj, &p);
update_object(obj);
}
}
static void hack_it(OBJECT *obj)
{
if(is_object_moveable(obj))
{
detach_object(obj, 1);
update_object(obj);
}
}
static OBJECT *newparent = NULL;
static void join_it(OBJECT *obj)
{
if(is_object_moveable(obj))
{
attach_object(obj, newparent, 1);
update_object(obj);
}
}
static void next_it(OBJECT *obj)
{
select_next_representation(obj);
}
static void first_it(OBJECT *obj)
{
select_first_representation(obj);
}
static int check_moveobj(void)
{
nselected = 0;
last_figure = NULL;
do_for_all_selected_moveable(count_moveable);
if (last_figure == NULL)
{
popmsg("No movable objects selected!");
tdelay(600);
return 1;
}
return 0;
}
static int check_obj(void)
{
nselected = 0;
last_figure = NULL;
do_for_all_selected(count_moveable);
if (nselected == 0)
{
popmsg("No objects selected!");
tdelay(600);
return 1;
}
return 0;
}
static void seg_info(int fig)
{
char b1[50]="", b2[50]="", b3[50]="", b4[50]="", b5[50]="", b6[50]="";
char *b[7];
POSE p;
b[0] = b1;
b[1] = b2;
b[2] = b3;
b[3] = b4;
b[4] = b5;
b[5] = b6;
b[6] = NULL;
nselected = 0;
last_figure = NULL;
do_for_all_selected(count_moveable);
sprintf(b6, "Object center:%ld, %ld, %ld", centx, centy, centz);
nobjs = nverts = npolys = 0;
if(fig && last_figure)
{
numsegs = numverts = numpolys = 0;
do_for_selected_related_objects(last_figure, count_moveable);
sprintf(b1, "%d seg%s, %d vert%s, %d poly%s",
numsegs, (numsegs == 1) ? "" : "s",
numverts, (numverts == 1) ? "" : "s",
numpolys, (numpolys == 1) ? "" : "s" );
}
else
{
nselected = numverts = numpolys = 0;
do_for_all_selected(count_all);
sprintf(b1, "%d obj%s, %d vert%s, %d poly%s",
nselected, (nselected == 1) ? "" : "s",
numverts, (numverts == 1) ? "" : "s",
numpolys, (numpolys == 1) ? "" : "s" );
}
if(last_figure==NULL)
{
sprintf(b2," No moveable objects selected");
b[2] = b6;
b[3] = NULL;
}
else
{
get_object_world_pose(last_figure, &p);
sprintf(b2, "World pos'n: %ld %ld %ld", p.x, p.y, p.z);
sprintf(b3, "World angle: %4.1f %4.1f %4.1f", angle2float(p.rx), angle2float(p.ry),angle2float(p.rz));
if(last_figure==NULL || fig==0)
{
get_object_pose(last_figure, &p);
sprintf(b4, "Joint pos'n: %ld %ld %ld", p.x, p.y, p.z);
sprintf(b5, "Joint angle: %4.1f %4.1f %4.1f", angle2float(p.rx), angle2float(p.ry),angle2float(p.rz));
}
else
{
b[4] = b6;
b[3] = b[2];
b[2] = b[1];
b[5] = NULL;
sprintf(b5,"Root of figure:");
b[1] = b5;
}
}
poptext(b);
}
/************* MOUSE MANIPULATION MENU ***********/
extern PDRIVER *cursor_device;
static POINTER pointer;
static void mouse_menu(void)
{
void pointer_to_world();
char buff[100], *p;
char c, d;
unsigned buttons;
int click = 0;
init_pointer(&pointer);
save_screen();
switch(c = menu(mousemenu))
{
case 'M':
restore_screen();
if(check_moveobj()) break;
if (!manip_2D_avail) break;
pointer_read(cursor_device, &pointer);
pointer_to_world(&pointer, current_camera, &ptx, &pty, &ptz);
click = 0;
while (click == 0)
{
screen_refresh(current_camera);
oldx = ptx;
oldy = pty;
oldz = ptz;
click = PNEW_BUT & pointer_read(cursor_device, &pointer);
if (!(pointer.buttons & 1)) click = 0;
pointer_to_world(&pointer, current_camera, &ptx, &pty, &ptz);
do_for_all_selected_moveable(move_it);
}
screen_refresh(current_camera);
world_changed++;
break;
case 'R':
case 'T':
restore_screen();
if(check_moveobj()) break;
if (!manip_2D_avail) break;
pointer_read(cursor_device, &pointer);
oldcx = oldx = pointer.x;
oldcy = oldy = pointer.y;
oldcz = oldz = pointer.z;
while ((pointer.buttons & 0x01) == 0)
{
if (toupper(c) == 'R')
{
ptx = 32768L*(pointer.y - oldy);
pty = -32768L*(pointer.x - oldx);
ptz = -32768L*(pointer.z - oldz);
}
else
{
ptx = 3270L*(pointer.y - oldcy);
pty = -3270L*(pointer.x - oldcx);
ptz = -3270L*(pointer.z - oldcz);
}
rotate_to_view(current_camera, &ptx, &pty, &ptz);
if(toupper(c)=='R') do_for_all_selected_moveable(rot_it);
else do_for_all_selected_moveable(twirl_it);
oldx = pointer.x;
oldy = pointer.y;
oldz = pointer.z;
screen_refresh(current_camera);
pointer_read(cursor_device, &pointer);
}
while (pointer.buttons & 0x01) pointer_read(cursor_device, &pointer);
screen_refresh(current_camera);
world_changed++;
break;
case 'G':
if(check_moveobj()) break;
do_for_all_selected_moveable(grab_it);
world_changed++;
break;
case 'U':
if(check_moveobj()) break;
do_for_all_selected_moveable(ungrab_it);
world_changed++;
break;
default:
break;
}
restore_screen();
}
static int obj_menu(void)
{
char buff[100], *p;
FILE *in, *out;
char c, d;
long x, y, z;
int i;
nselected = 0;
last_figure = NULL;
save_screen();
switch (c=menu(objmenu))
{
case 'L':/* load PLG file */
askfor("File to load? ", buff, 22);
if (buff[0] == '\0') break;
strcpy(buff, fix_fname(buff));
add_ext(buff,"plg");
if ((in = fopen(buff, "r")) == NULL)
{
errprintf("Could not open file");
}
else
{
POSE p = ZERO_POSE;
OBJECT *obj;
long sx = 1, sy = 1, sz = 1;
#ifdef ENABLE_RESIZE_ON_LOAD
askfor("Scale x,y,z: ", buff, 20);
if (buff[0])
sscanf(buff, "%ld,%ld,%ld", &sx, &sy, &sz);
#endif
while ((obj = load_plg_object(in, &p, 1, 1, 1, 0)) != NULL)
{
if (make_fixed_object_moveable(obj,NULL)) // moveable object
{ // now put nicely ahead
mxosize = 0;
do_for_visible_child_objects(obj, maxsize_it);
camera_point_ahead(current_camera, 500+mxosize*4, &p.x, &p.y, &p.z);
set_object_pose(obj, &p);
update_object(obj);
add_object_to_world(obj); // adds to world if not in it
}
else
{
errprintf("Warning -- out of memory!");
world_changed++;
}
}
fclose(in);
}
world_changed++;
break;
case 'S':
restore_screen();
if(check_obj()) break;
if (askfor("Enter filename: ", buff, 20) == 0x1B) break;
if (buff[0] == '\0')
{
world_changed++;
break;
}
nobjs = 0;
add_ext(buff,"plg");
if ((save_file = fopen(buff, "w")) == NULL)
{
errprintf("Could not create file");
world_changed++;
break;
}
nsaved = 0;
do_for_all_selected(save_it);
fclose(save_file);
save_file = NULL;
screen_refresh(current_camera);
sprintf(buff, "Saved %d object%s", nselected, (nselected > 1) ? "s" : "");
popmsg(buff);
get_response(1);
world_changed++;
fclose(out);
break;
case 'I':
{
seg_info(0);
get_response(1);
break;
}
case 'D':
restore_screen();
if(check_obj()) break;
sprintf(buff, "Delete %d object%s! Are you sure?",
nselected, (nselected > 1) ? "s" : "");
popmsg(buff);
i = get_response(1);
if (toupper(i) != 'Y') break;
restore_screen();
do_for_all_selected(zap_obj);
world_changed++;
break;
case 'U':
do_for_all_selected(unhighlight_object);
world_changed++;
break;
case 'F':
if(check_obj()) break;
do_for_all_selected(first_it);
world_changed++;
break;
case 'N':
if(check_obj()) break;
do_for_all_selected(next_it);
world_changed++;
break;
default: break;
}
restore_screen();
return 0;
}
/************** FIGURE MENU *************/
static int fig_menu(void)
{
char buff[100], *p;
FILE *in, *out;
char c, d;
long x, y, z;
int mx, my;
save_screen();
switch (menu(figmenu))
{
case 'L':
askfor("Figure file to read? ", buff, 15);
if (buff[0] == '\0') break;
add_ext(buff,"fig");
if ((in = fopen(buff, "r")) == NULL)
{
errprintf("Could not open figure file");
}
else
{
OBJECT *obj;
POSE p = DONTCARE_POSE;
obj = load_figure_as_object(in, default_objlist, NULL, 0, 1, 1, 1);
if (!obj)
{
errprintf("%s",seg_error(NULL));
world_changed++;
}
else
{
add_objlist_to_world(default_objlist);
mxosize = 0;
do_for_visible_child_objects(obj, maxsize_it);
camera_point_ahead(current_camera, 1000+mxosize, &p.x, &p.y, &p.z);
set_object_pose(obj, &p);
update_object(obj);
}
}
world_changed++;
break;
case 'I':
seg_info(1);
get_response(1);
break;
case 'S':
if(check_moveobj()) break;
do_for_visible_related_objects(last_figure, highlight_object); /* and down again */
break;
case 'U':
do_for_all_selected_moveable(unhighlight_object);
world_changed++;
break;
case 'H':
if(check_moveobj()) break;
screen_refresh(current_camera);
do_for_all_selected_moveable(hack_it);
world_changed++;
break;
case 'J':
if (check_moveobj()) break;
if (!can_point_2D()) break;
if (!manip_2D_avail) break;
popmsg("Click on new parent");
tdelay(500);
restore_screen();
newparent = NULL;
while(!newparent)
{
if(kbhit()) break;
newparent = move_and_find_object_2D(cursor_device, NULL);
if(!is_object_moveable(newparent)) newparent = NULL;
}
if(!newparent) break;
do_for_all_selected_moveable(join_it);
world_changed++;
break;
case 'A':
if(check_moveobj()) break;
connect_body(last_figure);
world_changed++;
break;
case 'D':
disconnect_body ();
if(!flymode)
{
body_pose->rz = 0;
}
world_changed++;
break;
default:
break;
}
restore_screen();
return 0;
}
/***************** DISPLAY OPTIONS MENU ***************/
static int disp_options(void)
{
char buff[20];
switch(menu(optmenu))
{
case 'M':
animatemode = !animatemode;
break;
case 'S':
do_screen_clear = !do_screen_clear;
popmsg(do_screen_clear ? "Will clear" : "Won't clear");
set_horizon(1,NULL,0);
tdelay(600); // so menu is erased
restore_screen();
if (!do_screen_clear) set_horizon(0,NULL,0);
else
{
if (do_horizon) set_horizon(2,NULL,0);
else set_horizon(1,NULL,0);
}
display_changed++;
break;
case 'D':
{
int s = (get_light_type(light1)==POINT_LIGHT) ? SPOT_LIGHT : POINT_LIGHT;
set_light_type(light1, s);
popmsg(s==SPOT_LIGHT ? "Spotlight" : "Point Source");
tdelay(600);
world_changed++;
break;
}
case 'H':
do_horizon = !do_horizon;
if (do_horizon) set_horizon(2,NULL,0);
else set_horizon(1,NULL,0);
popmsg(do_horizon ? "Horizon" : "No Horizon");
tdelay(600);
display_changed++;
break;
case 'A':
askfor("Ambient light: ", buff, 15);
set_light_intensity(amb_light, atoi(buff));
world_changed++;
break;
case 'P':
show_location = !show_location;
reset_screens();
display_changed++;
break;
case 'C':
show_compass = !show_compass;
reset_screens();
display_changed++;
break;
case 'F':
show_framerate = !show_framerate;
reset_screens();
display_changed++;
break;
default:
break;
}
restore_screen();
return 0;
}
/*************** PAINTING MENU OPERATIONS **********/
static unsigned stype[] = { 0, 0x1000, 0x2000, 0x3000 };
static unsigned paint = 1;
static unsigned surface = 0x1000;
static unsigned paintcolor = 1;
static void surf_it(OBJECT *obj)
{
masked_recolor_object_surface(obj, surface, 0x3000, 0);
}
static void color_it(OBJECT *obj)
{
masked_recolor_object_surface(obj, paint, 0x3FFF, 0);
}
static unsigned int get_surface(void)
{
save_screen();
switch (menu(surfmenu))
{
case 'A':
surface = stype[0];
break;
case 'C':
surface = stype[1];
break;
case 'M':
surface = stype[2];
break;
case 'G':
surface = stype[3];
break;
default:
return 1;
}
if (surface == 0) paint = paintcolor;
else paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
restore_screen();
while (bioskey(1)) bioskey(0); /* flush keyboard buffer */
return 0;
}
static int painting(void)
{
int x, y, c, i;
unsigned buttons;
char buff[100];
if (!can_point_2D()) return 3;
save_screen();
switch (menu(paintmenu))
{
case 'S':/* select surface */
get_surface();
break;
case 'C':/* select color */
if (!can_point_2D()) break;
if (!manip_2D_avail) break;
disp_palette();
do {
move_till_click(cursor_device, 1, &x, &y);
}
while (y>128 || x>160);
paintcolor = 16*(y/8) + x/10;
if (surface == 0)
paint = paintcolor;
else
paint = (surface | ((paintcolor << 4) & 0x0FF0) + 10); /* hue, brightness *16 */
world_changed++;
break;
case 'G':
restore_screen();
while (1)
{
int poly;
WORD buttons;
OBJECT *obj;
if (kbhit()) break;
obj = move_and_find_object_2D(cursor_device, &buttons);
if (obj)
{
poly = screen_found_poly();
if(buttons & 0x01)
{
get_poly_info(obj, poly, &c, NULL);
c &= 0x7FFF;
sprintf(buff,"Poly Color: 0x%04x", c);
save_screen();
popmsg(buff);
while(1)
{
int button;
mouse_read(cursor_device,NULL,NULL,&button);
if(!button) break;
}
restore_screen();
surface = c & 0x7000;
paintcolor = c & 0xFFF;
paint = c;
}
else break;
}
}
while (kbhit()) getch();
world_changed++;
break;
case 'P':
restore_screen();
while (1)
{
int poly;
WORD buttons;
OBJECT *obj;
if (kbhit()) break;
obj = move_and_find_object_2D(cursor_device, &buttons);
if (obj)
{
poly = screen_found_poly();
if(buttons & 0x01)
{
set_poly_color(obj, poly, paint);
screen_refresh(current_camera);
}
else if (buttons & 0x02)
{
get_poly_info(obj, poly, &c, NULL);
c &= 0x7FFF;
sprintf(buff,"Poly Color: 0x%04x", c);
save_screen();
popmsg(buff);
while(1)
{
int button;
mouse_read(cursor_device,NULL,NULL,&button);
if(!button) break;
}
restore_screen();
surface = c & 0x7000;
paintcolor = c & 0xFFF;
paint = c;
}
}
}
while (kbhit()) getch();
world_changed++;
break;
case 'R':
restore_screen();
if(get_surface()) break;
do_for_all_selected(surf_it);
world_changed++;
break;
case 'A':
do_for_all_selected(color_it);
world_changed++;
break;
default:
break;
}
restore_screen();
return 0;
}
/****************** MAIN MENU *************/
static int main_menu(void)
{
switch(menu(mainmenu))
{
case 'Q':
process_a_key('Q');
break;
case 'I':
process_a_key('I');
break;
case 'H':
process_a_key('H');
break;
case 'O':
process_a_key('O');
break;
case 'P':
process_a_key('P');
break;
case 'F':
process_a_key('F');
break;
case 'M':
process_a_key('M');
break;
case 'D':
disp_options();
break;
case 'V':
view_menu();
break;
default:
break;
}
restore_screen();
return 0;
}
/******************* SPINNING VIEW COMPUTE **************/
static l_x = 1000, l_y = 15000, l_z = -5000; /* light source */
long center_d = 10000;
long center_x = 0;
long center_y = 0;
long center_z = 0;
long latitude = 0;
long longitude = 0;
long center_roll = 0;
static long light_d = 1000000;
void spin_mode_compute() /* for spin mode: recompute viewpoint based on */
{ /* view angle and distance so object centered */
MATRIX m,n;
POSE p = DONTCARE_POSE;
long x = 0;
long y = 0;
long z = -center_d;
latitude = body_pose->ry; // angles of vision
longitude = body_pose->rx;
center_roll = body_pose->rz;
std_matrix(n,longitude,latitude,center_roll,0,0,0);
matrix_point(n,&x,&y,&z);
body_pose->x = x + center_x; // shift to distance from view center
body_pose->y = y + center_y;
body_pose->z = z + center_z;
if(get_light_type(light1)==POINT_LIGHT) // some attempt for
{ // interesting lighting
x = l_x;
y = l_y;
z = l_z;
matrix_point(n,&x,&y,&z);
p.x = x;
p.y = x;
p.z = x;
position_pointlight(light1, &p);
}
else
{
p.rx = longitude + float2angle(45);
p.ry = latitude + float2angle(45);
p.rz = 0;
rotate_spotlight(light1, &p);
}
}
/********************** KEY INTERPERTER *****************/
void view_menu(void), mouse_menu(void), stereo_info(void);
extern BOOL process_motion_keys(unsigned key);
BOOL process_display_keys(unsigned c) // processes and display setup keys
{
int i, j;
switch (c)
{
case CTRLLEFT:
i = +1;
goto set_shift;
case CTRLRIGHT:
i = -1;
set_shift:
if (current_camera->stereo->window[LEFT_EYE].orientation&XFLIP)
current_camera->stereo->window[LEFT_EYE].xoff += i;
else
current_camera->stereo->window[LEFT_EYE].xoff -= i;
if (current_camera->stereo->window[RIGHT_EYE].orientation&XFLIP)
current_camera->stereo->window[RIGHT_EYE].xoff -= i;
else
current_camera->stereo->window[RIGHT_EYE].xoff += i;
compute_camera_factors(current_camera);
display_changed++;
break;
case '+':
if (stereo_type == MONOSCOPIC)
{
SCALE z = get_camera_zoom(current_camera);
z *= 1.1;
if(z<65536L*0.5) z = 65536L*0.5;
if(z>65536L*16.0) z = 65536L*16.0;
set_camera_zoom(current_camera,z);
}
else
{
if(current_camera->stereo->phys_screen_dist>30)
current_camera->stereo->phys_screen_dist *= 1.05;
else current_camera->stereo->phys_screen_dist *= 1.25;
}
compute_camera_factors(current_camera);
display_changed++;
break;
case '-':
if (stereo_type == MONOSCOPIC)
{
SCALE z = get_camera_zoom(current_camera);
z /= 1.1;
if(z<65536L*0.5) z = 65536L*0.5;
if(z>65536L*16.0) z = 65536L*16.0;
set_camera_zoom(current_camera,z);
compute_camera_factors(current_camera);
display_changed++;
break;
}
else
{
current_camera->stereo->phys_screen_dist /= 1.05;
if(current_camera->stereo->phys_screen_dist<5)
current_camera->stereo->phys_screen_dist = 5;
}
compute_camera_factors(current_camera);
display_changed++;
break;
case '@':
if (stereo_type != MONOSCOPIC)
{
current_camera->stereo->phys_eye_spacing /= 1.05;
if(current_camera->stereo->phys_eye_spacing<5)
current_camera->stereo->phys_eye_spacing = 5;
compute_camera_factors(current_camera);
display_changed++;
}
break;
case '!':
if (stereo_type != MONOSCOPIC)
{
if(current_camera->stereo->phys_eye_spacing>30)
current_camera->stereo->phys_eye_spacing *= 1.05;
else
current_camera->stereo->phys_eye_spacing *= 1.25;
compute_camera_factors(current_camera);
display_changed++;
}
break;
default:
return FALSE;
}
return TRUE;
}
BOOL process_info_keys(unsigned c) // processes daata-display keys
{
int i, j;
switch (c)
{
case 'H':
save_screen();
poptext(helptext);
get_response(1);
restore_screen();
break;
case 'I':
{
POSE p;
get_camera_worldpose(current_camera,&p);
save_screen();
disp_status(&p);
get_response(1);
restore_screen();
break;
}
case '$':
stereo_info();
break;
case 'C':
save_screen();
disp_palette();
get_response(1);
restore_screen();
break;
default:
return FALSE;
}
return TRUE;
}
TELEPORT *fnkeyposn[10] =
{ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
TELEPORT *fnkeyhome[10];
WORD current_teleport = 0; // where to go home to
extern OBJECT *body_vehicle_object;
BOOL process_teleport_keys(unsigned c) // processes teleport and home keys
{
int i, j;
switch (c)
{
case F1:
case F2:
case F3:
case F4:
case F5:
case F6:
case F7:
case F8:
case F9:
case F10:
{
i = (c- F1) >> 8;
if(i==current_teleport) break;
// record current position for return
teleport_set_here(fnkeyposn[current_teleport], body_pose);
teleport_set_vehicle(fnkeyposn[current_teleport],
body_vehicle_object,NULL);
current_teleport = i; // set home number
if(fnkeyposn[i])
{
teleport_to(fnkeyposn[i]);
}
else
{
fnkeyposn[i] = create_teleport(); // records current state
fnkeyhome[i] = create_teleport();
}
position_changed++;
break;
}
case HOME:
if(fnkeyposn[current_teleport])
{
teleport_to(fnkeyhome[current_teleport]);
}
position_changed++;
break;
default:
return FALSE;
}
return TRUE;
}
BOOL process_system_keys(unsigned c) // processes quit, etc
{
int i, j;
switch (c)
{
case 'A':
animatemode = !animatemode;
break;
case TAB:
if(animatemode==0) animatemode = -1;
break;
case '^':
save_pcx_file();
break;
case 'Q':
case ESC:
popmsg("Really quit?");
i = get_response(1);
if (toupper(i)=='Y') running = 0;
else restore_screen();
break;
default:
return FALSE;
}
return TRUE;
}
extern int mouse_nav;
static int movemults[] = { 1,2,3,5,7,10,13,17,22,28}; // speed, angles
static int angmults[] = { 1,1,1,1,2,2,2,3,4,5}; // 0-9 scale factors
BOOL process_extmove_keys(unsigned c) // processes daata-display keys
{
int i, j;
switch (c)
{
case '*': /* level view */
body_pose->rx = body_pose->rz = 0;
display_changed++;
break;
case 'U':
body_pose->ry += 180*65536L;
position_changed++;
break;
case '0':
sstepsize = movemults[9];
astepsize = angmults[9];
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
sstepsize = movemults[c - '1'];
astepsize = angmults[c - '1'];
break;
case 'S':
if(spinmode) spinmode = 0;
else
{
OBJECT *newobj = NULL;
float dist;
save_screen();
if (can_point_2D() && manip_2D_avail)
{
restore_screen();
popmsg("Click on object to spin about");
tdelay(500);
restore_screen();
while(!newobj)
{
newobj = move_and_find_object_2D(cursor_device,NULL);
if(kbhit()) break;
}
if(!newobj) break;
get_object_bounds(newobj, ¢er_x, ¢er_y, ¢er_z);
}
center_d = magnitude32(center_x - body_pose->x,
center_y - body_pose->y,
center_z - body_pose->z );
spinmode = 1;
}
break;
case 'J':
mouse_nav = !mouse_nav; // toggle mouse joy
if(manip_2D_avail)
cursor_enable(!mouse_nav); // cursor on/off
break;
default:
return FALSE;
}
return TRUE;
}
BOOL process_menu_keys(unsigned c) // processes menu-entry keys
{
int i, j;
switch (c)
{
case 'X':
main_menu();
break;
case 'D':
disp_options();
restore_screen();
break;
case 'O':
obj_menu();
break;
case 'F':
fig_menu();
break;
case 'P':
painting();
break;
case 'M':
mouse_menu();
break;
case 'V':
view_menu();
break;
default:
return FALSE;
}
return TRUE;
}
/************ API KEY HANDLER **************/
void process_a_key(unsigned c) // processes key <c>
{
int i, j;
if(c<0x7f)
if(isalpha(c))
c = toupper(c);
if(process_motion_keys(c)) return;
if(process_display_keys(c)) return;
if(process_info_keys(c)) return;
if(process_teleport_keys(c)) return;
if(process_system_keys(c)) return;
if(process_extmove_keys(c)) return;
if(process_menu_keys(c)) return;
}
void key_process() // reads, processes keys
{
unsigned c;
if (!bioskey(1)) return;
c = getkey(); // read a key
while(bioskey(1)) getkey(); // dump others
process_a_key(c);
}
/************ API JOYSTICK HANDLER **************/
void joystick_process()
{
if(do_joy_navigate(body_pose,
spinmode, spacestep*sstepsize, astepsize*anglestep, flymode))
position_changed ++;
if (position_changed && spinmode) // SPECIAL: spin mode move xlat
spin_mode_compute();
}