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

File: [Development] / performer / src / lib / libpfutil / pfuClipCenterNode.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 2000, 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.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that (i) the above copyright notices and this
 * permission notice appear in all copies of the software and related
 * documentation, and (ii) the name of Silicon Graphics may not be
 * used in any advertising or publicity relating to the software
 * without the specific, prior written permission of Silicon Graphics.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
 * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
 * THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 */

//  pfuClipCenterNode.C
//
//  Clip centering node class 
// 

#include <Performer/pf.h>
#include <Performer/pr/pfLinMath.h>
#include <Performer/pf/pfTraverser.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfNode.h>
#include <Performer/pf/pfGroup.h>
#include <Performer/pf/pfMPClipTexture.h>
#include <Performer/pfutil/pfuClipCenterNode.h>

pfType *pfuClipCenterNode::classType = NULL;

// called after traversing children and after post-app func XXX 2nd part true?
static int
clipCenterPostApp(pfTraverser *trav)
{
    int travmode = PFUTRAV_SW_CUR | PFUTRAV_SEQ_CUR |
	           PFUTRAV_LOD_RANGE0 | PFUTRAV_LAYER_BOTH;

    pfVec3 eye;
    pfMatrix viewmat, travmat, invtravmat, mat;
    float x, y, z, s, t, r; /* vertex coords and tex coords of closest point */
    pfuClipCenterNode *ccn = (pfuClipCenterNode *)trav->getNode();
    pfMPClipTexture *mpcliptex = ccn->getMPClipTexture();
    pfClipTexture *cliptex = ccn->getClipTexture();
    pfNode *refnode = ccn->getRefNode();
    if(!refnode)
	refnode = ccn;
    
    //If a channel pointer is set, then only update the cliptexture center
    //if the specified channel is traversing the node
    if(ccn->getChannel() &&  ccn->getChannel() != trav->getChan())
	return PFTRAV_CONT;

    /*
     * Get the eye in the coordinate space of refnode...
     */
    eye[0] = eye[1] = eye[2] = 0;
    trav->getChan()->getViewMat(viewmat);
    trav->getMat(travmat);
    invtravmat.invertFull(travmat);
    PFCOPY_MAT(mat, viewmat);
    mat.postMult(invtravmat);
    eye.fullXformPt(eye, mat);

    if (mpcliptex && mpcliptex->getPipe() != NULL)
    {
	if (pfuGetClosestPoint(refnode,
			  eye[0], eye[1], eye[2],
			  (pfTexture *)cliptex,
			  travmode,
			  &x, &y, &z, &s, &t, &r))
	{
	    int width, height, depth, curS, curT, curR;
	    static int limit = -1;

	    cliptex->getVirtualSize(&width, &height, &depth);
#ifdef DEBUG
	pfNotify(PFNFY_DEBUG, PFNFY_PRINT,
	    "%d: MP PostApp(%s): %g %g %g -> %d %d %d\n",
	    pfGetFrameCount(),
	    pfGetTexName((pfTexture*)cliptex),
	    s, t, r, (int)(s*width), (int)(t*height), (int)(r*depth));
#endif /* DEBUG */

	    curS = (int)(s * width);
	    curT = (int)(t * height);
	    curR = (int)(r * depth);

	    if (limit != -1)
	    {
		int prevS, prevT, prevR;
	
	        mpcliptex->getCenter(&prevS, &prevT, &prevR);
		curS = PF_CLAMP(curS, prevS - limit, prevS + limit);
		curT = PF_CLAMP(curT, prevT - limit, prevT + limit);
		curR = PF_CLAMP(curR, prevR - limit, prevR + limit);
	    }
	    mpcliptex->setCenter(curS, curT, curR);
	}
    }
    else /* not attached to a pipe! */
    {
	// XXX make more specific message (handle both cases separately
	pfNotify(PFNFY_WARN, PFNFY_USAGE,
		 "pfuClipCenterNode post-app callback called,");
	pfNotify(PFNFY_WARN, PFNFY_MORE,
		 "but clip texture not defined or not attached to a pipe.");
	pfNotify(PFNFY_WARN, PFNFY_MORE,
		 "Use pfuProcessClipCenters() and pfuAddMPClipTexturesToPipes().");
    }

    return PFTRAV_CONT;
}

