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

File: [Development] / performer / src / pguide / libpf / C / page.c (download)

Revision 1.1, Tue Nov 21 21:39:37 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 1995, 1996 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
 *
 * page.c: simple database paging example with region of interest
 *
 * $Revision: 1.1 $ $Date: 2000/11/21 21:39:37 $ 
 *
 */

#include <math.h>
#include <stdlib.h>
#include <Performer/pf.h>
#include <Performer/pfdu.h>

/* size of the region, in tiles, that we page in each time */
#define REGW 2
#define REGH 2
#define NUMREQ (REGW*REGH)

#define DONE 0
#define REQUEST 1

#define APPOWN 0
#define DBPOWN 1

typedef struct {
    int	state;
    int filenum;
    pfNode *node;
} Request;
Request *llist;	/* list of load requests */
Request *dlist; /* list of delete requests */

typedef struct {
    pfGroup *group;
    pfDCS *dcs;
} Tile;
Tile *tlist;

typedef struct {
    int	fcnt;
    char **fnames;
    pfScene *scene;
    pfGroup *group;
    int done;
    int gridw, gridh;
} SharedData;
SharedData *shared;

/* ARGSUSED */
void
dbfunc(void *data)
{
    pfNode *node=0;
    static pfBuffer *buf=0;
    static int i;

    if (!buf)
    {
	buf = pfNewBuffer();
	pfSelectBuffer(buf);

	/* Open a window and context so loaders won't need to create */
	/* their own contexts each time. */
	pfOpenNewNoPortWin("Query", -1);
    }

    /*
     * NOTE: instead of using a real semaphore, we just use an integer
     * (shared->done) to keep track of ownership, to keep this example
     * simple.  The integer works because writes and reads are atomic
     * and there is no race here.  But a real application should use
     * a semaphore.
     */
    if (shared->done == DBPOWN) {
	for (i=0; i < NUMREQ; i++) {
	    if (llist[i].state == REQUEST) {
		node = pfdLoadFile(shared->fnames[llist[i].filenum]);
		if (!node) {
		    pfNotify(PFNFY_NOTICE, PFNFY_PRINT,
			     "cannot load file %s", shared->fnames[i]);
		    exit(1);
		}
		llist[i].node = node;
		llist[i].state = DONE;
	    } else {
		printf("dbfunc: llist %d is %d should be request\n",
		       i, llist[i].state);
	    } 
	}
	pfMergeBuffer();
	shared->done = APPOWN;
    }
    pfDBase();
}

float tsize = 40;
int regx, regy;

