A fix for pfuTravCalcBBox

New Message Reply Date view Thread view Subject view Author view

Ran Yakir (rany++at++bvr.co.il)
Tue, 01 Sep 1998 09:20:22 +0200


Hi All

Has anybody noticed that pfuTravCalcBBox doesn't handle pfBillboards ?
Attached to this mail is trav.c from the libpfutil with my suggestion of
how to handle billboards. My approach was to take the bounding box of
each billboard geoset, and apply the xsize to the ysize :

     gsetbox.min[1] = gsetbox.min[0];
     gsetbox.max[1] = gsetbox.max[0];
and then translate that box by the appropriate billboard position, and
extend the geode's box by it.
Maybe it will be even better to apply the max(xsize,ysize) to both xsize
and ysize, although most billboards are single polygons, so
max(xsize,ysize) will be xsize anyway.

May I suggest that this fix will go into the next distribution of
Performer ?

Ran

--
 __                                  | Ran Yakir
 /_)  _  __   \  / _   / o __        | BVR Technologies Ltd.
/ )_ (_(_) )   \/ (_(_/<_(_)(        |
              _/                     |
-------------------------------------+--------------------------------
Phone :                              | E-mail : rany++at++bvr.co.il
  Work : 972-3-5715671 #166,#177     |
  Res. : 972-9-7489974               |
Fax    : 972-3-5715668               |

http://www.rtset.co.il/rany

/* * Copyright 1993, 1994, 1995, Silicon Graphics, Inc. * ALL RIGHTS RESERVED * * UNPUBLISHED -- Rights reserved under the copyright laws of the United * States. Use of a copyright notice is precautionary only and does not * imply publication or disclosure. * * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND: * Use, duplication or disclosure by the Government is subject to restrictions * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or * in similar or successor clauses in the FAR, or the DOD or NASA FAR * Supplement. Contractor/manufacturer is Silicon Graphics, Inc., * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311. * * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION, * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON * GRAPHICS, INC. */

/* * file: trav.c * ------------- * * $Revision: 1.1 $ * $Date: 1998/08/30 15:15:11 $ * * Sample implementation of general user traversal utility. * * Specific Traversals implemented here: * o pfuTravPrintNodes() - a printing traversal * o pfuTravGLProf() - a traversal for outputing glprof object tags * (needs libflprof.a) * o pfuTravCountDB() - accumulates static graphics and database statistics * for the tree under the given node. * o pfuTravNodeHlight() - sets a given highlighting structure on all of the * pfGeoSet under the given node. * o pfuTravNodeAttrBind() - sets a given attr to the given bind value on * every pfGeoSet under the given node. * o pfuTravCalcBBox() - compute the bounding box * o pfuTravCountNumVerts() - count the number of vertices * o pfuTravSetDListMode() - * o pfuTravCreatePackedAttrs() - * o pfuFillGSetPackedAttrs() - * o pfuDelGSetAttrs() - * o pfuTravCachedCull() - * o pfuCalcDepth() - calculate the depth of the scene graph rooted at node. * a single root node with no children is counted * as having depth 1. * o pfuLowestCommonAncestor() - find the lowest common ancestor * of all nodes under node for which a given function returns true. * o pfuLowestCommonAncestorOfGeoSets() - find the lowest common ancestor node * of all geosets under node for which a given function returns true. * o pfuFindTexture() - find the n'th texture under a given node * for which a given function returns true. */

/****************************************************************************** * NOTES ****************************************************************************** */

/* * Sample code to put in program for calling the GLProf Traversal if (doGLProfTraversal) { if (glProfMode) { pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "installing glprof object tags"); pfuDoTravGLProf((pfNode *)scene, 1); } else { pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "removing glprof object tags"); pfuDoTravGLProf((pfNode *)scene, 1); } doGLProfTraversal = 0; } */

/* Traversals for SCSs and DCSs: * need matrix stacks if callback wants to be able to transform from * object coordinates into world coordinates. * trav.mstack = pfNewMStack(32, pfGetSharedArena()); .... pfuTraverse(trav); pfDelete(trav.mstack); */

#define _PFU_TRAV_C_

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <X11/X.h>

#include <Performer/pfutil.h>

/*extern void glpObject(unsigned int inNum, const char *inName);*/ void glprof_object (char *str) { (str, str); #ifdef IRISGL /*glpObject(0x10000, str);*/ #else /* OPENGL */ /* XXX glprof tags for OpenGL missing */ #endif /* GL type */ }

/****************************************************************************** * Static Variables ****************************************************************************** */

/* tables for printing modes and types */

static char primTable[9][32] ={ "POINTS", "LINES", "LINESTRIPS", "TRIS", "QUADS", "TRISTRIPS", "FLAT_LINESTRIPS", "FLAT_TRISTRIPS", "POLYS" "TRIFANS" "FLAT_TRIFANS" };

#if 0 static char *attrTable[4] = { "PFGS_COLOR4", "PFGS_NORMAL3", "PFGS_TEXCOORD2", "PFGS_COORD3" }; #endif

static char bindTable[4][32] ={ "OFF", "OVERALL", "PER_PRIM", "PER_VERT" };

static FILE *outFP;

/****************************************************************************** * General traversal routine ****************************************************************************** */

/* * Set up pfuTraverser with reasonable defaults. */ void pfuInitTraverser(pfuTraverser *trav) { trav->preFunc = NULL; trav->postFunc = NULL; trav->mode = PFUTRAV_SW_ALL | PFUTRAV_LOD_ALL | PFUTRAV_SEQ_ALL; trav->mstack = NULL; trav->data = NULL; trav->node = NULL; trav->depth = 0; } /* * Main traversal routine * recursively traverses database under node, applying the * the pre and post traversal functions specied in the * trav structure to each node. */

#define PFU_DO_RET(_ret) \ switch (_ret) \ { \ case PFTRAV_PRUNE: \ trav->node = prevNode; \ if (needPop) \ pfPopMStack(trav->mstack); \ return PFTRAV_CONT; \ case PFTRAV_TERM: \ trav->node = prevNode; \ if (needPop) \ pfPopMStack(trav->mstack); \ return PFTRAV_TERM; \ }

static int travChild(pfGroup *group, int i, pfuTraverser *trav) { int ret;

trav->depth++; ret = pfuTraverse((pfNode*)pfGetChild(group, i), trav); trav->depth--;

return ret; }

int pfuTraverse(pfNode *node, pfuTraverser *trav) { int i; int numChild = 1; int val; float range0, range1; int ret = PFTRAV_CONT, needPop = 0; pfNode *prevNode = trav->node; if (node == NULL) { pfNotify(PFNFY_WARN, PFNFY_USAGE, "pfuTraverse() Null node"); return PFTRAV_CONT; } trav->node = (pfNode *)node; if (pfIsOfType(node, pfGetSCSClassType()) && trav->mstack) { pfMatrix mat;

pfGetSCSMat((pfSCS *)trav->node, mat);

pfPushMStack(trav->mstack); pfPreMultMStack(trav->mstack, mat); needPop = 1; }

if (trav->preFunc) ret = (*trav->preFunc)(trav);

PFU_DO_RET(ret);

/* Reset variables in case preFunc replaced the current node */ node = trav->node; if (node == NULL) return PFTRAV_CONT;

/* after preFunc, in case topology changed */ if (pfIsOfType(node, pfGetGroupClassType())) numChild = pfGetNumChildren(node); /* pfSwitch */ if (pfIsOfType(node, pfGetSwitchClassType())) switch (trav->mode & PFUTRAV_SW_MASK) { case PFUTRAV_SW_CUR: val = pfGetSwitchVal((pfSwitch *)node); ret = travChild((pfGroup*)node, val, trav); break; case PFUTRAV_SW_ALL: for (i = 0 ; i < numChild && ret == PFTRAV_CONT ; i++) { ret = travChild((pfGroup*)node, i, trav); if(numChild > pfGetNumChildren(node)) /* if the child is deleted */ { i--; numChild--; } } break; case PFUTRAV_SW_NONE: break; } /* pfLOD */ else if (pfIsOfType(node, pfGetLODClassType())) switch (trav->mode & PFUTRAV_LOD_MASK) { case PFUTRAV_LOD_RANGE0: range0 = pfGetLODRange((pfLOD *)node, 0); range1 = pfGetLODRange((pfLOD *)node, 1); if (range0 <= 0.0f && 0.0f < range1) if (numChild > 0) ret = travChild((pfGroup*)node, 0, trav); break; case PFUTRAV_LOD_ALL: for (i = 0 ; i < numChild && ret == PFTRAV_CONT ; i++) { ret = travChild((pfGroup*)node, i, trav); if(numChild > pfGetNumChildren(node)) /* if the child is deleted */ { i--; numChild--; } } break; } /* pfSequence */ else if (pfIsOfType(node, pfGetSeqClassType())) switch (trav->mode & PFUTRAV_SEQ_MASK) { case PFUTRAV_SEQ_CUR: if ((val = pfGetSeqFrame((pfSequence *)node, NULL)) >= 0) ret = travChild((pfGroup*)node, val, trav); else ret = PFTRAV_PRUNE; break; case PFUTRAV_SEQ_ALL: for (i = 0 ; i < numChild && ret == PFTRAV_CONT ; i++) { ret = travChild((pfGroup*)node, i, trav); if(numChild > pfGetNumChildren(node)) /* if the child is deleted */ { i--; numChild--; } } break; case PFUTRAV_SEQ_NONE: break; } /* other pfGroups */ else if (pfIsOfType(node, pfGetGroupClassType())) for (i = 0 ; i < numChild && ret == PFTRAV_CONT ; i++) { ret = travChild((pfGroup*)node, i, trav); if(numChild > pfGetNumChildren(node)) /* if the child is deleted */ { i--; numChild--; } } /* other nodes, presume leaf */ else if (pfIsOfType(node, pfGetNodeClassType())) ; else pfNotify(PFNFY_WARN, PFNFY_USAGE, "pfuTraverse() Unknown node type 0x%x - %s", pfGetType(node), pfGetTypeName((pfObject *)node)); PFU_DO_RET(ret); trav->node = (pfNode *)node; if (trav->postFunc) ret = (*trav->postFunc)(trav); PFU_DO_RET(ret); if (needPop) pfPopMStack(trav->mstack); return PFTRAV_CONT; }

/************************************************************ * Various and Sundry Sample Traversals using pfuTraverse ************************************************************/

/************************************************************************ * Traversal and callback for printing info on pfGeoSets inside pfGeodes ***********************************************************************/

/* * traversal callback for printing out database information */

static int cbPrintNodeInfo(pfuTraverser *trav) { pfNode *node = trav->node; if (node == NULL) { pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbPrintNodeInfo: node null!"); return PFTRAV_CONT; } fprintf(outFP, "\nNode %s: type: %s address 0x%p\n", pfGetNodeName(node), pfGetTypeName((pfObject *)node), node); if (pfIsOfType(node, pfGetGeodeClassType())) { int nGSets = pfGetNumGSets((pfGeode *)node); int i; fprintf(outFP, "\tnum GeoSets: %d\n", nGSets); for (i = 0 ; i < nGSets ; i++) { pfGeoSet *gd = pfGetGSet((pfGeode *)node, i); int nPrims = pfGetGSetNumPrims(gd); int ptype = pfGetGSetPrimType(gd); int cbind = pfGetGSetAttrBind(gd, PFGS_COLOR4); int nbind = pfGetGSetAttrBind(gd, PFGS_NORMAL3); int tbind = pfGetGSetAttrBind(gd, PFGS_TEXCOORD2); pfGeoState *gs = pfGetGSetGState((pfGeoSet *)node); int nVerts = 0; int k; fprintf(outFP, "\t GeoSet %d: %s - %d prims, cbind=%s, " "nbind=%s, tbind=%s flatshade=%d\n", i, primTable[ptype], nPrims, bindTable[cbind], bindTable[nbind], bindTable[tbind], pfGetGSetDrawMode(gd, PFGS_FLATSHADE)); switch (ptype) { case PFGS_LINES: nVerts = 2 *nPrims; break; case PFGS_TRIS: nVerts = 3 * nPrims; break; case PFGS_QUADS: nVerts = 4 * nPrims; break; case PFGS_LINESTRIPS: case PFGS_FLAT_LINESTRIPS: { for (k = 0 ; k < nPrims ; k++) nVerts += pfGetGSetPrimLength(gd, k); } break; case PFGS_TRISTRIPS: case PFGS_FLAT_TRISTRIPS: case PFGS_POLYS: case PFGS_TRIFANS: case PFGS_FLAT_TRIFANS: { int len; fprintf(outFP, "\t\tlengths:"); for (k = 0 ; k < nPrims ; k++) { len = pfGetGSetPrimLength(gd, k); nVerts += len; fprintf(outFP, " %d",len); } fprintf(outFP, "\n"); } break; } fprintf(outFP, "\tGeoState: 0x%x\n", gs); } } return PFTRAV_CONT; }

/* Printing Traversal */ void pfuTravPrintNodes(pfNode *node, const char *fname) { pfuTraverser trav; pfuInitTraverser(&trav); if (!fname) outFP = stdout; else if (!(outFP = fopen(fname, "w"))) { pfNotify(PFNFY_FATAL, PFNFY_RESOURCE, "pfuTravPrintNodes: can't open %s for write", fname); exit(0); } trav.preFunc = cbPrintNodeInfo; pfuTraverse(node, &trav); }

/***************************************************************** * Traversal and callback to accumulate counts into a pfFrameStats *****************************************************************/

static int cbCountNodes(pfuTraverser *trav) { pfNode *node = trav->node; pfFrameStats *fstats = (pfFrameStats *)(trav->data); int nGSets, i; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbCountNodes: node null!"); /* pfBillboard */ else if (pfIsOfType(node, pfGetBboardClassType())) { pfFStatsCountNode(fstats, PFFSTATS_DB, PFFSTATS_DB_VIS, node); nGSets = pfGetNumGSets((pfBillboard *)node); for (i = 0 ; i < nGSets ; i++) { pfGeoSet *gs = pfGetGSet((pfGeode *)node, i); pfFStatsCountGSet(fstats, gs); } } /* pfGeode */ else if (pfIsOfType(node, pfGetGeodeClassType())) { pfFStatsCountNode(fstats, PFFSTATS_DB, PFFSTATS_DB_VIS, node); nGSets = pfGetNumGSets((pfGeode *)node); for (i = 0 ; i < nGSets ; i++) { pfGeoSet *gs = pfGetGSet((pfGeode *)node, i); pfFStatsCountGSet(fstats, gs); } } else pfFStatsCountNode(fstats, PFFSTATS_DB, PFFSTATS_DB_VIS, node); return PFTRAV_CONT; }

void pfuTravCountDB(pfNode *node, pfFrameStats *fstats) { pfuTraverser trav; pfFStatsClass(fstats, PFSTATS_ENGFX | PFFSTATS_ENDB, PFSTATS_ON); pfFStatsClassMode(fstats, PFSTATS_GFX, PFSTATS_GFX_GEOM | PFSTATS_GFX_TSTRIP_LENGTHS, PFSTATS_SET); pfOpenFStats(fstats, PFSTATS_ENGFX | PFFSTATS_ENDB); pfuInitTraverser(&trav); trav.preFunc = cbCountNodes; trav.data = fstats; pfuTraverse(node, &trav); pfCloseFStats(PFSTATS_ENGFX | PFFSTATS_ENDB); }

/*********************************************************************** * Traversal for highlighting all pfGeodes and pfBillboards under a node ************************************************************************/

static void fluxed_gset_hlight(void *gset, void *hl) { pfGSetHlight((pfGeoSet*)gset, (pfHighlight*)hl); }

/* callback sets on the given hlight structure in * trav->data on all the gsets under the node */ static int cbNodeHlight(pfuTraverser *trav) { pfNode *node = trav->node; pfHighlight *hl = (pfHighlight *)trav->data; int nGSets, i; static pfList *geom = NULL;

if(geom == NULL) geom = pfNewList(sizeof(pfGroup*), 1, pfGetSharedArena()); if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbNodeHlight: node null!"); else if (pfIsOfType(node, pfGetASDClassType())) { /* we only get geometry in the first channel because trav doesn't contain a channel pointer */ pfGetASDActiveGeom((pfASD *)node, NULL, geom); for(i = 0; i < pfGetNum(geom); i++) pfuTraverse((pfNode *)pfGet(geom, i), trav); } else if (pfIsOfType(node, pfGetGeodeClassType())) { nGSets = pfGetNumGSets((pfGeode *)node); for (i = 0 ; i < nGSets ; i++) { pfGeoSet *gd = pfGetGSet((pfGeode *)node, i); if (pfIsFluxed(gd)) pfFluxCallDataFunc(pfGetFlux(gd), fluxed_gset_hlight, hl); else pfGSetHlight(gd, hl); } } return PFTRAV_CONT; }

void pfuTravNodeHlight(pfNode *node, pfHighlight *hl) { pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbNodeHlight; trav.data = hl; pfuTraverse(node, &trav); }

/**************************************************** * Traversal and callback for setting an attribute * in all pfGeoSets to the have the specified binding ****************************************************/

static int cbNodeAttrBind(pfuTraverser *trav) { pfNode *node = trav->node; pfHighlight *hl = (pfHighlight *)trav->data; int nGSets, i; unsigned int attr = *((unsigned int*)trav->data); unsigned int bind = *(((unsigned int*)trav->data)+1); void *alist; unsigned short *ilist; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbNodeHlight: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType())) { nGSets = pfGetNumGSets((pfGeode *)node); for (i = 0 ; i < nGSets ; i++) { pfGeoSet *gd = pfGetGSet((pfGeode *)node, i); pfGetGSetAttrLists(gd, attr, &alist, &ilist); pfGSetAttr(gd, attr, bind, alist, ilist); } } return PFTRAV_CONT; }

void pfuTravNodeAttrBind(pfNode *node, unsigned int attr, unsigned int bind) { unsigned int data[2]; pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbNodeAttrBind; data[0] = attr; data[1] = bind; trav.data = &data; pfuTraverse(node, &trav); }

/******************************************************************* * Traversals and callbacks for using cull callbacks for re-using * cull results with static viewpoints. * WARNING: removes any existing pre or post-cull callbacks * WARNING: requires special matching cached-cull channel data ********************************************************************/

static int cbNodeCachedCullPreCull(pfTraverser *trav, void *data) { pfChannel *chan = pfGetTravChan(trav); pfuChanCullCache *chancc = (pfuChanCullCache *) pfGetChanData(chan); pfNode *n = pfGetTravNode(trav); pfuNodeCullCache *nodecc; nodecc = ((pfuNodeCullCache *) pfGetUserData(n)) + chancc->chanId; if (nodecc->updateFrame == chancc->updateFrame) { /* Cached cull result is valid */ pfCullResult(nodecc->cullResult); } return PFTRAV_CONT; }

static int cbNodeCachedCullPostCull(pfTraverser *trav, void *data) { pfChannel *chan = pfGetTravChan(trav); pfuChanCullCache *chancc = (pfuChanCullCache *) pfGetChanData(chan); pfuNodeCullCache *nodecc = ((pfuNodeCullCache *) pfGetUserData(pfGetTravNode(trav))) + chancc->chanId; if (nodecc->updateFrame != chancc->updateFrame) { /* Need to update node cull result for this channel */ nodecc->cullResult = pfGetCullResult(); nodecc->updateFrame = chancc->updateFrame; } return PFTRAV_CONT; }

static int cbInitCachedCull( pfuTraverser *trav) { pfNode *pfnThis = trav->node; int numChans = (int) trav->data; int i; pfuNodeCullCache *nodecc = pfMalloc(numChans * sizeof(pfuNodeCullCache), pfGetSharedArena()); if (nodecc) { pfNodeTravFuncs(pfnThis, PFTRAV_CULL, cbNodeCachedCullPreCull, cbNodeCachedCullPostCull); pfUserData(pfnThis, (void *) nodecc); /* Init each chan result to a stale value */ for (i = 0; i < numChans; i++) nodecc[i].updateFrame = 0; } else { pfNotify(PFNFY_FATAL, PFNFY_RESOURCE, "Couldn't allocate node data"); } return PFTRAV_CONT; }

void pfuTravCachedCull(pfNode* node, int numChans) { /* Install pre- and post- cull callbacks, node data */ pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbInitCachedCull; trav.data = (void*) numChans; pfuTraverse(node, &trav); }

/******************************************************************* * Traversals and callbacks for installing and removing pre-draw * callbacks (pfNodeFuncs) for generating GL Prof tags during drawing * WARNING: removes any existing pre or post-draw callbacks ********************************************************************/

/* * glprof pre-draw traversal callback issues glprof_object calls */ static int cbGLProf(pfTraverser *trav, void *data) { const pfNode *node = pfGetTravNode(trav); const char *nn; static char name[80]; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbGLProf: node null!"); else if (nn = pfGetNodeName(node)) { /* if it exists, use the node name for the tag */ strncpy(name, nn, 79); } else { /* otherwise, use the node type string for the tag */ strncpy(name, pfGetTypeName((pfObject *)node), 79); } glprof_object(name); return 0; }

/* * traversal callback for placing glprof callbacks as pre-draw * callbacks on nodes */ static int cbPutGLProfTag(pfuTraverser *trav) { pfNode *node = trav->node; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbPutGLProfTag: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType())) pfNodeTravFuncs(node, PFTRAV_DRAW, cbGLProf, (int (*) (pfTraverser *, void *))NULL); return PFTRAV_CONT; } /* * Traversal to remove the pre-draw glprof tag callbacks */ static int cbRmGLProfTag(pfuTraverser *trav) { pfNode *node = trav->node; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbGLProf: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType()) || pfIsExactType(node, pfGetGroupClassType())) pfNodeTravFuncs(node, PFTRAV_DRAW, (int (*) (pfTraverser *, void *))NULL, (int (*) (pfTraverser *, void *))NULL); return PFTRAV_CONT; }

/* glprof object tag traversal */ void pfuTravGLProf(pfNode *node, int mode) { pfuTraverser trav; pfuInitTraverser(&trav); pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "doing travGLProf: mode = %d", mode); if (mode) /* place gprof tag callbacks */ trav.preFunc = cbPutGLProfTag; else /* remove the callbacks */ trav.preFunc = cbRmGLProfTag; pfuTraverse(node, &trav); }

/************************************************************************ * Traversal and callback for computing the maximum depth of a subtree ***********************************************************************/

typedef struct { int depth; int maxDepth; } Depther;

/*--------------------------------------------------------------*/

static int cbPreDepth(pfuTraverser *trav) { Depther* dp = (Depther*)trav->data; dp->depth++; if (dp->depth > dp->maxDepth) dp->maxDepth = dp->depth; return PFTRAV_CONT; }

static int cbPostDepth(pfuTraverser *trav) { Depther* dp = (Depther*)trav->data; dp->depth--; return PFTRAV_CONT; }

int pfuCalcDepth(pfNode *node) { Depther dp; pfuTraverser trav; pfuInitTraverser(&trav); dp.depth = 0; dp.maxDepth = 0; trav.preFunc = cbPreDepth; trav.postFunc = cbPostDepth; trav.data = &dp; pfuTraverse(node, &trav); return dp.maxDepth; }

/************************************************************************ * Traversal and callback for computing a bounding box around pfGeoSets ***********************************************************************/

static int cbPreBbox(pfuTraverser *trav) { pfBox *box = (pfBox *)trav->data; int i; if (pfIsOfType(trav->node, pfGetASDClassType())) { pfGetASDBBox((pfASD *)trav->node, box); } else if (!pfIsOfType(trav->node, pfGetBboardClassType()) && (pfIsOfType(trav->node, pfGetGeodeClassType()))) { int ngsets, depth; pfMatrix *xform = NULL; pfGeode *geode = (pfGeode *)trav->node; depth = pfGetMStackDepth(trav->mstack); if (depth > 1) xform = pfGetMStackTop(trav->mstack); ngsets = pfGetNumGSets(geode); for (i = 0 ; i < ngsets ; i++) { pfBox gsetbox; pfGeoSet *gset = pfGetGSet(geode, i); pfGetGSetBBox(gset, &gsetbox); if (xform) pfXformBox(&gsetbox, &gsetbox, *xform); pfBoxExtendByBox(box, &gsetbox); } } else if (pfIsOfType(trav->node, pfGetBboardClassType())) { int ngsets, depth; pfMatrix *xform = NULL; pfBillboard *bboard = (pfBillboard *)trav->node; pfVec3 pos;

depth = pfGetMStackDepth(trav->mstack); if (depth > 1) xform = pfGetMStackTop(trav->mstack); ngsets = pfGetNumGSets(bboard); for (i = 0 ; i < ngsets ; i++) { pfBox gsetbox; pfGeoSet *gset = pfGetGSet(bboard, i); pfGetGSetBBox(gset, &gsetbox); gsetbox.min[1] = gsetbox.min[0]; gsetbox.max[1] = gsetbox.max[0]; pfGetBboardPos (bboard, i, pos); pfAddVec3 (gsetbox.min, gsetbox.min, pos); pfAddVec3 (gsetbox.max, gsetbox.max, pos);

if (xform) pfXformBox(&gsetbox, &gsetbox, *xform); pfBoxExtendByBox(box, &gsetbox); } }

return PFTRAV_CONT; }

void pfuTravCalcBBox(pfNode *node, pfBox *box) { pfuTraverser trav; pfuInitTraverser(&trav); pfMakeEmptyBox(box); trav.preFunc = cbPreBbox; trav.data = box; trav.mstack = pfNewMStack(32, pfGetSharedArena()); pfuTraverse(node, &trav); pfDelete(trav.mstack); }

/************************************************************************ * Traversal and callback for computing a the number of vertices in pfGeoSets ***********************************************************************/

static int cbPreNumVerts(pfuTraverser *trav) { int i; int *numVerts = (int *)trav->data; if (pfIsOfType(trav->node, pfGetGeodeClassType())) { int ngsets; pfGeode *geode = (pfGeode *)trav->node; ngsets = pfGetNumGSets(geode); for (i = 0 ; i < ngsets ; i++) { int j; pfGeoSet *gset = pfGetGSet(geode, i); int pType = pfGetGSetPrimType(gset); int numPrims = pfGetGSetNumPrims(gset); switch (pType) { case PFGS_POINTS: *numVerts += numPrims; break; case PFGS_LINES: *numVerts += 2 * numPrims; break; case PFGS_TRIS: *numVerts += 3 * numPrims; break; case PFGS_QUADS: *numVerts += 4 * numPrims; break; case PFGS_LINESTRIPS: case PFGS_TRISTRIPS: case PFGS_FLAT_LINESTRIPS: case PFGS_FLAT_TRISTRIPS: case PFGS_POLYS: case PFGS_TRIFANS: case PFGS_FLAT_TRIFANS: for (j = 0 ; j < numPrims ; j++) *numVerts += pfGetGSetPrimLength(gset, j); break; } } } return PFTRAV_CONT; }

int pfuTravCountNumVerts(pfNode *node) { int numVerts = 0; pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbPreNumVerts; trav.data = &numVerts; pfuTraverse(node, &trav); return numVerts; }

/************************************************************************ * Traversal and callback for creating vertex arrays for pfGeoSets ***********************************************************************/

#define MAX_SHORT 32767

static int calcVAStride(int mask) { int stride = 0; /* compute vertex size in shorts */ if (mask & PFU_ATTRS_COLORS) stride += 4; if (mask & PFU_ATTRS_NORMALS) stride += 8; if (mask & PFU_ATTRS_TEXCOORDS) stride += 8; if (mask & PFU_ATTRS_COORDS) stride += 12;

return stride; }

static int calcVABind(pfGeoSet *gset, int format) { int mask = 0; int cbind = pfGetGSetAttrBind(gset, PFGS_COLOR4); int nbind = pfGetGSetAttrBind(gset, PFGS_NORMAL3); int numPrims = pfGetGSetNumPrims(gset); int maxVerts, numVerts, length, i; int primType;

pfQueryGSet(gset, PFQGSET_NUM_VERTS, &numVerts); if (numVerts < 6) return 0;

primType = pfGetGSetPrimType(gset); /* we can do per-prim attributes only for stripped primitives */ if ((cbind == PFGS_PER_PRIM) || (nbind == PFGS_PER_PRIM)) { if ((primType != PFGS_TRISTRIPS) && (primType != PFGS_TRIFANS) && (primType != PFGS_LINESTRIPS) && (primType != PFGS_FLAT_LINESTRIPS) && (primType != PFGS_FLAT_TRISTRIPS)) { pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "pfuFillGSetPackedAttrs - non-stripped gset with per-prim attrs"); return 0; } } #if 1 if (nbind == PFGS_OVERALL) /* InfiniteReality bug GL Work-Around for 1st release */ { pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "pfuFillGSetPackedAttrs - skipping gset with overall normal" " for InfiniteReality bug Work-Around."); return 0; } #endif maxVerts = numVerts; switch (pfGetGSetPrimType(gset)) { case PFGS_LINESTRIPS: case PFGS_TRISTRIPS: case PFGS_POLYS: for (i=0; i < numPrims; i++) { length = pfGetGSetPrimLength(gset, i); if (length > maxVerts) maxVerts = length; } break; } if (maxVerts < 6) { return 0; } if (cbind == PFGS_PER_VERTEX) mask |= PFU_ATTRS_COLORS; if ((nbind == PFGS_PER_VERTEX) && ((format == PFGS_PA_C4UBN3ST2FV3F) || (format == PFGS_PA_C4UBN3ST2F))) mask |= PFU_ATTRS_NORMALS; if (pfGetGSetAttrBind(gset, PFGS_TEXCOORD2) == PFGS_PER_VERTEX) mask |= PFU_ATTRS_TEXCOORDS; if (format == PFGS_PA_C4UBN3ST2FV3F) mask |= PFU_ATTRS_COORDS; return mask; }

int pfuFillGSetPackedAttrs(pfGeoSet *gset, int mask) { int numPrims = pfGetGSetNumPrims(gset); int pType = pfGetGSetPrimType(gset); int *lengths = pfGetGSetPrimLengths(gset), length; int numVerts; ushort *coordsi=0, *normsi=0, *colorsi=0, *texcoordsi=0, *vai=0; pfVec3 *coords=0, *norms=0; pfVec4 *colors=0; pfVec2 *texcoords=0; char *va; int loop, flat=0, i, j; int attrStride=0;

pfQueryGSet(gset, PFQGSET_NUM_VERTS, &numVerts); if (numVerts < 6) { return 0; }

pfGetGSetAttrLists(gset, PFGS_PACKED_ATTRS, (void**)&va, &vai); if (mask & PFU_ATTRS_COLORS) pfGetGSetAttrLists(gset, PFGS_COLOR4, (void**)&colors, &colorsi); if (mask & PFU_ATTRS_NORMALS) pfGetGSetAttrLists(gset, PFGS_NORMAL3, (void**)&norms, &normsi); if (mask & PFU_ATTRS_TEXCOORDS) pfGetGSetAttrLists(gset, PFGS_TEXCOORD2, (void**)&texcoords, &texcoordsi); if (mask & PFU_ATTRS_COORDS) pfGetGSetAttrLists(gset, PFGS_COORD3, (void**)&coords, &coordsi); /* set up basic vertex loop control */ switch (pType) { case PFGS_POINTS: case PFGS_LINES: case PFGS_TRIS: case PFGS_QUADS: loop = 1; break; case PFGS_FLAT_LINESTRIPS: case PFGS_FLAT_TRISTRIPS: case PFGS_FLAT_TRIFANS: flat = 1; attrStride = calcVAStride(mask & PFU_ATTRS_CN); /* no break here - fall through for normal strip stuff */ case PFGS_LINESTRIPS: case PFGS_TRISTRIPS: case PFGS_POLYS: case PFGS_TRIFANS: loop = numPrims; numVerts = pfGetGSetPrimLength(gset, 0); break; }

for (j=1; loop--; j++) { for (i=0; i < numVerts; i++) { if (flat && (i < 2)) { va += attrStride; } else { if (mask & PFU_ATTRS_COLORS) { pfVec4 *c; if (colorsi) { c = &colors[*colorsi]; colorsi++; } else { c = colors; colors++; } *((uint*)va) = PFU_PACK_COLOR4(*c); va += 4; } if (mask & PFU_ATTRS_NORMALS) { pfVec3 *n; if (normsi) { n = &norms[*normsi]; normsi++; } else { n = norms; norms++; } ((short*)va)[0] = (short) (MAX_SHORT * ((*n)[0])); ((short*)va)[1] = (short) (MAX_SHORT * ((*n)[1])); ((short*)va)[2] = (short) (MAX_SHORT * ((*n)[2])); va += 8; } } if (mask & PFU_ATTRS_TEXCOORDS) { pfVec2 *t; if (texcoordsi) { t = &texcoords[*texcoordsi]; texcoordsi++; } else { t = texcoords; texcoords++; } ((float*)va)[0] = (*t)[0]; ((float*)va)[1] = (*t)[1]; va += 8; } if (mask & PFU_ATTRS_COORDS) { pfVec3 *v; if (coordsi) { v = &coords[*coordsi]; coordsi++; } else { v = coords; coords++; } ((float*)va)[0] = (*v)[0]; ((float*)va)[1] = (*v)[1]; ((float*)va)[2] = (*v)[2]; va += 12; } } if (loop && lengths) /* have strip primitive */ { numVerts = pfGetGSetPrimLength(gset, j); } } return 1; }

void pfuDelGSetAttrs(pfGeoSet *gset, int delMask) { void *alist, *ilist; if (delMask & PFU_ATTRS_COORDS) { pfGetGSetAttrLists(gset, PFGS_COORD3, (void**)&alist, (ushort**)&ilist); pfDelete(alist); pfDelete(ilist); pfGetGSetAttrLists(gset, PFGS_COORD3, NULL, NULL); } if (delMask & PFU_ATTRS_TEXCOORDS) { pfGetGSetAttrLists(gset, PFGS_TEXCOORD2, (void**)&alist, (ushort**)&ilist); pfDelete(alist); pfDelete(ilist); pfGetGSetAttrLists(gset, PFGS_TEXCOORD2, NULL, NULL); } if (delMask & PFU_ATTRS_NORMALS) { pfGetGSetAttrLists(gset, PFGS_NORMAL3, (void**)&alist, (ushort**)&ilist); pfDelete(alist); pfDelete(ilist); pfGetGSetAttrLists(gset, PFGS_NORMAL3, NULL, NULL); } if (delMask & PFU_ATTRS_COLORS) { pfGetGSetAttrLists(gset, PFGS_COLOR4, (void**)&alist, (ushort**)&ilist); pfDelete(alist); pfDelete(ilist); pfGetGSetAttrLists(gset, PFGS_COLOR4, NULL, NULL); } }

static int cbPreCreatePackedAttrs(pfuTraverser *trav) { int *vaData = (int*) trav->data; void *arena; char *va; int stride; int vaBind, format, delMask; int i; format = vaData[0]; delMask = vaData[1];

if (pfIsOfType(trav->node, pfGetGeodeClassType())) { int ngsets; pfGeode *geode = (pfGeode *)trav->node; ngsets = pfGetNumGSets(geode); arena = pfGetSharedArena(); for (i = 0 ; i < ngsets ; i++) { pfGeoSet *gset = pfGetGSet(geode, i); pfGeoState *gstate; int numVerts;

/* see if gset is already a vert array! */ if (pfGetGSetDrawMode(gset, PFGS_PACKED_ATTRS)) return PFTRAV_CONT; else { void *alist; ushort *ilist; pfGetGSetAttrLists(gset, PFGS_PACKED_ATTRS, &alist, &ilist); if (alist) return PFTRAV_CONT; } /* don't make vertex arrays for light-points */ gstate = pfGetGSetGState(gset); if (gstate && pfGetGStateAttr(gstate, PFSTATE_LPOINTSTATE)) { pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbPreCreatePackedAttrs - skipping light-point gset."); return PFTRAV_CONT; } /* determine vert array binding mask and vertex stride */ vaBind = calcVABind(gset, format); if (vaBind == 0) { pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbPreCreatePackedAttrs - skipping gset with problem vertex attribute binding."); return PFTRAV_CONT; } stride = calcVAStride(vaBind);

pfQueryGSet(gset, PFQGSET_NUM_VERTS, &numVerts); /* allocate an array for the packed verts */ va = (char *) pfMalloc(stride * numVerts * sizeof(char), arena); /* place array on the pfGeoSet */ pfGSetAttr(gset, PFGS_PACKED_ATTRS, format, va, NULL); /* copy vertex data into packed array */ if (pfuFillGSetPackedAttrs(gset, vaBind)) { pfGSetDrawMode(gset, PFGS_PACKED_ATTRS, 1); /* auto pfDelete attrs no longer needed */ if (delMask) pfuDelGSetAttrs(gset, delMask); } else { pfGSetAttr(gset, PFGS_PACKED_ATTRS, 0, NULL, NULL); pfDelete(va); va = NULL; } } } return PFTRAV_CONT; }

void pfuTravCreatePackedAttrs(pfNode *_node, int format, int delMask) { pfuTraverser trav; int data[2];

/* make sure this is a format we can handle */ if (format > PFGS_PA_C4UBN3ST2F) { pfNotify(PFNFY_NOTICE,PFNFY_PRINT, "pfuTravCreatePackedAttrs - sorry, format %d is not implemented.", format); return; } pfuInitTraverser(&trav); trav.preFunc = cbPreCreatePackedAttrs; data[0] = format; data[1] = delMask; trav.data = (void*) &data; pfuTraverse(_node, &trav); }

/************************************************************************ * Traversal and callback for turning quad-tmeshes into quads ***********************************************************************/

void pfuMeshToTri(pfGeoSet *gset) { int bind, prim, num, numT, *len; pfVec3 *verts, *overts, *ovp, *vp, *v0, *v1; pfVec3 *norms=NULL, *onorms, *onp, *np, *n0, *n1; pfVec4 *clrs=NULL, *oclrs, *ocp, *cp, *c0, *c1; pfVec2 *tex=NULL, *otex, *otp, *tp, *t0, *t1; ushort *index;

if (!gset) return;

/* do quick check for valid prim, lengths array and non-indexed */ prim = pfGetGSetPrimType(gset); if (!((prim == PFGS_TRISTRIPS) || (prim == PFGS_FLAT_TRISTRIPS))) return; pfGetGSetAttrLists(gset, PFGS_COORD3, (void**)&overts, &index); if (index) return; num = pfGetGSetNumPrims(gset); pfQueryGSet(gset, PFQGSET_NUM_TRIS, &numT); pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "pfuMeshToTri !!!!"); }

