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

File: [Development] / performer / src / lib / libpfutil / collide.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.
 */


/* 
 * collide.c
 *
 * $Revision: 1.1 $
 * $Date: 2000/11/21 21:39:36 $
 * 
 * simple collision routines for moving DCSes
 */

#define _PFU_COLLIDE_C_		/* don't want typdefing #defs */
#include <Performer/pfutil.h>

/* Channel used for evaluating LODs when intersecting */
static pfChannel	*isectChan = NULL;

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

void
pfuCollisionChan(pfChannel *chan)
{
    isectChan = chan;
}

pfChannel*
pfuGetCollisionChan(void)
{
    return isectChan;
}

/* 
 * Set up intersection masks for collision detection using 'mask' as the 
 * intersection mask. Cache normals and such inside geosets if the geometry 
 * is static, but not if it is dynamic, i.e., its vertices change.
 */
void
pfuCollideSetup(pfNode *node, int mode, int mask)
{
    int		completeMode;
    double	startTime;
    double	elapsedTime;

    pfNotify(PFNFY_INFO, PFNFY_PRINT, "pfuCollideSetup collision traversal");

    if (mode == PFUCOLLIDE_DYNAMIC)
    {
	completeMode = PFTRAV_SELF|PFTRAV_DESCEND|PFTRAV_IS_UNCACHE;
	pfNotify(PFNFY_INFO, PFNFY_MORE, "  Intersection data is uncached");
    }
    else
    {
	completeMode = PFTRAV_SELF|PFTRAV_DESCEND|PFTRAV_IS_CACHE;
	pfNotify(PFNFY_INFO, PFNFY_MORE, "  Intersection data is cached");
    }

    startTime = pfGetTime();
    pfNodeTravMask(node, PFTRAV_ISECT, mask, completeMode, PF_OR);
    elapsedTime = pfGetTime() - startTime;

    pfNotify(PFNFY_INFO, PFNFY_MORE, "  Elapsed time: %.3f sec", elapsedTime);
    pfNotify(PFNFY_INFO, PFNFY_MORE, NULL);
}

int
pfuCollideGrnd(pfCoord *coord, pfNode *node, pfVec3 zpr)
{
    int	    isect;
    pfHit	    **hits[32];
    pfSegSet        segset;

    zpr[0] = -1.0f;
    zpr[1] = 0.0f;
    zpr[2] = 0.0f;

    /* Make a ray looking "down" at terrain */
    PFCOPY_VEC3(segset.segs[0].pos, coord->xyz);
    segset.segs[0].pos[2] += 25000.0f;	    /* Find terrain even if we're below it */
    PFSET_VEC3(segset.segs[0].dir, 0.0f, 0.0f, -1.0f);
    segset.segs[0].length = 50000.0f;

    segset.mode = PFTRAV_IS_PRIM|PFTRAV_IS_NORM|PFTRAV_IS_CULL_BACK;
    segset.userData = NULL;
    segset.isectMask = PFUCOLLIDE_GROUND;
    segset.activeMask = 0x1;
    segset.bound = NULL;
    segset.discFunc = NULL;

    if (isectChan)
	isect = pfChanNodeIsectSegs(isectChan, node, &segset, hits, NULL);
    else
	isect = pfNodeIsectSegs(node, &segset, hits);

    /* See if we collided with object. */
    if (isect > 0)
    {
	uint query[] = { PFQHIT_FLAGS, PFQHIT_POINT, PFQHIT_NORM, NULL };
	struct 
	{
	    int flags;
	    pfVec3 point;
	    pfVec3 normal;
	} result;
	pfMatrix xform;
	    
	pfMQueryHit(hits[0][0], query, &result);

	if ((result.flags & PFHIT_POINT) && (result.flags & PFHIT_NORM))
	{
	    if (result.flags & PFHIT_XFORM)
	    {
		pfQueryHit(hits[0][0], PFQHIT_XFORM, &xform);

		pfXformPt3(result.point, result.point, xform);
		pfXformVec3(result.normal, result.normal, xform);
		pfNormalizeVec3(result.normal);
	    }
	    
	    zpr[0] = result.point[PF_Z];
	    
	    {
		pfVec3  head, head90;
		float   sh, ch;
		float   dotp;
		
		pfSinCos(coord->hpr[0], &sh, &ch);
		
		head[0] = -sh;
		head[1] =  ch;
		head[2] = 0.0f;
		dotp = PFDOT_VEC3(head, result.normal);
		zpr[1]  = pfArcCos(dotp) - 90.0f;
		
		head90[0] =  ch;
		head90[1] =  sh;
		head90[2] = 0.0f;
		dotp = PFDOT_VEC3(head90, result.normal);
		zpr[2]  = 90.0f - pfArcCos(dotp);
	    }
	    return PFUCOLLIDE_GROUND;
	}
    }
    return FALSE;
}


