[comp.sys.sgi] spaceball

emma@northstar27.dartmouth.edu (Emma Lan) (07/27/90)

  We had a 4D/80 IRIS two years ago, we did a lot things which need dials and 
buttons to rotate and translate objects on it.  So most of our programs have
been written accordingly.  Now we got another 4D/210 IRIS, and we are thinking
of transfering some of our programs to this new machine, but this new machine
has an innovative device called "spaceball", instead of the "dial and button
box".
  Could someone please send me a sample program using this new "spaceball" 
device or point it out how to convert "the dial and button box" to "spaceball
device".
  Please reply me to emma@northstar.dartmouth.edu.
  Thanks a lot in advance!

dmlaur@phoenix.Princeton.EDU (David M. Laur) (07/27/90)

In article <23385@dartvax.Dartmouth.EDU> emma@northstar27.dartmouth.edu (Emma Lan) writes:
>
>  We had a 4D/80 IRIS two years ago, we did a lot things which need dials and 
>buttons to rotate and translate objects on it.  So most of our programs have
>been written accordingly.  Now we got another 4D/210 IRIS, and we are thinking
>of transfering some of our programs to this new machine, but this new machine
>has an innovative device called "spaceball", instead of the "dial and button
>box".
>  Could someone please send me a sample program using this new "spaceball" 
>device or point it out how to convert "the dial and button box" to "spaceball
>device".
>  Please reply me to emma@northstar.dartmouth.edu.
>  Thanks a lot in advance!

try this ...

-------------------- cut here ------------------------------
/*
 *  - test spaceball to rotate and position an object
 *  - use triangle-mesh drawing routines
 *  - use RGB color scheme
 *
 * compile using:
 *
 *   cc -o sbtest sbtest.c -O -lspaceball -lgl_s -lc_s -lm -s
 *
 *
 *  David Laur, Princeton ICGL, Oct 89
 *  dmlaur@manray.princeton.edu
 *  609-258-4609
 *
 *
 * note: the Gouraud shading option on the menu isn't meaningful on some
 *       SGI systems ... the drawing scheme used 'forces' smooth shading
 *       on 4D/GT machines.
 */


#include <gl/gl.h>
#include <gl/device.h>
#include <math.h>

/* ---- function declarations / prototypes ---- */
void setup(void);
void do_events(void);
void figure(void);
void draw_cube(void);
void draw_axes(void);
void do_menu(void);
void newView(void);
void newSb (short *sbvals, Matrix sbmat);

long Zmax, menu, Wid, MouseIn=0;
char sbstatus[128];
Matrix Rmat;			/* global rotation matrix */
float sbscale = 0.0002, trns[3];
Boolean flat, dominant=FALSE;

char *sbsingle[] = {"Tx","Ty","Tz","Rx","Ry","Rz"};

Matrix Id_mat = {
		{ 1.0, 0.0, 0.0, 0.0 },
		{ 0.0, 1.0, 0.0, 0.0 },
		{ 0.0, 0.0, 1.0, 0.0 },
		{ 0.0, 0.0, 0.0, 1.0 } };


int Cv[][3] =	{	0, 0, 0,
			1, 0, 0,
			1, 1, 0,
			0, 1, 0,
			0, 0, 1,
			1, 0, 1,
			1, 1, 1,
			0, 1, 1,
		};

int Crgb[][3] =	{	30, 30, 30,
			100, 30, 30,
			30, 100, 30,
			30, 30, 100,
			100, 100, 100,
			255, 100, 100,
			100, 255, 100,
			100, 100, 255,
		};

/* -------------------------------------------------------------------- */

main (argc,argv)
	int argc;
	char **argv;
{
	if (!sbexists()) {
		puts("no spaceball on this machine!");
		exit(-1);
	}

	setup();		/* do initial window stuff */

	sbspaceball();		/* initialize the spaceball */
	sbrezero();		/* re-zero */
	sbdataperiod(0, -1);	/* only way I found to reset this */
	sbdataperiod(1000, 0);	/* seems to give reasonable performance on our GT */
	sbprompt();		/* make sure first SB events aren't delayed */
	
	do_events();		/* handle events 'forever' */

}	/* end of main routine */

/* -------------------------------------------------------------------- */