void pfuMeshToQuad(pfGeoSet *gset) { int bind, prim, num, numT, numQ, len; pfVec3 *verts, *overts, *ovp, *vp, *v0, *v1; pfVec3 *norms=NULL, *onorms, *onp, *np, *n0, *n1; pfVec4 *clrs=NULL, *oclrs, *ocp, *cp, *c0, *c1; pfVec2 *tex=NULL, *otex, *otp, *tp, *t0, *t1; ushort *index; int i, j;

if (!gset) return;

/* do quick check for valid prim, lengths array and non-indexed */ prim = pfGetGSetPrimType(gset); if (!((prim == PFGS_TRISTRIPS) || (prim == PFGS_FLAT_TRISTRIPS))) return; pfGetGSetAttrLists(gset, PFGS_COORD3, (void**)&overts, &index); if (index) return; num = pfGetGSetNumPrims(gset); if (num & 0x1) return; if (!pfGetGSetPrimLengths(gset)) return;

for (i=0; i < num; i++) { if (pfGetGSetPrimLength(gset, i) & 0x1) return; } pfQueryGSet(gset, PFQGSET_NUM_TRIS, &numT); numQ = (numT + 1) >> 1; pfGetGSetAttrLists(gset, PFGS_COORD3, (void**)&ovp, &index); vp = verts = pfMalloc(sizeof(pfVec3)*4*numQ, pfGetArena(gset)); bind = pfGetGSetAttrBind(gset, PFGS_NORMAL3); if (bind == PFGS_PER_VERTEX) { pfGetGSetAttrLists(gset, PFGS_NORMAL3, (void**)&onorms, &index); onp = onorms; np = norms = pfMalloc(sizeof(pfVec3)*4*numQ, pfGetArena(gset)); } bind = pfGetGSetAttrBind(gset, PFGS_COLOR4); if (bind == PFGS_PER_VERTEX) { pfGetGSetAttrLists(gset, PFGS_COLOR4, (void**)&oclrs, &index); ocp = oclrs; cp = clrs = pfMalloc(sizeof(pfVec4)*4*numQ, pfGetArena(gset)); } bind = pfGetGSetAttrBind(gset, PFGS_TEXCOORD2); if (bind == PFGS_PER_VERTEX) { pfGetGSetAttrLists(gset, PFGS_TEXCOORD2, (void**)&otex, &index); otp = otex; tp = tex = pfMalloc(sizeof(pfVec2)*4*numQ, pfGetArena(gset)); }

pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "pfuMeshToQuad !!!!"); for (i=0; i < num; i++); { int nv; nv = pfGetGSetPrimLength(gset, i); v0 = ovp; v1 = ovp + 1; ovp += 2; if (prim == PFGS_FLAT_LINESTRIPS) { if (norms) { n0 = n1 = onp; } if (clrs) { c0 = c1 = ocp; } if (tex) { t0 = t1 = otp; } } else { if (norms) { n0 = onp; n1 = onp + 1; onp += 2; } if (clrs) { c0 = ocp; c1 = ocp + 1; ocp += 2; } } if (tex) { t0 = otp; t1 = otp + 1; otp += 2; } for (j=0; j < nv; j+=2); { PFCOPY_VEC3(vp[0], *v0); PFCOPY_VEC3(vp[1], *v1); PFCOPY_VEC3(vp[2], ovp[1]); PFCOPY_VEC3(vp[3], ovp[0]); v0 = ovp; v1 = ovp + 1; ovp += 2; vp += 4; if (norms) { PFCOPY_VEC3(np[0], *n0); PFCOPY_VEC3(np[1], *n1); PFCOPY_VEC3(np[2], onp[1]); PFCOPY_VEC3(np[3], onp[0]); n0 = onp; n1 = onp+1; onp += 2; np += 4; } if (clrs) { PFCOPY_VEC4(cp[0], *c0); PFCOPY_VEC4(cp[1], *c1); PFCOPY_VEC4(cp[2], ocp[1]); PFCOPY_VEC4(cp[3], ocp[0]); c0 = ocp; c1 = ocp+1; ocp += 2; cp += 4; } if (tex) { PFCOPY_VEC2(tp[0], *t0); PFCOPY_VEC2(tp[1], *t1); PFCOPY_VEC2(tp[2], otp[1]); PFCOPY_VEC2(tp[3], otp[0]); t0 = otp; t1 = otp+1; otp += 2; tp += 4; } } } pfGSetNumPrims(gset,numQ); pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, NULL); pfDelete(overts); if (norms) { pfGSetAttr(gset, PFGS_NORMAL3, PFGS_PER_VERTEX, norms, NULL); pfDelete(onorms); } if (clrs) { pfGSetAttr(gset, PFGS_COLOR4, PFGS_PER_VERTEX, clrs, NULL); pfDelete(oclrs); } if (tex) { pfGSetAttr(gset, PFGS_TEXCOORD2, PFGS_PER_VERTEX, tex, NULL); pfDelete(otex); } }

