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

File: [Development] / performer / src / pguide / libpf / C / torusLOD.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, 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
 *
 * torusLOD.c
 *	OpenGL Performer example for creating GeoSets and LODs
 *	    usage:
 *		    lod		-runs sample program
 *		    F1		-toggle stats
 *		    w		-toggle wireframe
 *		    LEFTMOUSE:	- zoom in
 *		    RIGHTMOUSE	- zoom out
 * $Revision: 1.1 $ 
 * $Date: 2000/11/21 21:39:37 $
 */
#include <stdlib.h>
#include <X11/keysym.h>
#include <Performer/pf.h>

static void drawChannel(pfChannel *chan, void *data);
static void processInput(void);

static int winOriginX = 20, winOriginY = 20;
static int winSizeX = 500, winSizeY = 500;
static int done = FALSE;
static pfCoord view;
static void openPipeWin(pfPipeWindow *);
static void initView(pfChannel *);
static void processInput(void);
static pfLOD *generateTorusLODs(void *);

static float *offset = NULL;

/*
 *	main() -- program entry point.
 */
int
main (int argc, char *argv[])
{
    pfScene	    *scene;
    pfPipe	    *p;
    pfPipeWindow    *pw;
    pfChannel	    *chan;
    pfDCS	    *dcs;
    pfLOD	    *lod;
    pfGeoState      *gstate;
    void	    *arena;

    /* initialize Performer */    
    pfInit();
    pfMultiprocess(PFMP_DEFAULT);

    /* place "offset" in shared memory location before fork() call */
    offset = (float*)pfMalloc(sizeof(float), pfGetSharedArena());
    if (offset != NULL)
	*offset = 0.0f;

    /* initiate multi-processing mode */
    pfConfig();			    

    /* Set the graphics pipeline */
    p = pfGetPipe(0);
    pw = pfNewPWin(p);
    pfPWinType(pw, PFPWIN_TYPE_X);
    pfPWinName(pw, argv[0]);
    pfPWinOriginSize(pw, winOriginX, winOriginY, winSizeX ,winSizeY);
    pfPWinConfigFunc(pw, openPipeWin);
    pfConfigPWin(pw);

    pfPhase(PFPHASE_FLOAT);
    pfFrameRate(60.0f);

    /* get the malloc arena  */
    arena = pfGetSharedArena();

    /* create the root scene node */
    scene = pfNewScene();

    /* Create a scene pfGeoState with lighting enabled */
    gstate = pfNewGState(arena);
    pfGStateMode(gstate, PFSTATE_ENLIGHTING, PF_ON);

    /* attach pfGeoState to the scene */
    pfSceneGState(scene, gstate);

    /* create Level of Detail node */
    lod = generateTorusLODs(arena);

    /* attach the Level of Detail node to the scene */
    dcs = pfNewDCS();
    pfAddChild(dcs, lod);
    pfAddChild(scene, dcs);
 
    /* initialize the view */
    chan = pfNewChan(p);
    initView(chan);
    
    /* attach the scene to the channel */
    pfChanScene(chan, scene);	    

    while(!done)
    {
	/* update view position and direction   
	pfChanView(chan, view.xyz, view.hpr); */

	/* update the torus' position */
	pfDCSTrans(dcs, 0.0f, *offset, 0.0f);
	
	/* initiate traversal using current state */
	pfFrame();
    }

    /* terminate cull and draw processes */
    pfExit();

    /* exit to operating system */
    return 0;
}

/*
 *    initView() --sets up the initial viewing parameters 
 */
static void
initView(pfChannel *chan)
{
    pfEarthSky	*eSky;

    pfChanNearFar(chan, 0.0001f, 1000.0f);
    pfChanFOV(chan, 45.0f, -1.0f);

    /* set callback function for custom drawing */
    pfChanTravFunc(chan, PFTRAV_DRAW, drawChannel);

    /* create an Earth/Sky model that draws sky only */
    eSky = pfNewESky();
    pfESkyMode(eSky, PFES_BUFFER_CLEAR, PFES_FAST);
    pfESkyColor(eSky,PFES_CLEAR, 0.3f, 0.3f, 0.7f, 1.0f);
    pfChanESky(chan, eSky); 
    
    /* specify origin(X,Y,Z) and view direction(heading, pitch and roll)*/ 
    pfSetVec3(view.xyz, 0.0f, -8.0f, 8.0f);
    pfSetVec3(view.hpr, 0.0f,-40.0f, 0.0f);
    pfChanView(chan, view.xyz, view.hpr);
    pfChanViewport(chan,0.0f, 1.0f, 0.0f, 1.0f);
}


