ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/bin/stereo/stereo.c

This is stereo.c in view mode; [Download] [Up]

#include <stdio.h>
#include <forms.h>
#include <gl/gl.h>
#include <gl/device.h>
#include <gl/get.h>

#include <ooglutil.h>
#include <streampool.h>
#include <camera.h>
#include <window.h>
#include <lisp.h>

#include <sys/signal.h>

#include "sterui.h"

extern HandleOps CamOps, WindowOps;
static void monitor(int mode);

#define	CURRENT		0
#define	ST_MONO		1
#define	ST_CROSSEYED	2
#define	ST_HARDWARE	3
#define	ST_COLORED	4

#define	FOR_SOMETHING	0
#define	FOR_FOCUS	1
#define	FOR_REDRAW	2


Camera *cam;
WnWindow *win;
int camwinseq;
int expectredraw;
Pool *io;
Lake *lake;
long mainwin = -1, helpwin = -1, morewin = -1;	/* GL window id's */

			/* Values cached from current camera & window */
int	isstereo = 0;
float	pixelaspect = 1;	/* pixel aspect */
float	camaspect = 1.3;	/* Camera aspect ratio, xsize/ysize */
float	halffield = .4;		/* half linear field (= tan(fov/2)) */
float	halfyfield = .4;	/* half Y-axis linear field */
float	focallen = 3;		/* focal length */
char	*camname = "focus";	/* Use this camera */
int	smode = ST_MONO;	/* Last known mode */
WnPosition curpos;
int	xsize, ysize;

    /* Stereo convergence angle to an object in the nominal plane of view */
float	halfconv = .1;		/* tan(current convergence angle/2) */
float	halfmaxconv = .22;	/* tan(max allowable convergence/2) */
int	swapeyes = 1;

    /* Hardware parameters */
float	pixperinch;
int	xscreen, yscreen;
float	screenwidth;

    /* Warmware parameter? */
float	ocularsep = 1.15;	/* 2*ocularsep inches between human eyes */

current_mode()
{
    if(cam == NULL || win == NULL) {
	fprintf(stderr, "Hey? -- stereo sleeping...\n");
	unqdevice(WINSHUT);
	unqdevice(WINQUIT);
	pause();
	return ST_MONO;
    }
    CamGet(cam, CAM_STEREO, &isstereo);
    CamGet(cam, CAM_HALFYFIELD, &halfyfield);
    CamGet(cam, CAM_HALFFIELD, &halffield);
    CamGet(cam, CAM_FOCUS, &focallen);
    CamGet(cam, CAM_ASPECT, &camaspect);
    WnGet(win, WN_PIXELASPECT, &pixelaspect);
    WnGet(win, WN_CURPOS, &curpos);
    xsize = curpos.xmax - curpos.xmin + 1;
    ysize = curpos.ymax - curpos.ymin + 1;
    return smode;
}