// C bindings

void /* static */
pfuInitClipCenterNodeClass(void)
{
    if(pfIsConfiged())
        pfNotify(PFNFY_DEBUG, PFNFY_USAGE, 
	"pfuInitClipCenterNodeClasse() should be called before pfConfig()"
	" for multiprocessed operation");
    pfuClipCenterNode::init();
}

pfType * /* static */
pfuGetClipCenterNodeClassType(void)
{
    return pfuClipCenterNode::getClassType();
}

pfuClipCenterNode *
pfuNewClipCenterNode(void)
{
    return new pfuClipCenterNode();
}

void
pfuClipCenterNodeCallback(pfuClipCenterNode *_ccn,
			  pfuClipCenterPostAppCallbackType *_fun)
{
    _ccn->setCallback(_fun);
}

pfuClipCenterPostAppCallbackType *
pfuClipCenterNodeCallback(pfuClipCenterNode *_ccn)
{
    return _ccn->getCallback();
}

void
pfuClipCenterNodeRefNode(pfuClipCenterNode *_ccn, pfNode *_node)
{
    _ccn->setRefNode(_node);
}

pfNode *
pfuGetClipCenterNodeRefNode(pfuClipCenterNode *_ccn)
{
    return _ccn->getRefNode();
}

void
pfuClipCenterNodeClipTexture(pfuClipCenterNode *_ccn, pfClipTexture *_ct)
{
    _ccn->setClipTexture(_ct);
}

pfClipTexture *
pfuGetClipCenterNodeClipTexture(pfuClipCenterNode *_ccn)
{
    return _ccn->getClipTexture();
}

void
pfuClipCenterNodeMPClipTexture(pfuClipCenterNode *_ccn,
				  pfMPClipTexture *_mpct)
{
    _ccn->setMPClipTexture(_mpct);
}

pfMPClipTexture *
pfuGetClipCenterNodeMPClipTexture(pfuClipCenterNode *_ccn)
{
    return _ccn->getMPClipTexture();
}

void
pfuClipCenterNodeChannel(pfuClipCenterNode *_ccn, pfChannel *_chan)
{
    _ccn->setChannel(_chan);
}

pfChannel *
pfuGetClipCenterNodeChannel(pfuClipCenterNode *_ccn)
{
    return _ccn->getChannel();
}


pfuClipCenterNode::pfuClipCenterNode()
{
    clipTex = NULL;
    mpClipTex = NULL;
    refNode = NULL; //default point to ourselves (== no simplfying geometry)
    callback = (pfuClipCenterPostAppCallbackType *)clipCenterPostApp;
    type = pfuClipCenterNode::getClassType();
    chan = NULL;
}

pfuClipCenterNode::~pfuClipCenterNode()
{
    if(refNode)
	pfUnrefDelete(refNode);
    if(mpClipTex)
	pfUnrefDelete(mpClipTex);
    if(clipTex)
	pfUnrefDelete(clipTex);
}

pfChannel *
pfuClipCenterNode::getChannel(void)
{
    return chan;
}

void
pfuClipCenterNode::setChannel(pfChannel *_chan)
{
    chan = _chan;
}

int
pfuClipCenterNode::needsApp(void)
{
    return 1; //this node should always be traversed
}

/* overrider pfGroup's  traverser so that we can call our post app callback */
int
pfuClipCenterNode::app(pfTraverser *trav)
{
    int state;
    state = pfGroup::app(trav);
    /* do our own post app callback */
    if (callback != NULL)
	callback(trav);

    return state;
}

void
pfuClipCenterNode::setMPClipTexture(pfMPClipTexture *_mpcliptex)
{
    if(_mpcliptex)
	pfRef(_mpcliptex); //ref first; in case re-setting the same object

    if(mpClipTex)
	pfUnrefDelete(mpClipTex);

    mpClipTex = _mpcliptex;

}

