/* ////////////////////////////////////////////////////////////////////// */ /* */ /* callbacks.c - Intersection testing sample with callbacks */ /* Requires IRIS Performer 1.2 */ /* */ /* Available Fia anonymous FTP at ftp.sgi.com */ /* in the directory ~ftp/support/Pipeline */ /* */ /* To compile: */ /* cc -o callbacks callbacks.c -O2 -fullwarn -I/usr/include/Performer */ /* -L/usr/src/Performer/lib -lpfutil -lpf -lpr -lmpc -limage -lgl_s */ /* -lm -lfpe -lC */ /* */ /* To toggle the Statistics display, press the F1 or G keys. */ /* To toggle wireframe mode, press the W key. */ /* To toggle texturing, press the T key. */ /* To exit, press ESC. */ /* */ /* ////////////////////////////////////////////////////////////////////// */ #include #include #include #include #include #include #include typedef struct SharedData { int exitFlag; int showStats; float yval; float zval; } SharedData; typedef struct PassData { float x,y,z; } PassData; typedef struct NodeData { float offset; } NodeData; static void CullChannel (pfChannel *chan, void *data); static void DrawChannel (pfChannel *chan, void *data); static void OpenPipeline (pfPipe *p); static long PreCullCallback (pfTraverser *trav, void *data); static long PreDrawCallback (pfTraverser *trav, void *data); static long PostDrawCallback (pfTraverser *trav, void *data); SharedData *shared; static pfVec3 scoords[] ={ { -1.0f, -1.0f, 1.0f }, { 1.0f, -1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f }, { -1.0f, 1.0f, 1.0f }, { -2.0f, -2.0f, 0.0f }, { 2.0f, -2.0f, 0.0f }, { 2.0f, 2.0f, 0.0f }, { -2.0f, 2.0f, 0.0f }}; static ushort svindex[] ={ 0, 1, 2, 3, 0, 3, 7, 4, 4, 7, 6, 5, 1, 5, 6, 2, 3, 2, 6, 7, 0, 4, 5, 1}; static pfVec4 scolors[] ={ {1.0f, 0.0f, 0.0f, 0.5f}, {0.0f, 1.0f, 0.0f, 0.5f}, {0.0f, 0.0f, 1.0f, 0.5f}, {1.0f, 1.0f, 1.0f, 0.5f}}; static ushort scindex[] ={ 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3}; /* ////////////////////////////////////////////////////////////////////// */ void main() { pfPipe *pipe; pfChannel *chan; pfScene *scene; pfEarthSky *eSky; pfGroup *root; pfGeoSet *gset; pfSCS *scs[10]; pfGeode *geode; pfMatrix mat; pfCoord view; pfSegSet segset; PassData *passdata; int loop; /* Initialize Performer */ pfInit(); /* Use default multiprocessing mode based on number of processors. */ pfMultiprocess (PFMP_DEFAULT); /* Malloc storage in shared memory region for shared data */ shared = (SharedData *) pfMalloc(sizeof(SharedData),pfGetSharedArena()); /* Configure multiprocessing mode and start parallel processes */ pfConfig(); shared->exitFlag = 0; shared->showStats = 0; /* ////////////////////////////////////////////////////////////// */ /* Configure and open GL window */ pipe = pfGetPipe(0); pfInitPipe (pipe, OpenPipeline); pfFrameRate(30.0f); /* Create & configure channel */ chan = pfNewChan(pipe); pfChanCullFunc (chan, CullChannel); pfChanDrawFunc (chan, DrawChannel); pfChanNearFar (chan, 0.1f, 10000.0f); pfChanFOV (chan, 45.0f, -1.0f); passdata = pfAllocChanData (chan, sizeof(PassData)); /* Add an earth/sky effect */ eSky = pfNewESky(); pfESkyMode(eSky, PFES_BUFFER_CLEAR, PFES_SKY_GRND); pfESkyAttr(eSky, PFES_GRND_HT, -0.1f); pfESkyColor(eSky, PFES_SKY_TOP, 1.0f, 1.0f, 1.0f, 1.0f); pfESkyColor(eSky, PFES_SKY_BOT, 0.0f, 0.0f, 0.0f, 1.0f); pfESkyColor(eSky, PFES_HORIZ, 0.0f, 0.0f, 0.0f, 1.0f); pfESkyColor(eSky, PFES_GRND_FAR, 0.3f, 0.1f, 0.0f, 1.0f); pfESkyColor(eSky, PFES_GRND_NEAR, 0.5f, 0.3f, 0.1f, 1.0f); pfChanESky(chan, eSky); /* ////////////////////////////////////////////////////////////// */ /* Create pfScene node, attach it to channel */ scene = pfNewScene(); pfChanScene (chan, scene); /* Create group node to hold SCS's; attach it to scene */ root = pfNewGroup(); pfAddChild (scene, root); /* Create 10 SCS nodes, spaced equally apart. Make each one a child of 'root', and make 'geode' a child of each SCS */ geode = pfNewGeode(); for (loop=0; loop < 10; loop++) { NodeData *nodedata = pfMalloc (sizeof(NodeData), pfGetSharedArena()); nodedata->offset = (float) loop * 10.0f + 10.0f; pfMakeTransMat (mat, 0.0f, (float) loop * 10.0f + 10.0f, 0.0f); scs[loop] = pfNewSCS (mat); pfAddChild (scs[loop], geode); pfAddChild (root, scs[loop]); /* set up SCS's (and their children) for intersections */ pfNodeTravMask (scs[loop], PFTRAV_ISECT, 1, PFTRAV_SELF, PF_SET); /* Add a CULL traversal callback to each SCS */ pfNodeTravFuncs (scs[loop], PFTRAV_CULL, PreCullCallback, NULL); pfUserData (scs[loop], nodedata); pfNodeTravFuncs (scs[loop], PFTRAV_DRAW, PreDrawCallback, PostDrawCallback); } /* Create a GeoSet to hold the ramp geometry */ gset = pfNewGSet (pfGetSharedArena()); pfGSetAttr (gset, PFGS_COORD3, PFGS_PER_VERTEX, scoords, svindex); pfGSetAttr (gset, PFGS_COLOR4, PFGS_PER_VERTEX, scolors,scindex); pfGSetPrimType (gset, PFGS_QUADS); pfGSetNumPrims (gset, 6); /* attach it to the parent geode */ pfAddGSet (geode, gset); /* ////////////////////////////////////////////////////////////// */ /* set initial view position */ shared->yval=0.0f; shared->zval=0.5f; /* set up intersection segment, pointing down for "terrain" following */ segset.activeMask = 1; segset.isectMask = 0xFFFF; segset.mode = PFTRAV_IS_PRIM|PFTRAV_IS_NORM|PFTRAV_IS_CULL_BACK; pfSetVec3(segset.segs[0].dir, 0.0f, 0.0f, -1.0f); segset.segs[0].length = 50000.0f; /* ////////////////////////////////////////////////////////////// */ /* main loop */ while (!shared->exitFlag) { pfHit **hits[100]; long isect; pfSetVec3(view.xyz, 0.0f, shared->yval, shared->zval); pfSetVec3(view.hpr, 0.0f, -5.0f, 0.0f); passdata->x = 0.0f; passdata->y = shared->yval; passdata->z = shared->zval; pfChanView (chan, view.xyz, view.hpr); pfPassChanData (chan); pfFrame(); /* increment view position; if too far, reset */ shared->yval += 0.1f; if (shared->yval > 110.0f) shared->yval = 0.0f; /* update location of intersection segment */ pfSetVec3(segset.segs[0].pos, 0.0f, shared->yval,shared->zval); /* do an intersection test against the scene graph */ isect = pfSegsIsectNode(root, &segset, hits); /* if successful, set our height to that of the point of contact, plus a small offset */ if (isect) { pfVec3 pnt; pfQueryHit (*hits[0], PFQHIT_POINT, &pnt); shared->zval = pnt[PF_Z] + 0.5; } } pfExit(); } /* ////////////////////////////////////////////////////////////////////// */ /* Pipe Initialization Callback to open and configure * GL window, and set up GL event handling */ static void OpenPipeline (pfPipe *p) { pfTexture *tex; foreground(); winopen ("Terrain"); pfInitGfx(p); qdevice (ESCKEY); qdevice (F1KEY); qdevice (GKEY); qdevice (TKEY); qdevice (WKEY); tex = pfNewTex (pfGetSharedArena()); pfFilePath ("/usr/demos/data/textures"); pfLoadTexFile (tex, "cafe.rgb"); pfApplyTex (tex); pfApplyTEnv (pfNewTEnv (pfGetSharedArena())); if (pfGetEnable (PFEN_TEXTURE)) pfEnable (PFEN_TEXTURE); } /* ////////////////////////////////////////////////////////////////////// */ static long PreDrawCallback (pfTraverser *trav, void *data) { if (!pfGetEnable(PFEN_TEXTURE)) return 0; texgen(TX_S, TG_SPHEREMAP, 0); texgen(TX_T, TG_SPHEREMAP, 0); texgen(TX_S, TG_ON, NULL); texgen(TX_T, TG_ON, NULL); return 0; } /* ////////////////////////////////////////////////////////////////////// */ static long PostDrawCallback (pfTraverser *trav, void *data) { if (!pfGetEnable(PFEN_TEXTURE)) return 0; texgen(TX_S, TG_OFF, NULL); texgen(TX_T, TG_OFF, NULL); return 0; } /* ////////////////////////////////////////////////////////////////////// */ static long PreCullCallback (pfTraverser *trav, void *data) { PassData *pass = pfGetChanData (pfGetTravChan(trav)); NodeData *nodedata = pfGetUserData(pfGetTravNode(trav)); if (pfGetCullResult() & PFIS_FALSE) return PFTRAV_PRUNE; if ((pass->z < 1.0) && (pass->y < nodedata->offset-10.0f)) return PFTRAV_PRUNE; return PFTRAV_CONT; } /* /////////////////////////////////////////////////////////////////////// */ /* Cull Process Callback to cull the channel. Custom traversal would be */ /* done here.. */ static void CullChannel (pfChannel *chan, void *data) { pfCull(); } /* /////////////////////////////////////////////////////////////////////// */ /* Draw Process Callback to draw the channel and handle GL events */ static void DrawChannel (pfChannel *chan, void *data) { static pfMatrix tempmat; short dev,val; char string[40]; PassData *pass = (PassData*) data; /* clear and draw the channel */ pfClearChan (chan); pfDraw(); if (shared->showStats) pfDrawChanStats(chan); zfunction (ZF_ALWAYS); /* HUD always drawn */ zwritemask (0x0); pfPushState(); pfBasicState(); ortho2 (-0.5, 10.0, -0.5, 10.0); pfPushIdentMatrix(); cpack(0x000000); cmov2 (0.0, 0.0); sprintf(string, "x = %2.2f y = %2.2f z = %2.2f", pass->x, pass->y, pass->z); charstr (string); pfPopMatrix(); pfPopState(); zfunction (ZF_LEQUAL); /* the default */ zwritemask (0xffffffff); while (qtest()) { dev = qread(&val); if (val) switch (dev) { case ESCKEY: shared->exitFlag=1; break; case F1KEY: case GKEY: shared->showStats = !shared->showStats; break; case TKEY: if (pfGetEnable(PFEN_TEXTURE)) pfDisable (PFEN_TEXTURE); else pfEnable (PFEN_TEXTURE); break; case WKEY: if (pfGetEnable(PFEN_WIREFRAME)) pfDisable (PFEN_WIREFRAME); else pfEnable (PFEN_WIREFRAME); break; } } } /* /////////////////////////////////////////////////////////////////////// */