int
main (int argc, char *argv[])
{
    void	*arena;
    pfPipe      *pipe;
    pfPipeWindow *pwin;
    pfChannel   *chan;
    pfGeoState  *gstate;
    pfSphere	bsphere;
    pfGeoSet	*gset;
    pfGeode	*geode;
    pfMaterial	*material;
    float       t = 0.0;
    float	*verts, *norms;
    int		*plens;
    int		i, j, n, w, h;
    int		fnum, firstarg = 1;
    int		doscale = 0;
    int         numFilesFound = 0;

    if (argc < 2)
    {
	printf("usage: %s [-s][-t tilesize] file ... \n", argv[0]);
	exit(1);
    }
    for (i=1; i < argc; i++) {
	if (argv[i][0] == '-') {
	    switch (argv[i][1]) {
	      case 's':
		doscale = 1;
		firstarg += 1;
		break;
	      case 't':
		tsize = atoi(argv[i+1]);
		printf("using tile size %f\n", tsize);
		firstarg += 2;
		break;
	    }
	}
    }
    
    /* Initialize Performer */
    pfInit();	
    
    /* Get shared memory arena */
    arena = pfGetSharedArena();
    shared = (SharedData *) pfCalloc(1, sizeof(SharedData), arena);
    llist = (Request *) pfCalloc(NUMREQ, sizeof(Request), arena);
    dlist = (Request *) pfCalloc(NUMREQ, sizeof(Request), arena);

    /* Use a square, i.e. 3x3, 4x4, etc. tile layout */
    fnum = argc - firstarg;
    w = ceil(sqrt(fnum));
    if (w < REGW) w = REGW;

    /* If there are not enough models to fill the entire square, reuse some. */
    shared->gridw = shared->gridh = h = w;
    shared->fcnt = w * h;
    shared->fnames = (char **) pfCalloc(shared->fcnt,sizeof(char*), arena);

    pfFilePath(".:/usr/share/Performer/data:../../../../data:../pftexture");
    for (i=0; i < shared->fcnt; i++) {
        char path[PF_MAXSTRING];

	shared->fnames[i] = argv[(i % fnum) + firstarg];
        if (pfFindFile(shared->fnames[i], path, R_OK))
	    pfdInitConverter(shared->fnames[i]), numFilesFound++;
    }
    
    /* Exit if no files were found */
    if (!numFilesFound) 
      pfNotify(PFNFY_FATAL, PFNFY_PRINT, "Unable to find any of the "
	"files specified on command line. Exiting.");

    tlist = (Tile *) pfCalloc(shared->fcnt, sizeof(Tile), arena);

    pfMultiprocess(PFMP_APPCULLDRAW|PFMP_FORK_DBASE);			
    pfConfig();			
    pfDBaseFunc(dbfunc);

    shared->scene = pfNewScene();
    shared->group = pfNewGroup();
    pfAddChild(shared->scene, shared->group);

    for (j=0; j < h; j++) {
	for (i=0; i < w; i++) {
	    n = j * w + i;
	    tlist[n].dcs = pfNewDCS();
	    pfAddChild(shared->group, tlist[n].dcs);
	    tlist[n].group = pfNewGroup();
	    pfAddChild(tlist[n].dcs, tlist[n].group);

	    /* translate each tile so that scene is centered at 0,0 */
	    pfDCSTrans(tlist[n].dcs, (i - (w-1.0)/2) * tsize,
		       (j - (h-1.0)/2) * tsize, 0);
	}
    }

    /* Create a scene pfGeoState with lighting enabled */
    gstate = pfNewGState(arena);
    pfGStateMode(gstate, PFSTATE_ENLIGHTING, PF_ON);
    pfSceneGState(shared->scene, gstate);
    pfAddChild(shared->scene, pfNewLSource());

    /* Create and configure a pfChannel. */
    pipe = pfGetPipe(0);
    pwin = pfNewPWin(pipe);
    pfPWinOriginSize(pwin, 0, 0, 400, 400);
    pfOpenPWin(pwin);
    chan = pfNewChan(pipe);
    pfChanScene(chan, shared->scene);
    pfChanFOV(chan, 60.0f, 0.0f);

    /* Make a floor for the scene. */
    verts = (float *) pfMalloc(4 * 3 * sizeof(float), arena);
    norms = (float *) pfMalloc(3 * sizeof(float), arena);
    plens = (int *) pfMalloc(sizeof(int), arena);
    for (j=0; j < 2; j++) {
	for (i=0; i < 2; i++) {
	    verts[(j*2+i)*3 + 0] = (i-0.5)*w*tsize;
	    verts[(j*2+i)*3 + 1] = (j-0.5)*h*tsize; 
	    verts[(j*2+i)*3 + 2] = 0;
	}
    }
    norms[0] = norms[1] = 0; norms[2] = 1;
    plens[0] = 4;
    gset = pfNewGSet(arena);
    pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, NULL);
    pfGSetAttr(gset, PFGS_NORMAL3, PFGS_OVERALL, norms, NULL);
    pfGSetPrimType(gset, PFGS_TRISTRIPS);
    pfGSetPrimLengths(gset, plens);
    pfGSetNumPrims(gset, 1);

    /* Set up lighting for the floor */
    gstate = pfNewGState(arena);
    material = pfNewMtl(arena);
    pfMtlColor(material, PFMTL_DIFFUSE, 0.4, 0.4, 0.4);
    pfGStateAttr(gstate, PFSTATE_FRONTMTL, material);
    pfGStateMode(gstate, PFSTATE_ENLIGHTING, PF_ON);
    pfGStateMode(gstate, PFSTATE_ENTEXTURE, PF_OFF);
    pfGSetGState(gset, gstate);
    geode = pfNewGeode();
    pfAddGSet(geode, gset);
    pfAddChild(shared->group, geode);

    while (t < 600)
    {
	pfCoord	view;
	pfNode *new;
	static int firsttime=1;

	pfSync();		
	t = pfGetTime();

	/* determine extent of scene's geometry */
	pfChanNearFar(chan, 1, 3*h*tsize);
	pfSetVec3(view.hpr, 0, -30, 0);
	pfSetVec3(view.xyz, 0, -h*tsize, h*tsize/2);
	pfChanView(chan, view.xyz, view.hpr);

	pfFrame();
	if (firsttime || shared->done==APPOWN) {
	    for (j=0; j < REGH; j++) {
		for (i=0; i < REGW; i++) {
		    n = j*REGW + i;
		    if (llist[n].state != DONE) continue;

		    new = llist[n].node;
		    if (new) {
			pfAddChild(tlist[llist[n].filenum].group, new);
			if (doscale) {
			    /* very slow, but at least it lets you see */
			    pfGetNodeBSphere(new, &bsphere);
			    pfDCSScale(tlist[llist[n].filenum].dcs,
				       tsize*0.5/bsphere.radius);
			}
		    }
		    if (dlist[n].node) {
			pfRemoveChild(tlist[dlist[n].filenum].group,
				      dlist[n].node);
			pfAsyncDelete(dlist[n].node);
		    }
		    dlist[n].node = llist[n].node;
		    dlist[n].filenum = llist[n].filenum;
		    llist[n].filenum = (regy+j)*w + (regx+i);
		    llist[n].state = REQUEST;
		}
	    }
	    shared->done = DBPOWN;
	    
	    /* move region right, and maybe up */
	    regx++;
	    if (regx >= w-1) {
		regx = 0;
		regy++;
		if (regy >= h-1) {
		    regy = 0;
		}
	    }
	    firsttime = 0;
	}
	pfDrawChanStats(chan);
    }
    pfExit();

    return 0;
}