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

File: [Development] / performer / src / pguide / libpf / C / pbuffer.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
 *
 * pbuffer.c
 * 
 * OpenGL Performer pfPipeWindow example showing use of pbuffers.
 *
 * $Revision: 1.1 $ 
 * $Date: 2000/11/21 21:39:37 $
 *
 * Command line options:
 *	'b'	: noborder window
 *	'F'	: run X input in forked process
 *	'm procsplit' : multiprocess mode
 *
 *
 * Run-time controls:
 *       ESC-key: exits
 *        F1-key: profile
 *    Left-mouse: advance
 *  Middle-mouse: stop
 *   Right-mouse: retreat
 *	C-key	: close window (will auto-reopen in 3 secs).
 *	s-key	: toggle window between gfx and fill-stats windows
 */

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <signal.h> /* for sigset for forked X event handler process */
#include <getopt.h> /* for cmdline handler */
#include <X11/keysym.h>
#include <Performer/pf.h>
#include <Performer/pfutil.h>
#include <Performer/pfdu.h>

#define WIN_SIZE 400

/*
 * structure that resides in shared memory so that the
 * application, cull, and draw processes can access it.
 */
typedef struct
{
    pfPipeWindow    *pwCopy;
    pfPipeWindow    *pwPbuf;
    int		    exitFlag;
    int		    inWindow, reset;
    float	    mouseX, mouseY;
    int		    winSizeX, winSizeY;
    int		    mouseButtons;
    pfCoord	    view, viewOrig;
    float	    sceneSize;
    int		    drawStats;
} SharedData;


static int FBAttrs[] = {
    GLX_DRAWABLE_TYPE_SGIX, GLX_WINDOW_BIT_SGIX|GLX_PBUFFER_BIT_SGIX,
    GLX_RENDER_TYPE_SGIX, GLX_RGBA_BIT_SGIX,
    PFFB_RED_SIZE, 5,
    PFFB_BLUE_SIZE, 5,
    PFFB_GREEN_SIZE, 5,
    None,
};

static SharedData *Shared;

/*
 * APP process variables
 */
/* for configuring multi-process */
static int ProcSplit = PFMP_DEFAULT;
/* write out scene upon read-in - uses pfDebugPrint */
static int WinType = PFPWIN_TYPE_X;
char ProgName[PF_MAXSTRING];
 
/* light source created and updated in DRAW-process */
static pfLight *Sun=NULL;
  
static void CullChannel(pfChannel *chan, void *data);
static void DrawCopy(pfChannel *chan, void *data);
static void DrawPbuf(pfChannel *chan, void *data);
static void OpenPbuf(pfPipeWindow *pw);
static void OpenCopy(pfPipeWindow *pw);
static void Usage(void);


/*
 *	Usage() -- print usage advice and exit. This procedure
 *	is executed in the application process.
 */

static void
Usage (void)
{
    pfNotify(PFNFY_FATAL, PFNFY_USAGE, 
	    "Usage: %s [-m procSplit] [file.ext ...]\n", ProgName);
    exit(1);
}

/*
*	docmdline() -- use getopt to get command-line arguments, 
*	executed at the start of the application process.
*/

static int
docmdline(int argc, char *argv[])
{
    int	    opt;

    strcpy(ProgName, argv[0]);
    
    /* process command-line arguments */
    while ((opt = getopt(argc, argv, "Fm:Rp:?")) != -1)
    {
	switch (opt)
	{
	case 'm':
	case 'p':
	    ProcSplit = atoi(optarg);
	    break;
	case '?': 
	    Usage();
	}
    }
    return optind;
}

/*
 *	main() -- program entry point. this procedure
 *	is executed in the application process.
 */

