コード例 #1
0
int16_t plCullTree::IMakeHoleSubTree(const plCullPoly& poly) const
{
    if( fCapturePolys )
        IVisPoly(poly, true);

    int firstNode = fNodeList.GetCount();

    int16_t iNode = -1;

    int i;
    for( i = 0; i < poly.fVerts.GetCount()-1; i++ )
    {
        if( !poly.fClipped.IsBitSet(i) )
        {
            int16_t child = IMakePolyNode(poly, i, i+1);
            if( iNode >= 0 )
                IGetNode(iNode)->fOuterChild = child;
            iNode = child;
        }
    }
    if( !poly.fClipped.IsBitSet(i) )
    {
        int16_t child = IMakePolyNode(poly, i, 0);
        if( iNode >= 0 )
            IGetNode(iNode)->fOuterChild = child;
        iNode = child;
    }

    plCullNode* child = fNodeList.Push();
    child->Init(this, poly.fNorm, poly.fDist);
    if( iNode >= 0 )
        IGetNode(iNode)->fOuterChild = fNodeList.GetCount()-1;

    return firstNode;
}
コード例 #2
0
void plCullNode::ISetPointersRecur() const
{
    if( fInnerPtr = IGetNode(fInnerChild) )
        fInnerPtr->ISetPointersRecur();
    if( fOuterPtr = IGetNode(fOuterChild) )
        fOuterPtr->ISetPointersRecur();
}
コード例 #3
0
void plAnimCompProc::IUpdateNodeButton(HWND hWnd, IParamBlock2* pb)
{
    HWND hButton = GetDlgItem(hWnd, fNodeButtonID);

    plComponentBase* comp = IGetComp(pb);
    if (!comp)
    {
        SetWindowText(hButton, "(none)");
        EnableWindow(hButton, FALSE);
        return;
    }

    // If this is an anim grouped component you can't pick a target
    if (comp->ClassID() == ANIM_GROUP_COMP_CID)
    {
        IClearNode(pb);
        SetWindowText(hButton, "(none)");
        EnableWindow(hButton, FALSE);
        return;
    }

    EnableWindow(hButton, TRUE);

    // Make sure the node is actually in the components target list
    plMaxNode* node = IGetNode(pb);
    if (comp->IsTarget((plMaxNodeBase*)node))
        SetWindowText(hButton, node->GetName());
    else
        SetWindowText(hButton, "(none)");
}
コード例 #4
0
void plCullTree::AddPoly(const plCullPoly& poly)
{
    const plCullPoly* usePoly = &poly;

    hsVector3 cenToEye(&fViewPos, &poly.fCenter);
    hsFastMath::NormalizeAppr(cenToEye);
    float camDist = cenToEye.InnerProduct(poly.fNorm);
    plConst(float) kTol(0.1f);
    hsBool backFace = camDist < -kTol;
    if( !backFace && (camDist < kTol) )
        return;

    plCullPoly scratchPoly;
    if( poly.IsHole() )
    {
        if( !backFace )
            return;
    }
    else
    if( backFace )
    {
        plConst(hsBool) kAllowTwoSided(true);
        if( !kAllowTwoSided || !poly.IsTwoSided() )
            return;

        scratchPoly.Flip(poly);
        usePoly = &scratchPoly;
    }

    if( !SphereVisible(usePoly->GetCenter(), usePoly->GetRadius()) )
        return;

    usePoly->fClipped.Clear();

    usePoly->Validate();

    // Make sure we have enough scratch polys. Each node
    // can potentially split this poly, so...
    ISetupScratch(fNodeList.GetCount());

#if 1
    if( IGetRoot() && IGetNode(IGetRoot()->fOuterChild) )
    {
        IAddPolyRecur(*usePoly, IGetRoot()->fOuterChild);
    }
    else
#endif
    {
        fRoot = IAddPolyRecur(*usePoly, fRoot);
    }

#ifdef DEBUG_POINTERS
    if( IGetRoot() )
        IGetRoot()->ISetPointersRecur();
#endif // DEBUG_POINTERS
}
コード例 #5
0
bool plAnimCompProc::GetCompAndNode(IParamBlock2* pb, plComponentBase*& comp, plMaxNode*& node)
{
    comp = IGetComp(pb);
    if (comp)
    {
        node = IGetNode(pb);

        // If it's an anim group component (don't need a node), or we have a node
        // and the component is attached to it, we're ok.
        if (comp->ClassID() == ANIM_GROUP_COMP_CID ||
            (node && comp->IsTarget((plMaxNodeBase*)node)))
            return true;
    }

    return false;
}
コード例 #6
0
//////////////////////////////////////////////////////////////////////
// Harvest culling section.
// These are the functions used on a built tree
//////////////////////////////////////////////////////////////////////
plCullNode::plCullStatus plCullNode::ITestBoundsRecur(const hsBounds3Ext& bnd) const
{
    plCullNode::plCullStatus retVal = TestBounds(bnd);

    // No Children, what we say goes.
    if( (fOuterChild < 0) && (fInnerChild < 0) )
        return retVal;

    // No innerchild. If we cull, it's culled, else we
    // hope our outerchild culls it.
    if( fInnerChild < 0 )
    {
        if( retVal == kCulled )
            return kCulled;

        return IGetNode(fOuterChild)->ITestBoundsRecur(bnd);
    }

    // No outerchild. If we say it's clear, it's clear (or split), but if
    // it's culled, we have to pass it to innerchild, who may pronounce it clear
    if( fOuterChild < 0 )
    {
        if( retVal == kClear )
            return kClear;
        if( retVal == kSplit )
            return kSplit;
        return IGetNode(fInnerChild)->ITestBoundsRecur(bnd);
    }

    // We've got both children to feed.
    // We pass the clear ones to the inner child, culled to outer, 
    // and split to both. Remember, a both children have to agree to cull a split.
    if( retVal == kClear )
        return IGetNode(fOuterChild)->ITestBoundsRecur(bnd);

    if( retVal == kCulled )
        return IGetNode(fInnerChild)->ITestBoundsRecur(bnd);

    // Here's the split, to be culled, both children have to
    // say its culled.
    if( kCulled != IGetNode(fOuterChild)->ITestBoundsRecur(bnd) )
        return kSplit;

    if( kCulled != IGetNode(fInnerChild)->ITestBoundsRecur(bnd) )
        return kSplit;

    return kCulled;
}
コード例 #7
0
int16_t plCullTree::IAddPolyRecur(const plCullPoly& poly, int16_t iNode)
{
    if( poly.fVerts.GetCount() < 3 )
        return iNode;

    if( iNode < 0 )
        return IMakePolySubTree(poly);

    hsBool addInner = (IGetNode(iNode)->fInnerChild >= 0)
                        || ((iNode > 5) && poly.IsHole());
    hsBool addOuter = !poly.IsHole() || (IGetNode(iNode)->fOuterChild >= 0);

    plCullPoly* innerPoly = nil;
    plCullPoly* outerPoly = nil;

    plCullNode::plCullStatus test = IGetNode(iNode)->ISplitPoly(poly, innerPoly, outerPoly);

    switch( test )
    {
    case plCullNode::kClear:
        if( addOuter )
        {
            int child = IAddPolyRecur(poly, IGetNode(iNode)->fOuterChild);
            IGetNode(iNode)->fOuterChild = child;
        }
        break;
    case plCullNode::kCulled:
        if( addInner )
        {
            int child = IAddPolyRecur(poly, IGetNode(iNode)->fInnerChild);
            IGetNode(iNode)->fInnerChild = child;
        }
        break;
    case plCullNode::kSplit:
        hsAssert(innerPoly && outerPoly, "Poly should have been split into inner and outer in SplitPoly");
        if( addOuter )
        {
            int child = IAddPolyRecur(*outerPoly, IGetNode(iNode)->fOuterChild);
            IGetNode(iNode)->fOuterChild = child;
        }
        if( addInner )
        {
            int child = IAddPolyRecur(*innerPoly, IGetNode(iNode)->fInnerChild);
            IGetNode(iNode)->fInnerChild = child;
        }
        break;
    }
    return iNode;
}
コード例 #8
0
// Cycle through the Cull Nodes, paring down the list of who to test (through ITestNode above).
// We reclaim the scratch indices in clear and split when we're done (SetCount(0)), but we can't
// reclaim the culled, because our caller may be looking at who all we culled. See below in split.
// If a node is disabled, we can just ignore we ever got called.
void plCullNode::ITestNode(const plSpaceTree* space, int16_t who, hsBitVector& totList, hsBitVector& outList) const
{
    if( space->IsDisabled(who) )
        return;

    uint32_t myClearStart = ScratchClear().GetCount();
    uint32_t mySplitStart = ScratchSplit().GetCount();
    uint32_t myCullStart = ScratchCulled().GetCount();

    if( kPureSplit == ITestNode(space, who, ScratchClear(), ScratchSplit(), ScratchCulled()) )
        ScratchSplit().Append(who);

    uint32_t myClearEnd = ScratchClear().GetCount();
    uint32_t mySplitEnd = ScratchSplit().GetCount();
    uint32_t myCullEnd = ScratchCulled().GetCount();

    int i;
    // If there's no OuterChild, everything in clear and split is visible. Everything in culled
    // goes to innerchild (if any).
    if( fOuterChild < 0 )
    {
        plProfile_IncCount(HarvestNodes, myClearEnd - myClearStart + mySplitEnd - mySplitStart);
        // Replace these with a memcopy or something!!!!
        for( i = myClearStart; i < myClearEnd; i++ )
        {
            space->HarvestLeaves(ScratchClear()[i], totList, outList);
        }
        for( i = mySplitStart; i < mySplitEnd; i++ )
        {
            space->HarvestLeaves(ScratchSplit()[i], totList, outList);
        }

        if( fInnerChild >= 0 )
        {
            for( i = myCullStart; i < myCullEnd; i++ )
            {
                IGetNode(fInnerChild)->ITestNode(space, ScratchCulled()[i], totList, outList);
            }
        }
        ScratchClear().SetCount(myClearStart);
        ScratchSplit().SetCount(mySplitStart);
        ScratchCulled().SetCount(myCullStart);

        return;
    }

    // There is an OuterChild, so whether there's an InnerChild or not,
    // everything in ClearList is visible soley on the discretion of OuterChild.
    for( i = myClearStart; i < myClearEnd; i++ )
    {
        IGetNode(fOuterChild)->ITestNode(space, ScratchClear()[i], totList, outList);
    }

    // If there's no InnerChild, then the SplitList is also visible soley
    // on the discretion of OuterChild.
    if( fInnerChild < 0 )
    {
        for( i = mySplitStart; i < mySplitEnd; i++ )
        {
            IGetNode(fOuterChild)->ITestNode(space, ScratchSplit()[i], totList, outList);
        }

        ScratchClear().SetCount(myClearStart);
        ScratchSplit().SetCount(mySplitStart);
        ScratchCulled().SetCount(myCullStart);

        return;
    }

    // There is an inner child. Everything in culled list is visible
    // soley on its discretion.
    for( i = myCullStart; i < myCullEnd; i++ )
    {
        IGetNode(fInnerChild)->ITestNode(space, ScratchCulled()[i], totList, outList);
    }

    // Okay, here's the rub.
    // Everyone in the split list needs to be tested against InnerChild and OuterChild.
    // If either child says it's okay (puts it in OutList), then it's okay.
    // The problem is that if both children say it's okay, it will wind up in outList twice.
    // This is complicated by the fact that outList is still subTrees at this point,
    // so InnerChild adding a subTree and OuterChild adding a child of that subTree isn't
    // even appending the same value to the list.
    // Sooooo.
    // What we do is keep track of every node (interior and leaf) that gets harvested.
    // When we go to harvest a subtree, we check in totList for its bit being set. Bits
    // set in totList are ENTIRE SUBTREE IS HARVESTED. SpaceTree understands this too in
    // its HarvestLeaves. Seems obvious now, but I didn't hear you suggest it.

    for( i = mySplitStart; i < mySplitEnd; i++ )
    {
        IGetNode(fOuterChild)->ITestNode(space, ScratchSplit()[i], totList, outList);
    }

    for( i = mySplitStart; i < mySplitEnd; i++ )
    {
        if( !totList.IsBitSet(ScratchSplit()[i]) )
            IGetNode(fInnerChild)->ITestNode(space, ScratchSplit()[i], totList, outList);
    }

    ScratchClear().SetCount(myClearStart);
    ScratchSplit().SetCount(mySplitStart);
    ScratchCulled().SetCount(myCullStart);
}