static int cbMeshToIndep(pfuTraverser *trav) { pfNode *node = trav->node; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbMeshToQuad: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType())) { pfGeode *geode = (pfGeode *)node; int numGSets = pfGetNumGSets(geode); int prim, num, len; pfGeoSet *gset; int g, i, n;

for (g=0; g<numGSets; g++) { gset = pfGetGSet(geode, g); /* turn gsets that are all meshes of length 2 into quads */ prim = pfGetGSetPrimType(gset); num = pfGetGSetNumPrims(gset); n = pfGetGSetPrimLength(gset, 0); if ((n != 3) && (n != 4)) continue; if (prim == PFGS_TRISTRIPS || prim == PFGS_FLAT_TRISTRIPS) { for (i=1; i < num; i++) { len = pfGetGSetPrimLength(gset, i); if (len != n) { i = -1; break; } } if (i == num) { if (n == 4) pfuMeshToQuad(gset); else if (n == 3) pfuMeshToTri(gset); } } } }

return PFTRAV_CONT; }

void pfuTravMeshToIndep(pfNode *node) { pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbMeshToIndep; trav.data = 0; pfuTraverse(node, &trav); }

/************************************************************************ * Traversal and callback for setting display-list geoset status ***********************************************************************/

static int cbSetDListMode(pfuTraverser *trav) { pfNode *node = trav->node; int enable = ((int)(trav->data)); pfGeoState *gs; void *lpstate; int numVerts; if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbSetDListMode: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType())) { pfGeode *geode = (pfGeode *)node; int n = pfGetNumGSets(geode); pfGeoSet *gset; int i;

for (i=0; i<n; i++) { gset = pfGetGSet(geode, i);

if (!gset) continue;

pfQueryGSet(gset, PFQGSET_NUM_VERTS, &numVerts); if (numVerts < 6) { continue; }

/* do not compile gset with a lpstate */ gs = pfGetGSetGState(gset); if (gs) lpstate = pfGetGStateAttr(gs,PFSTATE_LPOINTSTATE); else lpstate = NULL;

if (lpstate == NULL) pfGSetDrawMode(gset, PFGS_COMPILE_GL, enable); } }