void
setup ()	/***** setup the window *****/
{
	Wid = winopen("sample");

	Zmax = getgdesc(GD_ZMAX); /* save max available z-depth */

	zbuffer(TRUE);
	doublebuffer();
	RGBmode();
	gconfig();

	qdevice(RIGHTMOUSE);	/* trap right mouse button events */
	qdevice(REDRAW);	/* trap window manager `redraw' messages */
	qdevice(INPUTCHANGE);	/* trap changes in input focus */

	qdevice(SBBUT1);	/* SpaceBall Button 1 */
	qdevice(SBBUT2);
	qdevice(SBBUT3);
	qdevice(SBBUT4);
	qdevice(SBTX);		/* SpaceBall Translate in X */
	qdevice(SBTY);
	qdevice(SBTZ);
	qdevice(SBRX);		/* SpaceBall Rotate about X */
	qdevice(SBRY);
	qdevice(SBRZ);
	qdevice(SBPERIOD);	/* SpaceBall time delta */

	qenter(REDRAW,Wid);	/* make sure we do initial redraw */

	menu = defpup("Some Choices%t|Reset Position%x10");
	addtopup(menu,"Use Flat Shading%x20|Use Gouraud Shading%x20");
	addtopup(menu,"Exit%x999");

	shademodel( (flat=TRUE) ? FLAT : GOURAUD );
	setpup(menu, ((flat) ? 2 : 3), PUP_GREY);	/* grey-out inappropriate menu entry */

	strcpy(sbstatus, "Spaceball may require Inputchange event");
}

/* -------------------------------------------------------------------- */

void
do_events ()	/***** event handler loop *****/
{
	long device;
	short value;
	long wx, wy;
	int mx, my;
	short sbvals[7];

	for (mx=0; mx<7; mx++) sbvals[mx] = 0;
	bcopy(Id_mat, Rmat, sizeof(float)*4*4);	/* initialize to no rotations */
	trns[0] = trns[1] = 0.0;  trns[2] = -500.0;

	while (1)	/* until killed from menu ... */
	{
	device = qread(&value);		/* read next event */

	switch (device)
	{
		case (RIGHTMOUSE):
			if (1 != value) break;
			do_menu();
			newView();
			break;

		case (SBPERIOD):
		case (SBTX):
		case (SBTY):
		case (SBTZ):
		case (SBRX):
		case (SBRY):
		case (SBRZ):
			sbvals[device-SBTX] = value;
			if (device == SBRZ) {	/* now have complete sb event */
				sbprompt();	/* ensure next sb is sent without delay */
				newSb( sbvals, Rmat);
				newView();
			}
			break;

		case SBBUT1:
			if (value != 1) break;
			bcopy(Id_mat, Rmat, sizeof(float)*4*4);
			trns[0] = trns[1] = 0.0;  trns[2] = -500.0;
			newView();
			break;

		case SBBUT2:
			if (value == 1) dominant = !dominant;
			break;

		case SBBUT3:
		case SBBUT4:
			if (value != 1) break;
			sbscale *= ((device == SBBUT3)? 0.5 : 2.0);
			break;

		case (REDRAW):
			reshapeviewport();		/* re-map new window position */
			getsize(&wx, &wy);		/* get window size */
			perspective(650, wx / (float)wy, 1.0, 1500.0);
			newView();
			break;

		case (INPUTCHANGE):
			if (value != Wid) break;
			if (++MouseIn == 2) {
				strcpy(sbstatus,"ok");
				newView();
			}
			break;

		} /* end switch */

	} /* end while */
	/*NOTREACHED*/
}

/* -------------------------------------------------------------------- */

