[BACK]Return to boxlod.c CVS log [TXT][DIR] Up to [Development] / performer / src / lib / libpfutil

File: [Development] / performer / src / lib / libpfutil / boxlod.c (download)

Revision 1.1, Tue Nov 21 21:39:36 2000 UTC (16 years, 10 months ago) by flynnt
Branch: MAIN
CVS Tags: HEAD

Initial check-in based on OpenGL Performer 2.4 tree.
-flynnt

/*
 * 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.
 */

/*
 * boxlod.c 
 *
 * $Revision: 1.1 $ 
 * $Date: 2000/11/21 21:39:36 $
 */

#include <math.h>
#include <stdlib.h>

#ifdef	_POSIX_SOURCE
extern double drand48 (void);
#endif

#include <Performer/pfutil.h>

/*
 * Input: pfBox, color, flag indicating whether boxes
 *	  should be flat shaded or blob like (gouraud 
 *	  with vertex average normals).
 *
 * Output: A pfGeoSet depicting the box
 */
pfGeoSet*
pfuMakeBoxGSet(pfBox *box, pfVec4 clr, int flat)
{
    int *primLengths;
    pfVec4 *clrs;
    pfVec3 *verts, *norms;
    pfGeoSet *gset = pfNewGSet(pfGetSharedArena());

    pfGSetNumPrims(gset, 3);
    primLengths = (int *)pfMalloc(sizeof(int)*3, pfGetSharedArena());
    primLengths[0] = 10;
    primLengths[1] = 4;
    primLengths[2] = 4;
    pfGSetPrimLengths(gset, primLengths);

    if (flat)
	pfGSetPrimType(gset, PFGS_FLAT_TRISTRIPS);
    else
	pfGSetPrimType(gset, PFGS_TRISTRIPS);

    clrs = (pfVec4 *)pfMalloc(sizeof(pfVec4), pfGetSharedArena());
    pfGSetAttr(gset, PFGS_COLOR4, PFGS_OVERALL, clrs, NULL);
    pfCopyVec4(clrs[0], clr);

    verts = (pfVec3 *)pfMalloc(18*sizeof(pfVec3), pfGetSharedArena());
    pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, NULL);
    /* strip around */
    pfSetVec3(verts[0], box->min[0], box->min[1], box->min[2]);
    pfSetVec3(verts[1], box->max[0], box->min[1], box->min[2]);
    pfSetVec3(verts[2], box->min[0], box->min[1], box->max[2]);
    pfSetVec3(verts[3], box->max[0], box->min[1], box->max[2]);
    pfSetVec3(verts[4], box->min[0], box->max[1], box->max[2]);
    pfSetVec3(verts[5], box->max[0], box->max[1], box->max[2]);
    pfSetVec3(verts[6], box->min[0], box->max[1], box->min[2]);
    pfSetVec3(verts[7], box->max[0], box->max[1], box->min[2]);
    pfSetVec3(verts[8], box->min[0], box->min[1], box->min[2]);
    pfSetVec3(verts[9], box->max[0], box->min[1], box->min[2]);
    /* min x end */
    pfSetVec3(verts[10], box->min[0], box->max[1], box->min[2]);
    pfSetVec3(verts[11], box->min[0], box->min[1], box->min[2]);
    pfSetVec3(verts[12], box->min[0], box->max[1], box->max[2]);
    pfSetVec3(verts[13], box->min[0], box->min[1], box->max[2]);
    /* max x end */
    pfSetVec3(verts[14], box->max[0], box->min[1], box->min[2]);
    pfSetVec3(verts[15], box->max[0], box->max[1], box->min[2]);
    pfSetVec3(verts[16], box->max[0], box->min[1], box->max[2]);
    pfSetVec3(verts[17], box->max[0], box->max[1], box->max[2]);

    norms = (pfVec3 *)pfMalloc(18*sizeof(pfVec3), pfGetSharedArena());
    pfGSetAttr(gset, PFGS_NORMAL3, PFGS_PER_VERTEX, norms, NULL);
    if (flat)
    {
	pfSetVec3(norms[0],  0.0f, -1.0f,  0.0f);
	pfSetVec3(norms[1],  0.0f, -1.0f,  0.0f);
	pfSetVec3(norms[2],  0.0f,  0.0f,  1.0f);
	pfSetVec3(norms[3],  0.0f,  0.0f,  1.0f);
	pfSetVec3(norms[4],  0.0f,  1.0f,  0.0f);
	pfSetVec3(norms[5],  0.0f,  1.0f,  0.0f);
	pfSetVec3(norms[6],  0.0f,  0.0f, -1.0f);
	pfSetVec3(norms[7],  0.0f,  0.0f, -1.0f);
	/* min x end */
	pfSetVec3(norms[8], -1.0f, 0.0f,  0.0f);
	pfSetVec3(norms[9], -1.0f, 0.0f,  0.0f);
	/* max x end */
	pfSetVec3(norms[10],  1.0f, 0.0f,  0.0f);
	pfSetVec3(norms[11],  1.0f, 0.0f,  0.0f);
    }
    else
    {
	int i;

	pfSetVec3(norms[0], -1.0f, -1.0f, -1.0f);
	pfSetVec3(norms[1],  1.0f, -1.0f, -1.0f);
	pfSetVec3(norms[2], -1.0f, -1.0f,  1.0f);
	pfSetVec3(norms[3],  1.0f, -1.0f,  1.0f);
	pfSetVec3(norms[4], -1.0f,  1.0f,  1.0f);
	pfSetVec3(norms[5],  1.0f,  1.0f,  1.0f);
	pfSetVec3(norms[6], -1.0f,  1.0f, -1.0f);
	pfSetVec3(norms[7],  1.0f,  1.0f, -1.0f);
	pfSetVec3(norms[8], -1.0f, -1.0f, -1.0f);
	pfSetVec3(norms[9],  1.0f, -1.0f, -1.0f);
	/* min x end */
	pfSetVec3(norms[10], -1.0f, 1.0f, -1.0f);
	pfSetVec3(norms[11], -1.0f,-1.0f, -1.0f);
	pfSetVec3(norms[12], -1.0f, 1.0f,  1.0f);
	pfSetVec3(norms[13], -1.0f,-1.0f,  1.0f);
	/* max x end */
	pfSetVec3(norms[14],  1.0f,-1.0f, -1.0f);
	pfSetVec3(norms[15],  1.0f, 1.0f, -1.0f);
	pfSetVec3(norms[16],  1.0f,-1.0f,  1.0f);
	pfSetVec3(norms[17],  1.0f, 1.0f,  1.0f);

	for (i = 0 ; i < 18 ; i++)
	    pfNormalizeVec3(norms[i]);
    }
    return gset;
}