int
main (int argc, char *argv[])
{
    int		    arg;
    int		    found;
    pfNode	   *root;
    pfChannel      *chanPbuf, *chanCopy;
    pfScene        *scene;
    pfPipe         *p;
    pfPipeWindow   *pw;
    pfEarthSky     *eSky;
    pfFrameStats   *fstats;
    pfSphere        bsphere;
    float	    far = 10000.0f;
    double	    ct;
    pfWSConnection  dsp=NULL;


    arg = docmdline(argc, argv);

    pfInit();

    /* configure multi-process selection */
    pfMultiprocess(ProcSplit);
    
    /* allocate shared before fork()'ing parallel processes */
    Shared = (SharedData*)pfCalloc(1, sizeof(SharedData), pfGetSharedArena());
    Shared->inWindow = 0;
    Shared->reset = 0;
    Shared->exitFlag = 0;
    Shared->drawStats = 0;

    /* Load all loader DSO's before pfConfig() forks */
    for (found = arg; found < argc; found++)
	pfdInitConverter(argv[found]);

    /* initiate multi-processing mode set in pfMultiprocess call 
     * FORKs for Performer processes,  CULL and DRAW, etc. happen here.
     */
    pfConfig();
    
    /* configure pipes and windows */
    p = pfGetPipe(0);
    pfPipeScreen(p, 0);
    
    Shared->pwPbuf = pfNewPWin(p);
    Shared->pwCopy = pfNewPWin(p); /* make copy 2nd so pbuf is drawn first */
    pfPWinShare(Shared->pwPbuf,  PFWIN_SHARE_FBCONFIG | PFWIN_SHARE_STATE | PFWIN_SHARE_GL_OBJS);
    pfPWinType(Shared->pwPbuf, PFPWIN_TYPE_SHARE);
    pfPWinType(Shared->pwCopy, PFPWIN_TYPE_SHARE);


    pfPWinOriginSize(Shared->pwPbuf, 0, 0, WIN_SIZE, WIN_SIZE);
    pfPWinOriginSize(Shared->pwCopy, 0, 0, WIN_SIZE, WIN_SIZE);
    
    pfPWinName(Shared->pwPbuf, "PBuffer");
    pfPWinType(Shared->pwPbuf, WinType | PFWIN_TYPE_PBUFFER);
    /* Open and configure the GL window. */
    pfPWinConfigFunc(Shared->pwPbuf, OpenPbuf);
    pfConfigPWin(Shared->pwPbuf);
    
    pfPWinName(Shared->pwCopy, "Copy");
    pfPWinType(Shared->pwCopy, WinType);
    /* Open and configure the GL window. */
    pfPWinConfigFunc(Shared->pwCopy, OpenCopy);
    pfConfigPWin(Shared->pwCopy);

    /* specify directories where geometry and textures exist */
    if (!(getenv("PFPATH")))
        pfFilePath(
                   "."
                   ":./data"
                   ":../data"
                   ":../../data"
                   ":../../../../data"
                   ":/usr/share/Performer/data"
                   );
    pfNotify(PFNFY_INFO, PFNFY_PRINT,"FilePath: %s\n", pfGetFilePath());
    
    /* load files named by command line arguments */
    scene = pfNewScene();
    for (found = 0; arg < argc; arg++)
    {
	if ((root = pfdLoadFile(argv[arg])) != NULL)
	{
	    pfAddChild(scene, root);
	    found++;
	}
    }

    /* if no files successfully loaded, terminate program */
#if 0
    if (!found)
	Usage();
#endif


    pfFrameRate(30.0f);
    pfPhase(PFPHASE_FREE_RUN);
    
    chanPbuf = pfNewChan(p);
    pfAddChan(Shared->pwPbuf, chanPbuf);
    pfChanTravFunc(chanPbuf, PFTRAV_CULL, CullChannel);
    pfChanTravFunc(chanPbuf, PFTRAV_DRAW, DrawPbuf);
    pfChanScene(chanPbuf, scene);
    pfChanNearFar(chanPbuf, 0.1f, far);
    
    /* Create an earth/sky model that draws sky/ground/horizon */
    eSky = pfNewESky();
    pfESkyMode(eSky, PFES_BUFFER_CLEAR, PFES_SKY_GRND);
    pfESkyAttr(eSky, PFES_GRND_HT, -10.0f);
    pfChanESky(chanPbuf, eSky);
    
    /* vertical FOV is matched to window aspect ratio */
    pfChanFOV(chanPbuf, 45.0f, -1.0f);
    if (found)
    {
	pfGetNodeBSphere (scene, &bsphere);
	Shared->sceneSize = bsphere.radius;
    }  else
    {
	pfSetVec3(Shared->view.xyz, 0.0f, 0.0f, 100.0f);
	PFSET_VEC3(bsphere.center, 0.0, 0.0, 0.0);
	bsphere.radius = Shared->sceneSize = 10000.0f;
    }
    pfSetVec3(Shared->view.hpr, 0.0f, 0.0f, 0.0f);
    pfChanView(chanPbuf, Shared->view.xyz, Shared->view.hpr);
    PFCOPY_VEC3(Shared->viewOrig.xyz, Shared->view.xyz);
    PFCOPY_VEC3(Shared->viewOrig.hpr, Shared->view.hpr);
    
    chanCopy = pfNewChan(p);
    pfMakeOrthoChan(chanCopy, 0, WIN_SIZE, 0, WIN_SIZE);
    pfChanNearFar(chanCopy, -1, 100);
    pfChanTravFunc(chanCopy, PFTRAV_DRAW, DrawCopy);
    pfAddChan(Shared->pwCopy, chanCopy);
    pfChanScene(chanCopy, pfNewScene());
    
    pfFrame();
    
    /* main simulation loop */
    while (!Shared->exitFlag)
    {
	double t;
	float s, c;
	/* wait until next frame boundary */
	pfSync();
	
	pfFrame();
	
	/* Compute new view position. */
	t = pfGetTime();
	pfSinCos(45.0f*t, &s, &c);
	pfSetVec3(Shared->view.hpr, 45.0f*t, -10.0f, 0);
	pfSetVec3(Shared->view.xyz, 2.0f * bsphere.radius * s, 
		-2.0f * bsphere.radius *c, 0.5f * bsphere.radius);
	
	pfChanView(chanPbuf, Shared->view.xyz, Shared->view.hpr);
	/* initiate traversal using current state */
    }
    
    /* terminate cull and draw processes (if they exist) */
    pfExit();
    
    /* exit to operating system */
    return 0;
}