return PFTRAV_CONT; }

void pfuTravSetDListMode(pfNode *node, int enable) { pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbSetDListMode; trav.data = (void*)enable; pfuTraverse(node, &trav); }

static int cbCompileDLists(pfuTraverser *trav) { pfNode *node = trav->node; int delMask = ((int)(trav->data)); pfGeoState *gs; void *lpstate; int numVerts;

if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbSetDListMode: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType())) { pfGeode *geode = (pfGeode *)node; int n = pfGetNumGSets(geode); pfGeoSet *gset; int i;

for (i=0; i<n; i++) { gset = pfGetGSet(geode, i); if (gset) { pfQueryGSet(gset, PFQGSET_NUM_VERTS, &numVerts); if (numVerts < 6) { continue; } /* do not compile gset with a lpstate */ gs = pfGetGSetGState(gset); if (gs) lpstate = pfGetGStateAttr(gs,PFSTATE_LPOINTSTATE); else lpstate = NULL;

if (lpstate == NULL) { pfCompileGSet(gset);

/* auto pfDelete attrs no longer needed */ if (delMask) pfuDelGSetAttrs(gset, delMask); } } } }

return PFTRAV_CONT; }

void pfuTravCompileDLists(pfNode *node, int delMask) { pfuTraverser trav; pfuInitTraverser(&trav); trav.data = (void*)delMask; trav.preFunc = cbCompileDLists; pfuTraverse(node, &trav); }

