[BACK]Return to nclops.C CVS log [TXT][DIR] Up to [Development] / performer / src / pguide / libpf / C++

File: [Development] / performer / src / pguide / libpf / C++ / nclops.C (download)

Revision 1.1, Tue Nov 21 21:39:38 2000 UTC (16 years, 11 months ago) by flynnt
Branch: MAIN
CVS Tags: HEAD

Initial check-in based on OpenGL Performer 2.4 tree.
-flynnt

//
// Copyright (c) 2000, Silicon Graphics, Inc.
// ALL RIGHTS RESERVED
//
// This source code ("Source Code") was originally derived from a
// code base owned by Silicon Graphics, Inc. ("SGI")
// 
// LICENSE: SGI grants the user ("Licensee") permission to reproduce,
// distribute, and create derivative works from this Source Code,
// provided that: (1) the user reproduces this entire notice within
// both source and binary format redistributions and any accompanying
// materials such as documentation in printed or electronic format;
// (2) the Source Code is not to be used, or ported or modified for
// use, except in conjunction with OpenGL Performer; and (3) the
// names of Silicon Graphics, Inc.  and SGI may not be used in any
// advertising or publicity relating to the Source Code without the
// prior written permission of SGI.  No further license or permission
// may be inferred or deemed or construed to exist with regard to the
// Source Code or the code base of which it forms a part. All rights
// not expressly granted are reserved.
// 
// This Source Code is provided to Licensee AS IS, without any
// warranty of any kind, either express, implied, or statutory,
// including, but not limited to, any warranty that the Source Code
// will conform to specifications, any implied warranties of
// merchantability, fitness for a particular purpose, and freedom
// from infringement, and any warranty that the documentation will
// conform to the program, or any warranty that the Source Code will
// be error free.
// 
// IN NO EVENT WILL SGI BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT
// LIMITED TO DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES,
// ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THE
// SOURCE CODE, WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT OR
// OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
// PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM,
// OR AROSE OUT OF USE OR RESULTS FROM USE OF, OR LACK OF ABILITY TO
// USE, THE SOURCE CODE.
// 
// Contact information:  Silicon Graphics, Inc., 
// 1600 Amphitheatre Pkwy, Mountain View, CA  94043, 
// or:  http://www.sgi.com

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <alloca.h>
#include <stdarg.h>

#include <sys/types.h>
#include <sys/sysmp.h>
#include <sys/sysinfo.h>

#include <X11/Xlib.h>
#include <X11/keysym.h>

#include <Performer/pr.h>
#include <Performer/pf.h>
#include <Performer/pfui.h>
#include <Performer/pfdu.h>

#include <Performer/pr/pfLinMath.h>

#include <Performer/pf/pfPipe.h>
#include <Performer/pf/pfPipeWindow.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfScene.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfLightSource.h>
#include <Performer/pf/pfFrameStats.h>

#include <Performer/pfui/pfiXformer.h>


// global command name parsed at startup
static char* gCmd;

// shared data region for communicating with draw
struct SharedData {
    int statsEnabled;
};

static SharedData* gShared;

// error message printing
static void
verrmsg(const char* fmt, va_list ap)
{
    char buf[2048];
    vsprintf(buf, fmt, ap);
    pfNotify(PFNFY_FATAL, PFNFY_USAGE, buf);
}


// error exit
static void
errexit(const char* fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    verrmsg(fmt, ap);
    va_end(ap);
    exit(EXIT_FAILURE);
}


static void
usage()
{
    errexit("%s [-sf] [-n level] [-r framerate] [-p phase] [-m mpmode]\n"
	    "   -f  use small window (512x512)\n"
	    "   -m  a-cd|a-c-d|a-cod|a-cld\n"
	    "   -n  notification level\n"
	    "   -p  float|lock|free|limit\n"
	    "   -s  show stats\n",
	    gCmd);
}


// PipeWindow config func
static void
openPipeWindow(pfPipeWindow* pw)
{
    pw->open();
}


// Draw callback
static void
drawFunc(pfChannel* chan, void*)
{
    chan->clear();
    pfDraw();
    if (gShared->statsEnabled)
	chan->drawStats();
}