void
set_mode(int mode, int why)
{
    char *layout = "no";
    int stereo = 1;
    int gap = 0;
    int dx, hvpwidth;
    float halfxfield, newxfield, newyfield, newfocallen, newaspect, focalscale;
    int got;
    char winstuff[80];
    char camstuff[80];
    char advice[120];
    static int oldxsize = -1, oldysize;

    request_camwin();
    got = camwinseq;
    do {
	LFree( LEvalSexpr(lake) );
    } while(got == camwinseq);	/* Keep reading until we see a camera/window. */
    got = current_mode();
    if(mode == 0)
	mode = got;

    if(why == FOR_REDRAW && oldxsize == xsize && oldysize == ysize) {
	expectredraw = 0;
	return;
    }

#ifdef notdef
fprintf(stderr, "# halfyfield %.3f  halffield %.3f fov %.3f\r\n",
	halfyfield, halffield, 2*DEGREES(atan(halffield)));
#endif

    winstuff[0] = '\0';
    camstuff[0] = '\0';
    hvpwidth = xsize/2;
    newyfield = halfyfield;
    focalscale = 1;

    printf("(progn\n");

    switch(mode) {
    case ST_MONO:
	monitor(HZ60);
	pixelaspect = 1;
	layout = "no";
	stereo = 0;
	camaspect = (double)xsize / ysize;
	newxfield = camaspect>1 ? camaspect*halffield : halffield;
	break;

    case ST_CROSSEYED:
	monitor(HZ60);
	hvpwidth = xsize/4;
	dx = xsize/2;
	pixelaspect = 1;
	layout = "horizontal";
	camaspect = .5*xsize / ysize;

	/* Field-of-view is related to convergence angle in crosseyed view:
	 *  tan(xfov/2) = tan(conv/2) / (1 + ocularsep/(viewportwidth/2)).
	 * Push the camera back so as to frame the same object, assuming its
	 * "focus" distance correctly reflects the object of interest.
	 */

	halfxfield = camaspect>1 ? halffield*camaspect : halffield;
	newxfield = halfconv / (1 + ocularsep*pixperinch / hvpwidth);
	focalscale = halfxfield / newxfield;
	break;

    case ST_HARDWARE:
	monitor(STR_RECT);
	gap = 40;
	dx = 0;
	pixelaspect = .5;
	layout = "vertical";
	sprintf(winstuff, "position %d %d %d %d\n",
		curpos.xmin, curpos.xmax, 0, yscreen-1);

	camaspect = (double)xsize / ((yscreen - gap) / 2);
	halfxfield = camaspect>1 ? halffield*camaspect : halffield;
	newxfield = halfconv / (pixelaspect * ocularsep*pixperinch / hvpwidth);
	focalscale = halfxfield / newxfield;
	break;

    case ST_COLORED:
	monitor(HZ60);
	gap = 0;
	dx = 0;
	pixelaspect = 1;
	layout = "colored";
	camaspect = (double)xsize / ysize;
	halfxfield = halfyfield*camaspect;
	newxfield = halfconv / (ocularsep*pixperinch / hvpwidth);
	focalscale = halfxfield / newxfield;
	break;

    default:
	fprintf(stderr, "set_mode(%d)?\n", mode);
    }

    halfyfield = newxfield/camaspect;
    halffield = newxfield < halfyfield ? newxfield : halfyfield;
    newfocallen = focallen * focalscale;
#ifdef notdef
fprintf(stderr, "# NEW halfxfield %.3f halfyfield %.3f  aspect %.3f focus %.2f  fov %.3f  hconv %.1f\r\n",
	    halfxfield, halfyfield, camaspect, newfocallen,
	    2*DEGREES(atan(halffield)), 2*DEGREES(atan(halfconv)));
#endif

    if(fabs(focalscale - 1) > .02 && why == FOR_SOMETHING && !fl_get_button(FixedCamButton)) {
	float near, far;
	CamGet(cam, CAM_NEAR, &near);
	CamGet(cam, CAM_FAR, &far);
	printf("(transform %s self self translate 0 0 %g)\n",
	    camname, focallen - newfocallen);
	sprintf(camstuff, "focus %g near %g far %g\n",
		newfocallen, near*focalscale, far*focalscale);
	focallen = newfocallen;
    }

    printf("(stereowin %s %s %d)\n", camname, layout, gap);
    printf("(merge window %s { pixelaspect %g %s })\n",
	camname, pixelaspect, winstuff);
    printf("(merge camera %s {\n\
	%s perspective 1 frameaspect %g halfyfield %g\n\
	stereyes\n\
	transform { 1 0 0 0  0 1 0 0  %g 0 1 0  %g 0 0 1 }\n\
	transform { 1 0 0 0  0 1 0 0  %g 0 1 0  %g 0 0 1 }\n\
}))",
	camname, camstuff, camaspect, halfyfield,
	-swapeyes*halfconv, -swapeyes*halfconv*focallen,
	swapeyes*halfconv, swapeyes*halfconv*focallen);
    fflush(stdout);

    /* Advise viewing from distance such that the field-of-view is correct. */
    halfxfield = halffield * (camaspect>1 ? camaspect : 1);
    sprintf(advice, "%.1f degree field of view\nBest view ~%.0f\" from screen",
	2*DEGREES(atan(halffield)), hvpwidth/pixperinch / halfxfield);

    fl_set_object_label(BestViewText, advice);

    isstereo = stereo;
    expectredraw = 1;
    oldxsize = xsize;
    oldysize = ysize;

    if(stereo)
	fl_show_object(SwapButton);
    else
	fl_hide_object(SwapButton);
    if(fl_get_browser(StereoBrowser) != mode)
	fl_select_browser_line(StereoBrowser, mode);
}