void
computeNormals(pfVec3 *verts,ushort *vl,pfVec3 *norms,ushort *nl,int numTris)
{
    int i, j;
    float *v0, *v1, *v2;
    pfVec3 vec0, vec1;

    for( j = 0, i = 0; i < numTris ; i++, j+=3)
    {
	v0 = verts[ vl[j]];
	v1 = verts[ vl[j+1]];
	v2 = verts[ vl[j+2]];
	PFSUB_VEC3(vec0, v1, v0);
	PFSUB_VEC3(vec1, v2, v1);
	pfCrossVec3(norms[i], vec0, vec1);
	pfNormalizeVec3(norms[i]);
	nl[i] = i;
    }
}

/*
 *    createTorusGSet()--Sweeps out a torus using an approximation
 *	     to a circle with numPoints. 
 */
static pfGeoSet *
createTorusGSet(void *arena,ushort numPieces, ushort numPoints, float radius)
{
    pfGeoSet	*gset;
    pfVec4	*clr;
    pfVec3	*verts, *norms;
    ushort	*v_ilist, *c_ilist, *n_ilist;
    int		numVerts, numTris,index;
    ushort	i, base, limit, piece;
    float	phi, theta, thetaAngInc, phiAngInc;
    float	sTheta, cTheta, sPhi, cPhi;
    pfGeoState  *gSt;
    pfMaterial	*mtl;

    /* create a new pfGeoSet */
    gset = pfNewGSet(arena);
 
    /* GeoSet will be comprised of independent triangles */
    pfGSetPrimType(gset, PFGS_TRIS);			
    numVerts	= numPieces*numPoints;
    numTris	= numPieces*2*numPoints;

    /* create a lists for vertex and color values */
    verts = (pfVec3 *)pfMalloc(sizeof(pfVec3)*numVerts,arena);
    norms = (pfVec3 *)pfMalloc(sizeof(pfVec3)*numTris, arena);
    clr = (pfVec4 *)pfMalloc(sizeof(pfVec4), arena);
    /* create indices lists for colors and triangle vertices */
    v_ilist = (ushort *)pfMalloc(sizeof(ushort)*numTris*3, arena);
    c_ilist = (ushort *)pfMalloc(sizeof(ushort), arena);
    n_ilist = (ushort *)pfMalloc(sizeof(ushort)*numTris, arena);

    /* set the color the entire GeoSet will be one color*/
    pfSetVec4(*clr, 0.5f, 0.1f, 0.1f, 1.0f);
    c_ilist[0] = 0;		    

    /* set attributes for the GeoSet */
    pfGSetNumPrims(gset, numTris);
    pfGSetAttr(gset, PFGS_COLOR4, PFGS_OVERALL, clr, c_ilist);
    pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, v_ilist);
    pfGSetAttr(gset, PFGS_NORMAL3, PFGS_PER_PRIM, norms, n_ilist);
 
    thetaAngInc = 360.f/numPieces;
    phiAngInc   = 360.f/numPoints;
    for(theta =0.0f,piece = 0,i=0; piece < numPieces; piece++)
    { 
	pfSinCos(theta, &sTheta, &cTheta);
	for( phi = 0.0f; phi < 360.0f; phi += phiAngInc )
	    {/* this loop generates each n-gonal piece.*/
		pfSinCos(phi, &sPhi, &cPhi);
		pfSetVec3(verts[i++], (3*radius + radius*cPhi)*cTheta, 
		 (3*radius + radius*cPhi)*sTheta, radius*sPhi);
	    }
	theta += thetaAngInc;
    }
    /* now establish connectivity with the indexlist  */
    piece = index = 0;
    for(base = piece*numPoints; piece < numPieces; piece++)
    {
	limit = base + numPoints;
	for( i = base; i < (numPoints+base); i++)
	{/* this loop connects each n-gonal piece to the next w/triangles */ 
	    v_ilist[index++] = i;
	    v_ilist[index++] = (i + numPoints)%numVerts;
	    v_ilist[index++] = (((i + 1) < limit)?(i+1):base);
	    v_ilist[index++] = (((i + 1) < limit)?(i+1):base);
	    v_ilist[index++] = (i + numPoints)%numVerts;
	    v_ilist[index++] = ((((i + 1)<limit)?i+1:base)+numPoints)%numVerts;
	}
	base = limit ;
    }
    computeNormals(verts, v_ilist, norms,n_ilist, numTris);
    /*pfPrint(gset, 1, NULL);*/
    
    mtl = pfNewMtl(arena);
    pfMtlColor(mtl, PFMTL_SPECULAR, 0.6f, 0.0f, 0.6f); 
    pfMtlColorMode(mtl, PFMTL_FRONT, PFMTL_CMODE_AD);        
    gSt = pfNewGState(arena);
    pfGStateAttr(gSt, PFSTATE_FRONTMTL, (void *)mtl);
    pfGSetGState(gset,gSt);

    return(gset);
}

/*  
 *	generateTorusLODs()-- creates Torus LOD node
 */