static int cbDrawDLists(pfuTraverser *trav) { pfNode *node = trav->node;

if (node == NULL) pfNotify(PFNFY_DEBUG, PFNFY_PRINT, "cbSetDListMode: node null!"); else if (pfIsOfType(node, pfGetGeodeClassType())) { pfGeode *geode = (pfGeode *)node; int n = pfGetNumGSets(geode); pfGeoSet *gset; int i;

for (i=0; i<n; i++) { gset = pfGetGSet(geode, i); if (gset && (pfGetGSetDrawMode(gset, PFGS_DRAW_GLOBJ))) { pfDrawGSet(gset); } } }

return PFTRAV_CONT; }

void pfuTravDrawDLists(pfNode *node) { pfuTraverser trav; pfuInitTraverser(&trav); trav.preFunc = cbDrawDLists; pfuTraverse(node, &trav); }

/************************************************************************ * Traversal and callback for computing the least common ancestor * of all nodes in a scene for which a given function returns true. ***********************************************************************/

struct LCAinfo { int (*fun)(pfNode*,void*); /* the testing function */ void *arg; /* closure arg for the testing function */ pfNode *lca; /* output, always best approx. so far */ int possibleLCAdepth; /*depth of least common ancestor of lca with current*/ int possibleLCAIsIt; /* set when lca!=NULL and another node returns true */ };