void
ConvProc(FL_OBJECT *obj, long arg)
{
    float v = fl_get_slider_value(obj);

    halfconv = tan(RADIANS(v/2));
    if(isstereo)
	set_mode(CURRENT, FOR_SOMETHING);
}

void
StereoProc(FL_OBJECT *obj, long arg)
{
    set_mode(fl_get_browser(obj), FOR_SOMETHING);
}

void
SwapProc(FL_OBJECT *obj, long arg)
{
    swapeyes = fl_get_button(obj) ? -1 : 1;
    set_mode(CURRENT, FOR_SOMETHING);
}


LDEFINE(stereowin, LVOID, "")
{
    char *cam = NULL, *mode = NULL;
    LDECLARE(("stereowin", LBEGIN,
	LSTRING, &cam,
	LSTRING, &mode,
	LREST, NULL,
	LEND));
    if(mode == NULL)
	return Lnil;
    switch(mode[0]) {
    case 'n': smode = ST_MONO; break;		/* "no" */
    case 'h': smode = ST_CROSSEYED; break;	/* "horizontal" */
    case 'v': smode = ST_HARDWARE; break;	/* "vertical" */
    case 'c': smode = ST_COLORED; break;	/* "colored" */
    default:
	fprintf(stderr,
	  "stereo: Can't understand  '(stereowin %s %s)' from geomview.\n",
		cam, mode);
    }
    return Lt;
}


LDEFINE(redraw, LVOID, "")
{
    LDECLARE(("redraw", LBEGIN,
	LREST, NULL,
	LEND));

    if(expectredraw-- <= 0) {
	expectredraw = 1;		/* Prevent reentrant calls */
	set_mode(CURRENT, FOR_REDRAW);
    }
    return Lt;
}


static char simplepick[] = "(pick %s nil * nil nil nil nil nil nil nil)";

LDEFINE(pick, LVOID, "")
{
    float z;
    HPoint3 pt;
    char *me, *it;
    int npt = 4;
    static int picking = 0;

    LDECLARE(("pick", LBEGIN,
	LSTRING, &me,
	LSTRING, &it,
	LHOLD, LARRAY, LFLOAT, &pt, &npt,
	LREST, NULL,
	LEND));

    fl_set_object_boxtype(FocalButton, FL_UP_BOX);
    if(picking) return Lnil;
    picking = 1;

    printf("(progn (uninterest\n");
    printf(simplepick, camname);
    printf(")");
    if(npt == 4) {
	printf("(merge camera %s { focus %g }))\n", camname, -pt.z / pt.w);
	fflush(stdout);
	set_mode(CURRENT, FOR_FOCUS);
    } else {
	printf(")\n");	/* Close the progn */
	fflush(stdout);
    }
    picking = 0;
    return Lt;
}

static char simplemerge[] = "(merge camera %s *)";