void
newSb (short *sbvals, Matrix sbmat)
{
	Matrix sbtmp;
	static int oldn=0, maxn, run=0;
	register int n, v,w;
	float trv[6];
	
	sprintf(sbstatus,"%3s   T(%-5hd%-5hd%-5hd)    R(%-5hd%-5hd%-5hd)", 
		((dominant)?sbsingle[maxn]:"all"),
	sbvals[0],sbvals[1],sbvals[2],sbvals[3],sbvals[4],sbvals[5]);

	if (dominant) {
		for (n=0; n<6; n++) if (5 < abs(sbvals[n])) break;
		if (n == 6) {	/* all zeros, end of sb events */
		run = 0;
		strcpy(sbstatus,"Stop  T(0    0    0    )    R(0    0    0    )");
		return;
	}
	if (run < 2) {	/* find dominant mode */
		for (maxn=n=v=0; n<6; n++) if (v < (w = abs(sbvals[n]))) { maxn = n; v = w; }
		if (oldn == maxn) run++;
		else { run=0; oldn = maxn; }
		if (run < 2) return;
		else for (n=0; n<6; n++) trv[n] = 0.0;
	}
	trv[maxn] = (float) (sbvals[maxn]);
	}
	else for (n=run=0; n<6; n++) trv[n] = (float) (sbvals[n]);

	if ( ((!dominant) || (maxn < 3)) && (trv[0] || trv[1] || trv[2])) {
		trv[2] *= -1.0;
		for (n=0; n<3; n++) trns[n] += (25.0 * sbscale * trv[n]);
	}

	if ( ((!dominant) || (maxn > 2)) && (trv[3] || trv[4] || trv[5]) && (!getbutton(SBPICK))) {
		trv[3] *= -1.0;
		trv[4] *= -1.0;

		rotarbaxis(sbscale, trv[3], trv[4], trv[5], sbtmp);	/* convert SB to matrix */

		pushmatrix();
		loadmatrix(sbtmp);
		multmatrix(sbmat);	/* use GL to do post-multiply */
		getmatrix(sbmat);	/* ... there's probably a better way */
		popmatrix();
	}
}

/* -------------------------------------------------------------------- */

void
newView ( void )	/***** draw scene *****/
{
	czclear(0, Zmax);
	pushmatrix();			/* store perspective */

	translate( trns[0], trns[1], trns[2] );
	multmatrix(Rmat);
	draw_axes();
	figure();

	ortho2(0.0, 500.0, 0.0, 500.0);
	RGBcolor(255,255,0);
	cmov2i(10,5);
	charstr(sbstatus);
	cmov2i(10,20);
	charstr("1: Reset   2: All/One Axis   3: Slower   4: Faster");

	popmatrix();
	swapbuffers();
}

/* -------------------------------------------------------------------- */

void
figure ()	/***** geometry drawing subroutine *****/
{
	pushmatrix();	/* cube centered at origin, scaled */
	scale(100.0, 100.0, 100.0);
	draw_cube();
	popmatrix();

	pushmatrix();	/* cube translated, scaled, intersects first */
	translate(100.0, 100.0, 100.0);
	scale(50.0, 50.0, 50.0);
	rotate(900, 'y');
	rotate(900, 'z');
	translate(-.5, -.5, -.5);
	draw_cube();
	popmatrix();

	pushmatrix();	/* another cube, distorted */
	translate(-50.0, -150.0, -70.0);
	scale(30.0, 20.0, 50.0);
	rotate(300, 'x');
	draw_cube();
	popmatrix();
}

/* -------------------------------------------------------------------- */

void
draw_cube ()	/* draw a unit cube: 8 corners, 6 faces (right-handed) */
{
	bgntmesh();
	c3i(Crgb[0]);	v3i(Cv[0]);
	c3i(Crgb[3]);	v3i(Cv[3]);
	c3i(Crgb[1]);	v3i(Cv[1]);
	c3i(Crgb[2]);	v3i(Cv[2]);
	c3i(Crgb[5]);	v3i(Cv[5]);
	c3i(Crgb[6]);	v3i(Cv[6]);
	c3i(Crgb[4]);	v3i(Cv[4]);
	c3i(Crgb[7]);	v3i(Cv[7]);
	endtmesh();

	bgntmesh();
	c3i(Crgb[1]);	v3i(Cv[1]);
	c3i(Crgb[5]);	v3i(Cv[5]);
	c3i(Crgb[0]);	v3i(Cv[0]);
	c3i(Crgb[4]);	v3i(Cv[4]);
	c3i(Crgb[3]);	v3i(Cv[3]);
	c3i(Crgb[7]);	v3i(Cv[7]);
	c3i(Crgb[2]);	v3i(Cv[2]);
	c3i(Crgb[6]);	v3i(Cv[6]);
	endtmesh();
}

/* -------------------------------------------------------------------- */