static int cbPostLCA(pfuTraverser *trav) { struct LCAinfo *info = (struct LCAinfo *)trav->data; if (info->possibleLCAIsIt && info->possibleLCAdepth == trav->depth) { info->lca = trav->node; info->possibleLCAIsIt = 0; } if (info->lca != NULL) info->possibleLCAdepth = PF_MIN2(info->possibleLCAdepth, trav->depth-1);

return PFTRAV_CONT; }

static int cbPreLCA(pfuTraverser *trav) { struct LCAinfo *info = (struct LCAinfo *)trav->data; if (info->possibleLCAIsIt) { /* * possibleLCAIsIt is a message * sent to the post-function of one of my ancestors * from one of that ancestor's other descendents * for which fun() returned TRUE... * if that message is in the process of being sent, * then I am irrelevant. */ return PFTRAV_PRUNE; } if (info->fun(trav->node, info->arg)) { if (info->lca == NULL) info->possibleLCAdepth = trav->depth; info->possibleLCAIsIt = 1; /* pruning keeps the post callback from being called, so force it */ (void)cbPostLCA(trav); return PFTRAV_PRUNE; /* my children are irrelevant */ } return PFTRAV_CONT; }

extern pfNode * pfuLowestCommonAncestor(pfNode *scene, int (*fun)(pfNode*,void*), void *arg, int mode) { struct LCAinfo info; pfuTraverser trav;

info.fun = fun; info.arg = arg; info.lca = NULL; info.possibleLCAIsIt = 0; /* possibleLCAdepth is irrelevant until some fun(node,arg) returns true */

pfuInitTraverser(&trav); trav.mode = mode; trav.data = (void *)&info; trav.preFunc = cbPreLCA; trav.postFunc = cbPostLCA; pfuTraverse(scene, &trav); return info.lca; }