LDEFINE(merge, LVOID,
       "(merge camera CAM-ID  { CAMERA ... } )")
{
  char *opsname = NULL;
  int c, id;
  LObject *kw = NULL, *idarg = NULL;
  float newfocallen = focallen;

  if (lake == NULL)
    return Lt;

  /* All the work of this function is done at parse time. */

  /* parse first arg [ops]: */
  if (! LakeMore(lake,c) || (kw = LSexpr(lake)) == Lnil ||
      !LFROMOBJ(LSTRING)(kw, &opsname) || strcmp(opsname, "camera") != 0) {
    OOGLSyntax(stdin, "merge: expected \"camera\", got \"%s\"", opsname);
    goto parsefail;
  }

  /* parse 2nd arg; it's a string (id) */
  if (! LakeMore(lake,c) || (idarg = LEvalSexpr(lake)) == Lnil) {
    OOGLSyntax(stdin,"\"merge\": expected CAM-ID");
    goto parsefail;
  }


  cam = NULL;
  if(CamOps.strmin(POOL(lake), NULL, &cam) == 0) {
    OOGLSyntax(stdin, "\"merge\": error reading camera");
    goto parsefail;
  }

  CamGet(cam, CAM_FOCUS, &focallen);
  if(fabs(focallen - newfocallen) > .01) {
    focallen = newfocallen;
    if(!expectredraw)
	set_mode(CURRENT, FOR_FOCUS);
  }
 parsefail:
  LFree(kw);
  LFree(idarg);
  return Lt;
}

request_camwin()
{
    printf("\
(progn (echo (stereowin %s)) (echo \"(camwin \") (write camera - %s) (write window - %s) (echo \"\\n)\\n\") )\n",
	camname, camname, camname);
    fflush(stdout);
}

LDEFINE(camwin, LVOID, "")
{
    if(lake == NULL) return Lt;
    camwinseq++;
    if(CamStreamIn(POOL(lake), NULL, &cam) <= 0) {
	OOGLSyntax(stdin, "stereo: couldn't read camera");
	return Lnil;
    }
    if(WnStreamIn(POOL(lake), NULL, &win) <= 0) {
	OOGLSyntax(stdin, "stereo: couldn't read window");
	return Lnil;
    }
    return Lt;
}

void
FocalProc(FL_OBJECT *obj, long arg)
{
    printf("(interest ");
    printf(simplepick, camname);
    printf(")\n");
    fflush(stdout);
    fl_set_object_label(BestViewText, "Click right mouse on point");
    fl_set_object_boxtype(obj, FL_DOWN_BOX);
}

static char *HelpText[] = {
#include "help.c"
};

void HelpProc(FL_OBJECT *obj, long arg)
{ helpwin = fl_show_form(Help, FL_PLACE_SIZE, TRUE, "Stereo Help"); }

int
validinput(FL_OBJECT *obj, float *val)
{
  char *s = fl_get_input(obj);
  char *s0 = s;
  float v;
  v = strtod(s, &s);
  if(s == s0) return 0;
  if(*val == v) return -1;
  *val = v;
  return 1;
}

void updateMore()
{
  char s[80];
  fl_freeze_form(More);
  sprintf(s, "%.2f", screenwidth);
  fl_set_input(ScreenWidthInput, s);
  sprintf(s, "%.2f", 2*ocularsep);
  fl_set_input(OcularInput, s);
  fl_unfreeze_form(More);
}

void
OcularSepProc(FL_OBJECT *obj, long arg)
{
  if(validinput(obj, &ocularsep) > 0) {
    ocularsep *= .5;
    set_mode(CURRENT, FOR_SOMETHING);
  }
  updateMore();
}

void
ScreenWidthProc(FL_OBJECT *obj, long arg)
{
  if(validinput(obj, &screenwidth) > 0 && screenwidth > 0) {
    pixperinch = xscreen / screenwidth;
    set_mode(CURRENT, FOR_SOMETHING);
  }
  updateMore();
}

void
CamNameProc(FL_OBJECT *obj, long arg)
{
  char *is = fl_get_input(CamNameInput);
  if(strcmp(camname, is) && is[0] != '\0') {
    camname = is;
    request_camwin();
  }
}

void MoreProc(FL_OBJECT *obj, long arg)
{
  updateMore();
  morewin = fl_show_form(More, FL_PLACE_SIZE, TRUE, "Stereo Parameters");
}