pfMPClipTexture *
pfuClipCenterNode::getMPClipTexture(void)
{
    //if it hasn't been set, and it hasn't been made before, promote
    //a cliptexture to an mpcliptexure, save and return it
    if(!mpClipTex && clipTex)
    {
	mpClipTex = new pfMPClipTexture();
	pfRef(mpClipTex);
	mpClipTex->setClipTexture(clipTex);
    }

    return mpClipTex;
}

void
pfuClipCenterNode::setClipTexture(pfClipTexture *_cliptex)
{
    if(_cliptex) //ref first in case we're re-setting the same object
	pfRef(_cliptex);

    if(clipTex)
	pfUnrefDelete(clipTex);

    clipTex = _cliptex;
}

void
pfuClipCenterNode::setRefNode(pfNode *_node)
{
    if(_node)
	pfRef(_node); //ref first in case we're re-setting the same object

    if(refNode)
	pfUnrefDelete(refNode);

    refNode = _node; 
}

void
pfuClipCenterNode::init()
{
    if(!classType)
    {
	pfGroup::init();
	classType = new pfType(pfGroup::getClassType(), "pfuClipCenterNode");
    }
}

//This is for dynamically changing callback at run time
//to create a different callback needed different args
// subclass node (see example!)
void
pfuClipCenterNode::setCallback(pfuClipCenterPostAppCallbackType *_fun)
{
    callback = _fun;
}


//*************************************************************************

//SUBCLASS EXAMPLE: pfuExampleClipCenterNode

class pfuExampleClipCenterNode : public pfuClipCenterNode
{
public:

    pfuExampleClipCenterNode();

    void setCenterDisplace(int _displaceS, int _displaceT);
    void getCenterDisplace(int *_displaceS, int *_displaceT) const;

private:

    int displaceS; // displacement from directly "below" node
    int displaceT; // displacement from directly "below" node
};


static int
exampleClipCenterPostApp(pfTraverser *trav)
{
    int dispS, dispT;
    // same stuff as clipCenterPostApp()...
    pfuExampleClipCenterNode *eccn = 
	(pfuExampleClipCenterNode *)trav->getNode();

    //If a channel pointer is set, then only update the cliptexture center
    //if the specified channel is traversing the node
    if(eccn->getChannel() &&  eccn->getChannel() != trav->getChan())
        return PFTRAV_CONT;

    eccn->getCenterDisplace(&dispS, &dispT);
    
    //use displacement to offset computed center

    return PFTRAV_CONT;
}

pfuExampleClipCenterNode::pfuExampleClipCenterNode()
{
    displaceS = 0;
    displaceT = 0;

    setCallback(exampleClipCenterPostApp);
}


void
pfuExampleClipCenterNode::setCenterDisplace(int _displaceS, int _displaceT)
{
    displaceS = _displaceS;
    displaceT = _displaceT;
}

void
pfuExampleClipCenterNode::getCenterDisplace(int *_displaceS, 
					    int *_displaceT) const
{
    if(_displaceS)
	*_displaceS = displaceS;
    if(_displaceT)
	*_displaceT = displaceT;
}

//*************************************************************************

//SUBCLASS  pfuTexGenClipCenterNode