/************************************************************************ * pfuLowestCommonAncestorOfGeoSets is just like * pfuLowestCommonAncestor except that the condition * function is appied to the leaf geosets rather than nodes ***********************************************************************/

struct GeoSetFunAndArg { int (*fun)(pfGeoSet*,void*); void *arg; }; static int isGeodeContainingGSetForWhichFunReturnsTrue(pfNode *node, void *arg) { struct GeoSetFunAndArg *fun_and_arg = (struct GeoSetFunAndArg *)arg; if (pfIsOfType(node, pfGetGeodeClassType())) { pfGeode *geode = (pfGeode *)node; int nGSets = pfGetNumGSets(geode); int i; for (i = 0; i < nGSets; ++i) if (fun_and_arg->fun(pfGetGSet(geode, i), fun_and_arg->arg)) return TRUE; } return FALSE; }

extern pfNode * pfuLowestCommonAncestorOfGeoSets(pfNode *scene, int (*fun)(pfGeoSet*,void*), void *arg, int mode) { struct GeoSetFunAndArg fun_and_arg; fun_and_arg.fun = fun; fun_and_arg.arg = arg; return pfuLowestCommonAncestor(scene, isGeodeContainingGSetForWhichFunReturnsTrue, (void *)&fun_and_arg, mode); }