void
main(int argc, char** argv)
{
#ifndef SGIX_hyperpipe
    errexit("Hyperpipe extension not available on this system.\n");
#else
    if ((gCmd = strrchr(argv[0], '/')) == NULL) gCmd = argv[0];

    int hyperpipePipes = 2;
    int fullscreen = 1;
    int c, i;
    char *cmpmode = NULL, *cphase = NULL;
    size_t slen;
    int numHyper = 1;
    int nLevel = -1;
    int nFrameRate = -1;

    // init Performer and allocate shared data
    pfInit();

    gShared = (SharedData*)pfMalloc(sizeof(SharedData));
    gShared->statsEnabled = 0;

    while ((c = getopt(argc, argv, "fm:n:p:r:s")) != -1) {
	switch (c) {
	    case 'f':
		fullscreen = 0;
		break;
	    case 'm':
		slen = strlen(optarg);
		cmpmode = (char*)alloca(slen+1);
		for (i = 0; i < slen; i++)
		    cmpmode[i] = tolower(optarg[i]);
		cmpmode[slen] = '\0';
		break;
	    case 'n':
		nLevel = atoi(optarg);
		break;
	    case 'p':
		slen = strlen(optarg);
		cphase = (char*)alloca(slen+1);
		for (i = 0; i < slen; i++)
		    cphase[i] = tolower(optarg[i]);
		cphase[slen] = '\0';
		break;
	    case 'r':
		nFrameRate = atoi(optarg);
		break;
	    case 's':
		gShared->statsEnabled = 1;
		break;
	    case '?':
		usage();
	}
    }

    // determine multiprocess mode
    int mpmode = PFMP_APP_CULL_DRAW;
    if (cmpmode) {
	if (strcmp(cmpmode, "a-cd") == 0)
	    mpmode = PFMP_APP_CULLDRAW;
	else if (strcmp(cmpmode, "ac-d") == 0)
	    mpmode = PFMP_APPCULL_DRAW;
	else if (strcmp(cmpmode, "a-c-d") == 0)
	    mpmode = PFMP_APP_CULL_DRAW;
	else if (strcmp(cmpmode, "a-cod") == 0)
	    mpmode = PFMP_APP_CULLoDRAW;
	else if (strcmp(cmpmode, "a-cld") == 0)
	    mpmode = PFMP_APP_CULL_DL_DRAW;
	else
	    usage();
    }
    pfMultiprocess(mpmode);

    // determine phase
    int phase = PFPHASE_LOCK;
    if (cphase) {
	if (strncmp(cphase, "flo", 3) == 0)
	    phase = PFPHASE_FLOAT;
	else if (strncmp(cphase, "loc", 3) == 0)
	    phase = PFPHASE_LOCK;
	else if (strncmp(cphase, "fre", 3) == 0)
	    phase = PFPHASE_FREE_RUN;
	else if (strncmp(cphase, "lim", 3) == 0)
	    phase = PFPHASE_LIMIT;
    }
    pfPhase(phase);

    // set pfPath to something reasonable
    pfFilePath("."
	       ":./moffett"
	       ":/usr/share/Performer/data"
	       ":/usr/share/Performer/data/clipdata/hunter"
	       ":/usr/share/Performer/data/clipdata/moffett"
	       ":../data"
	       ":../../data"
	       ":../../data/polyhedra"
	       ":../../../data"
	       ":/usr/demos/models"
	       ":/usr/demos/data/flt");

    if (nLevel >= 0)
	pfNotifyLevel(nLevel);

    GLXHyperpipeNetworkSGIX* net = NULL;
    int netPipes;

    Display* dsp;
    dsp = pfGetCurWSConnection();

    // Does this machine support hyperpipe
    int hasHyperpipe;
    pfQueryFeature(PFQFTR_HYPERPIPE, &hasHyperpipe);
    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "hasHyperpipe = %d\n", hasHyperpipe);
    if (hasHyperpipe) {
	net = glXQueryHyperpipeNetworkSGIX(dsp, &netPipes);
	pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "netpipes = %d\n", netPipes);

	if (netPipes == 0)
	    errexit("%s: no hyperpipes associated with display %s\n",
		    gCmd, getenv("DISPLAY"));
	
	// determine number of distinct hyperpipe groups
	numHyper = net[netPipes-1].networkId + 1;

	// setup the hyperpipes (they'll be mapped to screens below)
	int hpipe = net[0].networkId, i = 0;
	int pipeCount = 0;
	while (i < netPipes) {
	    if (net[i].networkId != hpipe || i == netPipes-1) {
		// Tell Performer to aggregate pfPipes for each
		// hyperpipe group
		pfHyperpipe(pipeCount);
		pipeCount = 1;
		hpipe = net[i].networkId;
	    } else
		pipeCount++;

	    i++;
	}
    } else
	errexit("%s: no hyperpipe feature on %s\n", gCmd, getenv("DISPLAY"));

    // Init the loaders before Config
    for (i = optind; i < argc; i++)
	pfdInitConverter(argv[i]);

    // Init the utilities
    pfuInit();

    // Config the rendering pipeline
    pfConfig();

    // initialize frame rate if supplied
    if (nFrameRate > -1)
	pfFrameRate(nFrameRate);

    float frameRate = -1, frameRateDiv = 1;

    // Map the hyperpipe group pipes to pfPipes
    for (i = 0; i < netPipes; i++)
	pfGetPipe(i)->setWSConnectionName(net[i].pipeName);

    // Create the pfPipeWindows and pfChannels for the master
    // pfPipes (lowest numbered pfPipe of the hyperpipe group) of
    // each hyperpipe group.
    pfChannel* masterChan;	// master channel
    pfPipeWindow* masterPw;	// master pipewindow

    i = 0;
    while (i < netPipes) {
	pfPipe* p = pfGetPipe(i);

	// Construct the PipeWindow
	pfPipeWindow* pw = new pfPipeWindow(p);
	pw->setName("Hyperpipe Window");
	pw->setConfigFunc(openPipeWindow);
	pw->setWinType(PFPWIN_TYPE_X);
	if (fullscreen)
	    pw->setFullScreen();
	else
	    pw->setOriginSize(0, 0, 512, 512);
	pw->setMode(PFWIN_NOBORDER, 1);
	pw->config();
	if (i == 0)
	    masterPw = pw;

	// Construct the Channel
	pfChannel* chan = new pfChannel(p);
	pw->addChan(chan);

	chan->setShare(chan->getShare() | PFCHAN_VIEWPORT |
		PFCHAN_SWAPBUFFERS | PFCHAN_SWAPBUFFERS_HW);
	chan->makeSimple(45);
	chan->setAutoAspect(PFFRUST_CALC_VERT);

	// Lay channels out vertically
	pfVec3 xyz(0, 0, 0);
	pfVec3 hpr((((numHyper-1)*.5f)-(i/hyperpipePipes))*45.f,0,0);
	chan->setViewOffsets(xyz, hpr);
	if (i > 0)
	    masterChan->attach(chan);
	else 
	    masterChan = chan;

	chan->setNearFar(.000001, 100000);
	chan->setTravFunc(PFTRAV_DRAW, drawFunc);

	i += pfGetHyperpipe(p);
    }

    // Init the input library
    pfiInit();

    // Setup the transformer
    pfiTDFXformer* xformer = new pfiTDFXformer;
    pfuMouse mouse;

    pfuEventStream events;
    memset(&events, 0, sizeof(events));

    xformer->setAutoInput(masterChan, &mouse, &events);

    // Construct the scene
    pfScene* scene = new pfScene;

    pfLightSource* sun = new pfLightSource;
    sun->setPos(0, -1, 0, 0);
    sun->setColor(PFLT_AMBIENT, 0, 0, 0);
    sun->setColor(PFLT_DIFFUSE, .8, .8, .8);
    sun->setColor(PFLT_SPECULAR, .8, .8, .8);

    pfDCS* sunDCS = new pfDCS;
    sunDCS->addChild(sun);

    scene->addChild(sunDCS);

    pfDCS* sceneDCS = new pfDCS;
    scene->addChild(sceneDCS);

    pfGroup* sceneGroup = new pfGroup;
    sceneDCS->addChild(sceneGroup);

    // load the input files
    for (i = optind; i < argc; i++) {
	pfNode* root = pfdLoadFile(argv[i]);
	if (root != NULL)
	    sceneGroup->addChild(root);
    }

    // set the scene on the master Channel
    masterChan->setScene(scene);

    // Init any cliptextures
    {
	pfList* mpct = new pfList(sizeof(pfMPClipTexture*), 1);
	pfuProcessClipCentersWithChannel((pfNode*)sceneGroup, mpct, masterChan);
	delete mpct;
	mpct = new pfList(sizeof(pfMPClipTexture*), 1);
	pfuProcessClipCenters((pfNode*)scene, mpct);
	pfuAddMPClipTexturesToPipes(mpct, pfGetPipe(0), NULL);
	delete mpct;
    }

    // Position the eye point
    pfSphere bsphere;
    scene->getBound(&bsphere);

    {
	pfList* mpct = new pfList(sizeof(pfMPClipTexture*), 1);
	pfuProcessClipCentersWithChannel((pfNode*)sceneGroup, mpct, masterChan);
	delete mpct;
	mpct = new pfList(sizeof(pfMPClipTexture*), 1);
	pfuProcessClipCenters((pfNode*)scene, mpct);
	pfuAddMPClipTexturesToPipes(mpct, pfGetPipe(0), NULL);
	delete mpct;
    }

    pfCoord initPos;
    PFCOPY_VEC3(initPos.xyz, bsphere.center);
    initPos.xyz[1] -= PF_MIN2(2.5f*bsphere.radius, 80000.0f);
    initPos.hpr[0] = initPos.hpr[1] = initPos.hpr[2] = 0;

    // Finish transformer setup
    xformer->setNode(sceneGroup);
    xformer->setAutoPosition(NULL, sceneDCS);
    xformer->setResetCoord(&initPos);
    xformer->selectModel(PFITDF_TRACKBALL);
    xformer->stop();
    xformer->setCoord(&initPos);

    pfMatrix mat;
    xformer->getMat(mat);
    masterChan->setViewMat(mat);

    // Place the Sun
    sunDCS->setMat(mat);

    pfuInitInput(masterPw, PFUINPUT_X);

    // Setup statistics
    pfFrameStats* fstats = masterChan->getFStats();
    fstats->setAttr(PFFSTATS_UPDATE_SECS, 2);
    fstats->setClass(PFFSTATS_ENPFTIMES, PFSTATS_ON);
    fstats->setClass(PFFSTATS_ENRTMON, PFSTATS_ON);
    fstats->setClassMode(PFFSTATS_CLASSES, PFFSTATS_PFTIMES_MASK, PFSTATS_ON);

    // Kick off the first frame
    pfFrame();

    pfNotify(PFNFY_DEBUG, PFNFY_INTERNAL, "field rate = %d, frame rate = %f "
	    "video rate = %f\n", pfGetFieldRate(), pfGetFrameRate(),
	    pfGetVideoRate());

    int exitFlag = 0;
    events.numDevs = 0;
    while (!exitFlag) {
	pfSync();


	pfuGetEvents(&events);
	pfuGetMouse(&mouse);
	pfiUpdateXformer(xformer);

	for (i = 0; i < events.numDevs; i++) {
	    int dev = events.devQ[i];

	    if (events.devCount[dev] > 0) {
		switch (dev) {
		    case PFUDEV_WINQUIT:
			exitFlag = 1;
			break;
		    case PFUDEV_KEYBD:
			for (int j = 0; j < events.numKeys; j++) {
			    int key = events.keyQ[j];
			    if (events.keyCount[key]) {
				switch (key) {
				    case 27:
					exitFlag = 1;
					break;
				    case 'r':
					xformer->stop();
					xformer->setCoord(&initPos);
					break;
				    case 's':
					gShared->statsEnabled ^= 1;
					break;
				    case 'p':
					pfPhase(phase = (phase + 1) % 4);
					break;
				    case 'f':
					if (frameRateDiv < 10)
					    frameRateDiv += 1;
					else
					    frameRateDiv = 1;
					if (frameRate < 0)
					    frameRate = pfGetFrameRate();
					pfNotify(PFNFY_DEBUG, PFNFY_INTERNAL,
						"video rate %f, old frame "
						"rate %f, new frame rate %f\n",
						pfGetVideoRate(), frameRate,
						frameRate/frameRateDiv);
					pfFrameRate(frameRate/frameRateDiv);
					break;
				    case 'F':
					if (frameRateDiv > 1)
					    frameRateDiv -= 1;
					else
					    frameRateDiv = 10;
					if (frameRate < 0)
					    frameRate = pfGetFrameRate();
					pfNotify(PFNFY_DEBUG, PFNFY_INTERNAL,
						"video rate %f, old frame "
						"rate %f, new frame rate %f\n",
						pfGetVideoRate(), frameRate,
						frameRate/frameRateDiv);
					pfFrameRate(frameRate/frameRateDiv);
					break;
				    case 'i':
					{
					    int fields, vrate;
					    vrate = pfGetVideoRate();
					    fields = pfGetFieldRate();
					    fields++;
					    if (fields > vrate)
						fields = vrate;
					    pfFieldRate(fields);
					    frameRate = pfGetFrameRate();
					    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "field rate %d frame rate %f\n",
						    fields, frameRate);
					}
					break;
				    case 'I':
					{
					    int fields;
					    fields = pfGetFieldRate();
					    fields--;
					    if (fields <= 0)
						fields = 1;
					    pfFieldRate(fields);
					    frameRate = pfGetFrameRate();
					    pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "field rate %d frame rate %f\n",
						    fields, frameRate);
					}
					break;
				}
			    }
			}
		}
	    }
	}

	events.numDevs = 0;

	pfFrame();
    }

    pfuExitInput();
    pfuExitUtil();
    pfExit();

    exit(EXIT_SUCCESS);
#endif
}