static void
monitor(int mode)
{
    if((mode == STR_RECT) != (getmonitor() == STR_RECT) && !getenv("NOMON"))
	setmonitor(mode);
}

void
die(int sig)
{
    monitor(HZ60);
    exit(0);
}

void
QuitProc(FL_OBJECT *obj, long arg)
{
    die(0);
}

void
DoneProc(FL_OBJECT *obj, long arg)
{
   fl_hide_form(obj->form);
}

main(int argc, char *argv[])
{
    int i, c;

    io = PoolStreamOpen("stdio", stdin, 0, &CamOps);
    PoolStreamOpen("stdio", stdout, 1, &CamOps);
    lake = LakeDefine(stdin, stdout, io);

    LInit();
    LDefun("pick", Lpick, Hpick);
    LDefun("redraw", Lredraw, Hredraw);
    LDefun("merge", Lmerge, Hmerge);
    LDefun("camwin", Lcamwin, Hcamwin);
    LDefun("stereowin", Lstereowin, Hstereowin);

    foreground();
    fl_init();
    create_the_forms();


    signal(SIGHUP, die);
    signal(SIGINT, die);

	/* This order must match that of the ST_* define's */
    fl_add_browser_line(StereoBrowser, "Monoscopic");
    fl_add_browser_line(StereoBrowser, "Crosseyed");
    fl_add_browser_line(StereoBrowser, "Hardware");
    fl_add_browser_line(StereoBrowser, "Red/Cyan");

    fl_set_slider_bounds(ConvSlider, 1.5, DEGREES(atan(halfmaxconv)));
    fl_set_slider_value(ConvSlider, 2*DEGREES(atan(halfconv)));
    mainwin = fl_show_form(stereo, FL_PLACE_SIZE, TRUE, "Stereo View");
    fl_qdevice(WINSHUT);
    fl_qdevice(WINQUIT);

    fl_set_input(CamNameInput, camname);

    for(i = 0; i < COUNT(HelpText); i++)
	fl_add_browser_line(HelpBrowser, HelpText[i]);

	/* Screen pixel density */
    xscreen = getgdesc(GD_XPMAX);
    yscreen = getgdesc(GD_YPMAX);
    screenwidth = getgdesc(GD_XMMAX) * .03937;
    pixperinch = xscreen / screenwidth;

    printf("(interest (redraw))\n");
    printf("(interest (merge camera))\n");
    request_camwin();
    for(i = 1; i < argc; i++) {
	if(!strcmp(argv[i], "-fixed")) {
	    fl_set_button(FixedCamButton, 1);
	} else if(!strcmp(argv[i], "-unfixed")) {
	    fl_set_button(FixedCamButton, 0);
	} else if(!strncmp(argv[i], "-cam", 4)) {	/* -cam or -camera */
	    fl_set_input(CamNameInput, argv[++i]);
	    CamNameProc(CamNameInput, 0);
	} else if(!strcmp(argv[i], "-mode")) {
	    /* ... */
	}
    }

    for(;;) {
	if((c = async_fnextc(stdin, 0)) == NODATA) {
	    static struct timeval tenth = { 0, 100000 }; /* 0.1 sec */
	    select(0, NULL, NULL, NULL, &tenth);
	} else {
	    /* Got a Lisp expression */
	    c = camwinseq;
	    LFree(LEvalSexpr(lake));
	    /* If it was a camera/window pair, ... */
	    if(c != camwinseq)
		set_mode(current_mode(), FOR_REDRAW);
	}
	fl_check_forms();
	if(fl_qtest()) {
	    short v;

	    switch( fl_qread(&v) ) {
	    case WINQUIT:
		die(0);

	    case WINSHUT:
		if(v == mainwin) die(0);
		else if(v == helpwin) fl_hide_form(Help), helpwin = -1;
		else if(v == morewin) fl_hide_form(More), morewin = -1;
	    }
	}
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.