/************************************************************************ * pfuFindTexture finds the n'th texture in the scene * for which fun(gstate,tex,arg) returns true. * XXX textures occuring multiple times will be counted multiple times. * See the libpfsubstclip source for a more sophisticated algorithm. ***********************************************************************/

struct TexFunAndArg { int (*fun)(pfGeoState*,pfTexture*,void*); void *arg; pfTexture *tex; /* return value */ int n, i; };

static int _find_texture(pfuTraverser *trav) { struct TexFunAndArg *fun_and_arg = (struct TexFunAndArg *)trav->data; int i; if (pfIsOfType(trav->node, pfGetGeodeClassType())) { pfGeode *geode = (pfGeode *)trav->node; int nGSets = pfGetNumGSets(geode); for (i = 0; i < nGSets; ++i) { pfGeoSet *gset = pfGetGSet(geode, i); pfGeoState *gstate = pfGetGSetGState(gset); if (gstate != NULL) { pfTexture *tex = (pfTexture *) pfGetGStateAttr(gstate, PFSTATE_TEXTURE); if (tex != NULL && (fun_and_arg->fun == NULL || fun_and_arg->fun(gstate, tex, fun_and_arg->arg))) if ((fun_and_arg->n < 0) || (fun_and_arg->i == fun_and_arg->n)) { fun_and_arg->tex = tex; return PFTRAV_TERM; } else fun_and_arg->i++; } } } else if (pfIsOfType(trav->node, pfGetASDClassType())) { pfASD *asd = (pfASD *) trav->node; int numGStates; pfGeoState **gstates; pfGetASDGStates(asd, &gstates, &numGStates); for (i = 0; i < numGStates; ++i) { pfGeoState *gstate = gstates[i]; if (gstate != NULL) { pfTexture *tex = (pfTexture *) pfGetGStateAttr(gstate, PFSTATE_TEXTURE); if (tex != NULL && (fun_and_arg->fun == NULL || fun_and_arg->fun(gstate, tex, fun_and_arg->arg))) if ((fun_and_arg->n < 0) || (fun_and_arg->i == fun_and_arg->n)) { fun_and_arg->tex = tex; return PFTRAV_TERM; } else fun_and_arg->i++; } } } return PFTRAV_CONT; }

extern pfTexture * pfuFindTexture(pfNode *scene, int n, int (*fun)(pfGeoState*,pfTexture*,void*), void *arg, int mode) { pfuTraverser trav; struct TexFunAndArg fun_and_arg; fun_and_arg.fun = fun; fun_and_arg.arg = arg; fun_and_arg.tex = NULL; fun_and_arg.n = n; fun_and_arg.i = 0; pfuInitTraverser(&trav); trav.preFunc = _find_texture; trav.data = (void *)&fun_and_arg; trav.mode = mode; pfuTraverse(scene, &trav); return fun_and_arg.tex; }

/* ** Find all cliptextures in the scene graph. If the ** _promote argument is nonzero, all cliptextures found will be promoted ** to mpcliptextures and added to the _tex list. Otherwise the cliptextures ** will be returned to the list unchanged. */

typedef struct { uint promote; /* promote cliptextures to mpcliptextures */ pfList *cliptextures; } _pfuFindClipTexData;

int _pfuClipTexCallback(pfGeoState *_gstate, pfTexture *_tex, void *_data) { _pfuFindClipTexData *info = (_pfuFindClipTexData *)_data;

if(pfIsOfType(_tex, pfGetClipTextureClassType())) { /* don't do it to the same cliptexture twice */ if(pfSearch(info->cliptextures, _tex) == -1) if(info->promote) { pfMPClipTexture *mpct = pfNewMPClipTexture(); pfMPClipTextureClipTexture(mpct, (pfClipTexture *)_tex); pfAdd(info->cliptextures, mpct); } else pfAdd(info->cliptextures, _tex); } return PFTRAV_CONT; /* find all cliptextures and mpcliptextures */ }

extern void pfuFindClipTextures(pfList *_tex, pfNode *_scene, uint _promote) { _pfuFindClipTexData data;

data.cliptextures = _tex; data.promote = _promote;

pfuFindTexture(_scene, -1, _pfuClipTexCallback, (void*)&data, 0); }


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 31 1998 - 23:23:08 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.