void
draw_axes ()
{
	RGBcolor(255,0,0); movei(0,0,0); drawi(150,0,0); cmovi(150,0,0); charstr("x");
	RGBcolor(0,255,0); movei(0,0,0); drawi(0,150,0); cmovi(0,150,0); charstr("y");
	RGBcolor(0,0,255); movei(0,0,0); drawi(0,0,150); cmovi(0,0,150); charstr("z");
}

/* -------------------------------------------------------------------- */

void
do_menu ()	/***** pop-up menu stuff *****/
{
	int v;

	v = dopup(menu);
	if (v < 1) return;		/* nothing selected */

	switch( v )
	{
	case 10:	/* reset position */
		bcopy(Id_mat, Rmat, sizeof(float)*4*4);
		trns[0] = trns[1] = 0.0;  trns[2] = -500.0;
		newView();
		break;
	case 20:
		flat = !flat;
		shademodel( (flat) ? FLAT : GOURAUD );
		setpup(menu, ((flat) ? 2 : 3), PUP_GREY);	/* grey-out inappropriate menu entry */
		setpup(menu, ((flat) ? 3 : 2), PUP_NONE);	/* allow other menu selection */
		break;
	case 999:
		gexit();
		exit(0);
		break;
	default:
		break;
	}
}

/* -------------------------------------------------------------------- */

karron@MCIRPS2.MED.NYU.EDU (07/29/90)

emma@northstar.dartmouth.edu asks:

>  We had a 4D/80 IRIS two years ago, we did a lot things which need dials and
>buttons to rotate and translate objects on it.  So most of our programs have
>been written accordingly.  Now we got another 4D/210 IRIS, and we are thinking
>of transferring some of our programs to this new machine, but this new machine
>has an innovative device called "spaceball", instead of the "dial and button
>box".

Why not order a dial and button box in addition to the spaceball ? You can run
both gizmos at the same time, at least that is what I think.

>  Could someone please send me a sample program using this new "spaceball"
>device or point it out how to convert "the dial and button box" to "spaceball
>device".

I think that when you install the software, you must specifically ask for
the spaceball support software. That should include the man pages and
sample source code. While I don't have space ball ( yet; it is on order. ),
I installed 3.3 with the spaceball code.

This may not help you in your problem of converting from a dial and button box
to a Spaceball device, but this raises an import software development issue:

What to do when you write a wizz bang program, and you want to show it off on
other machines that may not have all the hardware you have?

I am working on a possible solution by using the NASA panel library, written
by David Tristram.  It contains a software analog of the dial and button box
as a demo program.  My particular problem is that my program depends on a
3space tracker that is polled in the main loop of the program.  It looks
great, and I want to show it all over the place, except that very very few
machines have a 3space gizmo attached.

I don't know if there is any code in the library (I have release 9.6 ) that
enables the output from the dials and buttons box to be "piped" through the
screen version of the hardware.

Has anyone out there done what I am about to describe ? (You probably did it
better)

I have some hacks in the code so that the library will allow you to run a
program that can get input from the panels, and if the appropriate hardware is
plugged in (Question:  How can I sense the presence of the d-b-box or
spaceball), the output from the hardware actuators will drive the software
panels.  A side effect of this is that I can make scripts of the hardware
input and replay point of view trajectories and object animations, including
delays and velocity information.  You can have better annotation on the
software panel of what each dial and button on the box does.  You can also
make multiple level dials when you run out of single purpose dials.  As you
diddle with each dial, the dial panel show you where the dial value "pointer"
is (the dials do not have index marks to show you where they are).  My plan is
to let the panel library handle special hardware actuators, and my application
will run without them, or with recorded data from the actuators.

The panel library is available through anonymous ftp from
Panel-Request@orville.nasa.gov.  (I think) I will submit my hacks to the
people there if they want to include it into the library distribution.  They
are not ready yet, but if you want what I have at the moment, let me know.

dan.

+-----------------------------------------------------------------------------+
| karron@nyu.edu                          Dan Karron                          |
| . . . . . . . . . . . . . .             New York University Medical Center  |
| 560 First Avenue           \ \    Pager <1> (212) 397 9330                  |
| New York, New York 10016    \**\        <2> 10896   <3> <your-number-here>  |
| (212) 340 5210               \**\__________________________________________ |
+-----------------------------------------------------------------------------+