/*
 *	CullChannel() -- traverse the scene graph and generate a
 * 	display list for the draw process.  This procedure is 
 *	executed in the CULL process.
 */

static void
CullChannel(pfChannel *channel, void *data)
{
    /* 
     * pfDrawGeoSet or other display listable Performer routines
     * could be invoked before or after pfCull()
     */
    
    (channel, data);
    
    pfCull();
}


/*
 *	OpenPipeWin() -- create a win: setup the GL and OpenGL Performer.
 *	This procedure is executed in the DRAW process 
 *	(when there is a separate draw process).
 */
 
static void
OpenPbuf(pfPipeWindow *pw)
{
    pfPipe *p;
    pfWSConnection dsp;
    int xs=0, ys=0, wxs, wys, num, screen, ret;
    Window pbuf;
    GLXFBConfigSGIX *fbc;

    dsp = pfGetCurWSConnection();
    screen = pfGetPWinScreen(pw);
    if (screen < 0)
    {
	screen = DefaultScreen(dsp);
	pfPWinScreen(pw, screen);
    }
    {
    fbc = glXChooseFBConfigSGIX(dsp, 0, FBAttrs, &num);
pfNotify(PFNFY_NOTICE,PFNFY_PRINT,"Num matching FBConfigs on display 0x%p=%s screen %d is %d", 
	dsp, XDisplayString(dsp), screen, num);

    /* just use first FBConfig found */
#if 0
    glXGetFBConfigAttribSGIX(dsp, *fbc, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX, &xs);
    glXGetFBConfigAttribSGIX(dsp, *fbc, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX, &ys);
pfNotify(PFNFY_NOTICE,PFNFY_PRINT, "Optimal pbuffer size: %d %d", xs, ys);
#endif

    /* note that since we are drawing to the pbuffer, if the pbuffer
     * is bigger, the visual window will only show the lower-left
     * corner of the scene 
     */
    pfGetPWinSize(pw, &wxs, &wys);
    if (!xs)
    {
	xs = wxs;
	ys = wys;
    }
    else if (xs < wxs || ys < wys)
	pfPWinSize(Shared->pwCopy, xs, ys);

    pfPWinSize(pw, xs, ys);
    pfPWinFBConfig(pw, *fbc);
    }
    pfOpenPWin(pw);

    pbuf = pfGetPWinWSDrawable(pw);
    pfNotify(PFNFY_NOTICE,PFNFY_PRINT,"PBuf is 0x%x", pbuf);

    /* create a light source in the "south-west" (QIII) */
    Sun = pfNewLight(NULL);
    pfLightPos(Sun, -0.3f, -0.3f, 1.0f, 0.0f);
    
    pfNotify(PFNFY_NOTICE,PFNFY_PRINT,"PBuf is OPEN");
}
 
static void
OpenCopy(pfPipeWindow *pw)
{
    
    pfOpenPWin(pw);

    pfNotify(PFNFY_NOTICE,PFNFY_PRINT,"Main window is OPEN");
}

/*
 *	DrawPbuf() -- draw the scene graph into the pbuffer window
 *	procedure is executed in the draw process (when there is a
 *	separate draw process).
 */
static void
DrawPbuf (pfChannel *channel, void *data)
{
    /* rebind light so it stays fixed in position */
    pfLightOn(Sun);

    /* erase framebuffer and draw Earth-Sky model */
    pfClearChan(channel);
    
    /* invoke Performer draw-processing for this frame */
    pfDraw();

    /* draw Performer throughput statistics */
    pfDrawChanStats(channel);
}

/*
 *	DrawCopy() -- copy the pbuffer window the visible window
 */
static void
DrawCopy (pfChannel *channel, void *data)
{
    pfWSDrawable draw, read;
    pfGLContext ctx;
    int width,  height;
    pfWSConnection dsp;
    
    pfGetPWinSize(Shared->pwCopy, &width, &height);
    dsp = pfGetCurWSConnection();
    read = pfGetPWinWSDrawable(Shared->pwPbuf);
    draw = pfGetPWinWSDrawable(Shared->pwCopy);
    ctx = pfGetPWinGLCxt(Shared->pwCopy);

#if 0
    if (!read)
	return;
#endif

    glXMakeCurrentReadSGI(dsp, draw, read, ctx);
    pfPushIdentMatrix();
    glRasterPos2i(1, 1);
    glCopyPixels(0, 0, width, height, GL_COLOR);

    pfPopMatrix();
   {
   int err;
   if ((err = glGetError()) != GL_NO_ERROR)
        pfNotify(PFNFY_NOTICE,PFNFY_USAGE,"OpenGL Error 0x%x - %s",err, gluErrorString(err));
   }
}