static int
texGenClipCenterPostApp(pfTraverser *trav)
{
    pfVec3 eye;
    pfTexGen *tgen;
    pfMatrix viewmat, travmat, invtravmat, mat;
    pfuTexGenClipCenterNode *ccn = (pfuTexGenClipCenterNode *)trav->getNode();
    pfMPClipTexture *mpcliptex = ccn->getMPClipTexture();
    pfClipTexture *cliptex = ccn->getClipTexture();
    
    //If a channel pointer is set, then only update the cliptexture center
    //if the specified channel is traversing the node
    if(ccn->getChannel() &&  ccn->getChannel() != trav->getChan())
        return PFTRAV_CONT;

    tgen = ccn->getTexGen();

    if(!tgen)
    {
	pfNotify(PFNFY_WARN, PFNFY_PRINT, 
	  	"texGenClipCenter: texgen is not set");
	return PFTRAV_CONT;
    }

    /*
     * Get the eye in the coordinate space of refnode...
     */
    eye[0] = eye[1] = eye[2] = 0;
    trav->getChan()->getViewMat(viewmat);
    trav->getMat(travmat);
    invtravmat.invertFull(travmat);
    PFCOPY_MAT(mat, viewmat);
    mat.postMult(invtravmat);
    eye.fullXformPt(eye, mat);

    if (mpcliptex && mpcliptex->getPipe() != NULL)
    {
            /* get the texture matrix and normalize eye into texture space */
        {
            pfVec3          tCenter;
            pfMatrix        tMtx;

            tgen->getPlane( PF_S,
                            & tMtx[ 0 ][ PF_S ], & tMtx[ 1 ][ PF_S ],
                            & tMtx[ 2 ][ PF_S ], & tMtx[ 3 ][ PF_S ] );
            tgen->getPlane( PF_T,
                            & tMtx[ 0 ][ PF_T ], & tMtx[ 1 ][ PF_T ],
                            & tMtx[ 2 ][ PF_T ], & tMtx[ 3 ][ PF_T ] );
            tgen->getPlane( PF_R,
                            & tMtx[ 0 ][ PF_R ], & tMtx[ 1 ][ PF_R ],
                            & tMtx[ 2 ][ PF_R ], & tMtx[ 3 ][ PF_R ] );
/*	we do need Q in cliptexture --- hatch */
            tgen->getPlane( PF_Q,
                            & tMtx[ 0 ][ PF_Q ], & tMtx[ 1 ][ PF_Q ],
                            & tMtx[ 2 ][ PF_Q ], & tMtx[ 3 ][ PF_Q ] );

	    tCenter.fullXformPt(eye, tMtx);

	    tCenter[0] = PF_CLAMP(tCenter[0], 0.0, 1.0);
	    tCenter[1] = PF_CLAMP(tCenter[1], 0.0, 1.0);

            /* special case because "terrain" is always in "X-Y" plane */
            /* scale normalized texture space center into virtual space */
            {
                int depth, height, width;

                cliptex->getVirtualSize( & width, & height, & depth );
                mpcliptex->setCenter( ( int ) ( tCenter[ 0 ] * width ),
                                    ( int ) ( tCenter[ 1 ] * height ), 0 );
            }
        }
    }
    else /* not attached to a pipe! */
    {
        // XXX make more specific message (handle both cases separately
        pfNotify(PFNFY_WARN, PFNFY_USAGE,
                 "pfuTexGenClipCenterNode post-app callback called,");
        pfNotify(PFNFY_WARN, PFNFY_MORE,
                 "but clip texture not defined or not attached to a pipe.");
        pfNotify(PFNFY_WARN, PFNFY_MORE,
                 "Use pfuProcessClipCenters() and pfuAddMPClipTexturesToPipes().");
    }

    return PFTRAV_CONT;
}

pfuTexGenClipCenterNode::pfuTexGenClipCenterNode()
{
    tgen = NULL;
    setCallback(texGenClipCenterPostApp);
}


pfuTexGenClipCenterNode::~pfuTexGenClipCenterNode()
{
    if(tgen)
        pfUnrefDelete(tgen);
    #ifndef __linux__
    pfuClipCenterNode::~pfuClipCenterNode();
    #else
    pfNotify(PFNFY_WARN, PFNFY_PRINT,
	"Linux: apparently bogus destruct in [%s:%d]", __FILE__, __LINE__);
    #endif  /* __linux__ */
}

void
pfuTexGenClipCenterNode::setTexGen(pfTexGen *_tgen)
{
    tgen = _tgen;
    pfRef(tgen);
}

pfTexGen *
pfuTexGenClipCenterNode::getTexGen(void)
{
    return tgen;
}

/* the C-API wrappers */
pfuTexGenClipCenterNode *
pfuNewTexGenClipCenterNode(void)
{
    return new pfuTexGenClipCenterNode();
}

void
pfuTexGenClipCenterNodeTexGen(pfuTexGenClipCenterNode *_ccn, pfTexGen *_tgen)
{
    _ccn->setTexGen(_tgen);
}

pfTexGen *
pfuGetTexGenClipCenterNodeTexGen(pfuTexGenClipCenterNode *_ccn)
{
    return _ccn->getTexGen();
}