static pfLOD *
generateTorusLODs(void *arena)
{
    pfGeode  *geode;
    pfGeoSet *gset;
    pfLOD    *lod;
    pfVec3   center;
    int	     i;
    ushort   numLOD = 4;
    ushort   numPoints = 2 << numLOD;
    ushort   numPieces = 2 << numLOD;
    
    lod = pfNewLOD();
    for( i = 1; i <= numLOD; i++)
    {    
	/* create a new Geode */
	geode = pfNewGeode();

    	/* build a torus GeoSet */
	gset = createTorusGSet(arena, numPieces, numPoints, 1.0f);

	/* now add the GeoSet to the Geode */
	pfAddGSet(geode, gset);

	/* add geode as another level of detail node */
	pfAddChild(lod, geode);   

	/* simplify the geometry */	
	numPoints >>= 1;
	numPieces >>= 1;
    }

    /* set ranges for LODs, there should be (num LODs + 1) ranges */
    pfLODRange(lod, 0,   0.0f);
    pfLODRange(lod, 1,  25.0f);
    pfLODRange(lod, 2,  32.0f);
    pfLODRange(lod, 3,  39.0f);
    pfLODRange(lod, 4, 100.0f);

    /* set the center of the LOD */    
    pfSetVec3(center, 0.0f, 0.0f, 0.0f);
    pfLODCenter(lod, center);

    return(lod);
}

/*
 * Draw Process Routines
 */

static int WinXSize, WinYSize, ShowStats=0;

/*
 *    openPipeWin()-- opens a GL window and initializes  
 */
static void
openPipeWin(pfPipeWindow *pw)
{
    Display *dsp;
    Window win;
    
    pfOpenPWin(pw);

    pfGetPWinSize(pw, &WinXSize, &WinYSize);
    
    dsp = pfGetCurWSConnection();
    win = pfGetPWinWSWindow(pw);
    XSelectInput(dsp, win, PointerMotionMask | KeyPressMask | 
			    ButtonPressMask | ButtonReleaseMask);
    XMapWindow(dsp, win);
    
    pfLightOn(pfNewLight(NULL));
}

/*
 *	drawChannel()-- Custom drawing routine callback
 */
static void
drawChannel(pfChannel *chan, void *data)
{
    /* Must erase framebuffer and draw Earth-Sky model */
    pfClearChan(chan);

    /* get any input from GL */    
    processInput();			    

    /* invoke Performer draw for this frame */
    pfDraw();
    if (ShowStats)
	pfDrawChanStats(chan);
}

/*
 *	processInput()-- handles X input queue events in draw process
 */
static void 
processInput(void)
{
    Display *dsp;
    int x,y;
    static int leftDown=0, rightDown=0;
    static float vy = 0.0f;
    
    dsp = pfGetCurWSConnection();
    if (XEventsQueued(dsp, QueuedAfterFlush))
    while (XEventsQueued(dsp, QueuedAlready))
    {
	XEvent event;
	XNextEvent(dsp, &event);
	switch (event.type)
	{
	    case MotionNotify: 
	    {
		XMotionEvent *motion_event = (XMotionEvent *) &event;
		x =  motion_event->x;
		y = WinYSize - motion_event->y;
	    }
	    break;
	    case ButtonPress: 
	    {
		XButtonEvent *button_event = (XButtonEvent *) &event;
		x = event.xbutton.x;
		y = WinYSize - event.xbutton.y;
		switch (button_event->button) {
		    case Button1:
			leftDown = 1;
			break;
		    case Button3:
			rightDown = 1;
			break;
		}
	    }
	    break;
	    case ButtonRelease:
	    {
		XButtonEvent *button_event = (XButtonEvent *) &event;
		x = event.xbutton.x;
		y = WinYSize - event.xbutton.y;
		switch (button_event->button) {
		    case Button1:
			leftDown = 0;
			break;
		    case Button3:
			rightDown = 0;
			break;
		}
	    }
	    break;
	    case KeyPress:
            {
                char buf[100];
                int rv;
                KeySym ks;
                rv = XLookupString(&event.xkey, buf, sizeof(buf), &ks, 0);
                switch(ks) 
		{
                case XK_Escape:
                    exit(0);
                    break;
		case XK_F1:
		case XK_g:
		    ShowStats = !ShowStats;
		    break;
		case XK_w:
		    if( pfGetEnable(PFEN_WIREFRAME))
			pfDisable(PFEN_WIREFRAME);
		    else
			pfEnable(PFEN_WIREFRAME);
		    break;
		    break;
		default:
		    break;
		}
	    }
	 }
    }
   
    if (leftDown && (vy < 20.0f)) /* zoom in */
	vy += 0.1f;
    if (rightDown && (vy > -2.0f)) /* zoom out */
	vy -= 0.1f;

    if (offset != NULL)
	*offset = vy;
}