/*
 * Input: A subgraph and a depth
 * 
 * Output: 
 *        A new graph with all subgraphs below the specified
 *	  depth replaced by geodes with geometry representing
 *	  the corresponding bounding box.
 */

typedef struct 
{
    int targCount;
    int flat;
    pfVec4 *clr;
} Cloner;


static int
cbPreBoxClone(pfuTraverser *trav)
{
    Cloner *cl = (Cloner *)trav->data;
    pfNode *node = trav->node;
    pfBox box;
    int nChild, i;
    pfGeode *newGeode = NULL;

    if (!pfIsOfType(node, pfGetGroupClassType()))
	return PFTRAV_PRUNE;

    nChild = pfGetNumChildren(node);

    /* 
     * check if number of vertices under any children
     * is less than target, if so replace with bbox - SLOW
     */

    for (i = 0 ; i < nChild ; i++)
    {
	int numVerts;
	pfNode *child = pfGetChild(node, i);
	numVerts = pfuTravCountNumVerts(child);

	if (numVerts <= cl->targCount && numVerts > 18)
	{
	    pfGeoSet *boxGSet;
	    pfVec4 clr;

	    if (cl->clr == NULL)
		pfSetVec4(clr, drand48(), drand48(), drand48(), 1.0f);
	    else
		pfCopyVec4(clr, *(cl->clr));
	    pfuTravCalcBBox(child, &box);
	    boxGSet = pfuMakeBoxGSet(&box, clr, cl->flat);
	    if (newGeode == NULL)
		newGeode = pfNewGeode();
	    pfAddGSet(newGeode, boxGSet);
	    pfRemoveChild(node, child);
	    i--;
	    nChild--;
	}
    }
    if (newGeode)
	pfAddChild(node, newGeode);
    return PFTRAV_CONT;
}

pfNode* 
pfuBoxClone(pfNode *node, int targCount, int flat, pfVec4 *clrp)
{
    Cloner cl;
    pfuTraverser trav;
    pfNode *newGraph;
    int numVerts;

    pfuInitTraverser(&trav);

    cl.targCount = targCount;
    cl.flat = flat;
    cl.clr = clrp;

    numVerts = pfuTravCountNumVerts(node);

    if (numVerts <= targCount && numVerts > 18)
    {
	pfBox box;
	pfVec4 clr;
	pfGeoSet *boxGSet;
	pfGeode *geode;
	pfuTravCalcBBox(node, &box);
	if (clrp == NULL)
	    pfSetVec4(clr, drand48(), drand48(), drand48(), 1.0f);
	else
	    PFCOPY_VEC4(clr, *clrp);
	    
	boxGSet = pfuMakeBoxGSet(&box, clr, flat);
	geode = pfNewGeode();
	pfAddGSet(geode, boxGSet);
	return (pfNode *)geode;
    }

    newGraph = pfClone(node, 0);

    trav.preFunc = cbPreBoxClone;
    trav.data = &cl;

    pfuTraverse(newGraph, &trav);

    return newGraph;
}

/*
 * Input: A subgraph
 * 
 * Output: 
 *        An LOD which draws low-LOD geometry as bounding boxes
 */

pfLOD*
pfuBoxLOD(pfGroup *grp, int flat, pfVec4 *clr)
{
    pfLOD *lod;
    int numVerts;
    pfBox box;
    pfVec3 center;
    float size;
    int i;
    int lastVerts;
    int il = 0;

    pfuTravCalcBBox((pfNode *)grp, &box);
    size = 2 * PFDISTANCE_PT3(box.min, box.max);
    pfCombineVec3(center, 0.5f, box.min, 0.5f, box.max);

    lod = pfNewLOD();
    pfLODCenter(lod, center);

    numVerts = lastVerts = pfuTravCountNumVerts((pfNode *)grp);
    pfAddChild(lod, grp);
    pfLODRange(lod, il, size*il);
    il++;

    /*
     * try for a factor of two each time 36 is 2X the 
     * number of vertices in a tstripped box 
     */
    for (i = 36 ; i < 2 * numVerts ; i *= 2)
    {
	pfNode *boxy = pfuBoxClone((pfNode *)grp, i, flat, clr);
	if (boxy)
	{
	    int newVerts = pfuTravCountNumVerts(boxy);
	    if (newVerts < lastVerts)
	    {
		pfAddChild(lod, boxy);
		pfLODRange(lod, il, size*il);
		il++;
	    }
	    else
	    {
		pfNotify(PFNFY_NOTICE, PFNFY_PRINT, 
			 "BoxLOD throwing away LOD with %d vertices, higher than previous with %d", 
			 newVerts, lastVerts);
		pfDelete(boxy);
	    }
	}
    }
    pfLODRange(lod, il, size*il);
    return lod;
}