int
pfuCollideObj(pfSeg *seg, pfNode *objNode, pfVec3 hitPos, pfVec3 hitNorm)
{
    int	    	isect;
    pfHit	**hits[32];
    pfSegSet    segset;

    segset.mode = PFTRAV_IS_PRIM|PFTRAV_IS_NORM|PFTRAV_IS_CULL_BACK;
    segset.userData = NULL;
    segset.isectMask = PFUCOLLIDE_OBJECT;
    segset.activeMask = 0x1;
    segset.bound = NULL;
    segset.discFunc = NULL;
    segset.segs[0] = *seg;

    if (isectChan)
	isect = pfChanNodeIsectSegs(isectChan, objNode, &segset, hits, NULL);
    else
	isect = pfNodeIsectSegs(objNode, &segset, hits);

    /* see if we collided with object */
    if (isect > 0)
    {
	uint query[] = { PFQHIT_FLAGS, PFQHIT_POINT, PFQHIT_NORM, NULL };
	struct 
	{
	    int flags;
	    pfVec3 point;
	    pfVec3 normal;
	} result;
	pfMatrix xform;
	    
	pfMQueryHit(hits[0][0], query, &result);

	/* transform intersection */
	if (result.flags & PFHIT_XFORM)
	{
	    /* get matrix */
	    pfQueryHit(hits[0][0], PFQHIT_XFORM, &xform);

	    /* transform point */
	    if (result.flags & PFHIT_POINT)
		pfXformPt3(result.point, result.point, xform);

	    /* transform normal */
	    if (result.flags & PFHIT_NORM)
	    {
		pfXformVec3(result.normal, result.normal, xform);
		pfNormalizeVec3(result.normal);
	    }
	}

	/* copy intersection data to user's arguments */
	if ((result.flags & PFHIT_POINT) && (hitPos  != NULL))
	    PFCOPY_VEC3(hitPos, result.point);
	if ((result.flags & PFHIT_NORM)  && (hitNorm != NULL))
	    PFCOPY_VEC3(hitNorm, result.normal);

	/* indicate that intersection occurred */
	return PFUCOLLIDE_OBJECT;
    }
    else
	return FALSE;
}

int
pfuCollideGrndObj(pfCoord *coord, pfNode *grndNode, pfVec3 zpr, 
		  pfSeg *seg, pfNode *objNode, pfVec3 hitPos, pfVec3 hitNorm)
{
    int 	    retval = 0;
    int	    isect;
    pfHit	    **hits[32];
    pfSegSet        segset;

    /* Collide separately if ground and object nodes are different */
    if (grndNode != objNode)
    {
	return pfuCollideGrnd(coord, grndNode, zpr) | 
	       pfuCollideObj(seg, objNode, hitPos, hitNorm);
    }

    /* Else, we can intersect both segments at once for better performance */
    zpr[0] = -1.0f;
    zpr[1] = 0.0f;
    zpr[2] = 0.0f;

    /* Make a ray looking "down" at terrain */
    PFCOPY_VEC3(segset.segs[0].pos, coord->xyz);
    segset.segs[0].pos[2] += 25000.0f;	    /* Find terrain even if we're below it */
    PFSET_VEC3(segset.segs[0].dir, 0.0f, 0.0f, -1.0f);
    segset.segs[0].length = 50000.0f;

    /* Copy user supplied segment */
    segset.segs[1] = *seg;

    segset.mode = PFTRAV_IS_PRIM|PFTRAV_IS_NORM|PFTRAV_IS_CULL_BACK;
    segset.userData = NULL;
    segset.isectMask = PFUCOLLIDE_GROUND;
    segset.activeMask = 0x3;
    segset.bound = NULL;
    segset.discFunc = NULL;

    if (isectChan)
	isect = pfChanNodeIsectSegs(isectChan, grndNode, &segset, hits, NULL);
    else
	isect = pfNodeIsectSegs(grndNode, &segset, hits);

    /* See if we collided with anything. */
    if (isect > 0)
    {
	uint query[] = { PFQHIT_FLAGS, PFQHIT_POINT, PFQHIT_NORM, NULL };
	struct 
	{
	    int flags;
	    pfVec3 point;
	    pfVec3 normal;
	} result;
	pfMatrix xform;
	    
	pfMQueryHit(hits[0][0], query, &result);

	if ((result.flags & PFHIT_POINT) && (result.flags & PFHIT_NORM))
	{
	    if (result.flags & PFHIT_XFORM)
	    {
		pfQueryHit(hits[0][0], PFQHIT_XFORM, &xform);

		pfXformPt3(result.point, result.point, xform);
		pfXformVec3(result.normal, result.normal, xform);
		pfNormalizeVec3(result.normal);
	    }
	    
	    zpr[0] = result.point[PF_Z];
	    
	    {
		pfVec3  head, head90;
		float   sh, ch;
		float   dotp;
		
		pfSinCos(coord->hpr[0], &sh, &ch);
		
		head[0] = -sh;
		head[1] =  ch;
		head[2] = 0.0f;
		dotp = PFDOT_VEC3(head, result.normal);
		zpr[1]  = pfArcCos(dotp) - 90.0f;
		
		head90[0] =  ch;
		head90[1] =  sh;
		head90[2] = 0.0f;
		dotp = PFDOT_VEC3(head90, result.normal);
		zpr[2]  = 90.0f - pfArcCos(dotp);
	    }
	    retval |= PFUCOLLIDE_GROUND;
	}
	    
	pfMQueryHit(hits[1][0], query, &result);

	if ((result.flags & PFHIT_POINT) && (result.flags & PFHIT_NORM))
	{
	    if (result.flags & PFHIT_XFORM)
	    {
		pfQueryHit(hits[0][0], PFQHIT_XFORM, &xform);
		pfXformPt3(result.point, result.point, xform);
		pfXformVec3(result.normal, result.normal, xform);
		pfNormalizeVec3(result.normal);
	    }
	    PFCOPY_VEC3(hitPos, result.point);
	    PFCOPY_VEC3(hitNorm, result.normal);

	    retval |= PFUCOLLIDE_OBJECT;
	}
    }
    return retval;
}