void OcclusionCullingTreeBuilder::drawNode(OCRenderTreeNode   *pNode,
                                           DrawEnv             &denv,
                                           RenderPartitionBase *part)
{
    leaveTesting(denv, part);

    UInt32 uiNextMatrix = pNode->getMatrixStore().first;

    if(uiNextMatrix != 0 && uiNextMatrix != _uiActiveMatrix)
    {
        glLoadMatrixf(pNode->getMatrixStore().second.getValues());

        _uiActiveMatrix = uiNextMatrix;

        _currMatrix.second = pNode->getMatrixStore().second;

        updateTopMatrix(denv);

        denv.setObjectToWorld(_accMatrix);

        ++part->_uiNumMatrixChanges;
    }

    //STATE ACTIVATION
    State         *pNewState         = pNode->getState();
    StateOverride *pNewStateOverride = pNode->getStateOverride();

    denv.setLightState(pNode->getLightState());

    denv.activateState(pNewState, pNewStateOverride);

    pNode->setIsRendered(true);

    if(_ract->getOcclusionCullingDebug() && pNode->getNode())
    {
        pNode->getNode()->setTravMask(
            pNode->getNode()->getTravMask() |
            _ract->getOcclusionVisibleDebugMask()
            );
    }

    //DRAW DRAW DRAW

    if(pNode->hasFunctor() == true)
    {
        if(part->_bCorrectNegScale)
        {
            const Matrix &m = _currMatrix.second;

            // test for a "flipped" matrix
            // glFrontFace can give conflicts with the polygon chunk ...

            if(m[0].cross(m[1]).dot(m[2]) < 0.0)
            {
                glFrontFace(GL_CW);
            }
            else
            {
                glFrontFace(GL_CCW);
            }
        }

        //BoxVolume volume = pNode->getVol();
        //drawVolume(volume);
        pNode->getFunctor()(&denv);
    }
}
void OcclusionCullingTreeBuilder::testNode(OCRenderTreeNode   *pNode,
                                           DrawEnv             &denv,
                                           RenderPartitionBase *part,
                                           Real32              &scr_percent)
{
    while (pNode != NULL)
    {
    //MATRIX SETUP
        UInt32 uiNextMatrix = pNode->getMatrixStore().first;

        if(uiNextMatrix != 0 && uiNextMatrix != _uiActiveMatrix)
        {
            glLoadMatrixf(pNode->getMatrixStore().second.getValues());

            _uiActiveMatrix = uiNextMatrix;

            _currMatrix.second = pNode->getMatrixStore().second;

            updateTopMatrix(denv);

            denv.setObjectToWorld(_accMatrix);

            ++part->_uiNumMatrixChanges;
        }

        const BoxVolume &volume = pNode->getVolume();
        Pnt3f min,max;

        volume.getBounds(min, max);
        Pnt3f p[8];
        p[0].setValues(min[0],min[1],min[2]);
        p[1].setValues(max[0],min[1],min[2]);
        p[2].setValues(min[0],max[1],min[2]);
        p[3].setValues(min[0],min[1],max[2]);
        p[4].setValues(max[0],max[1],min[2]);
        p[5].setValues(max[0],min[1],max[2]);
        p[6].setValues(min[0],max[1],max[2]);
        p[7].setValues(max[0],max[1],max[2]);

        //std::cout << "OtoW:" << std::endl;
        //std::cout << denv.getObjectToWorld() << std::endl;
        //std::cout << "WtoC:" << std::endl;
        //std::cout << worldToCam << std::endl;
        for(UInt32 i = 0; i<8;i++)
        {
           // std::cout << p[i] << "=>";
            denv.getObjectToWorld().mult    (p[i], p[i]);
            _worldToScreen         .multFull(p[i], p[i]);
            //std::cout << p[i] << "  ";
        }
        min=p[0];
        max=p[0];
        for(UInt32 i = 0; i<8; i++)
        {
           for(UInt32 j=0; j<2; j++)
           {
              if(p[i][j] < min[j])
              {
                min[j] = p[i][j];
              }
              if(p[i][j] > max[j])
              {
                max[j] = p[i][j];
              }
           }
        }
        max[0] = osgClamp(-1.f, max[0], 1.f);
        max[1] = osgClamp(-1.f, max[1], 1.f);
        min[0] = osgClamp(-1.f, min[0], 1.f);
        min[1] = osgClamp(-1.f, min[1], 1.f);

        // cbb is the percent of the screen real estate this would cover
        Real32 cbb = (max[0] - min[0]) * (max[1] - min[1]) / 4.f;

        //std::cout << cur_node << ":" << pix << " ";
        //std::cout << pNode->getScalar() << std::endl;

//Make decision

        if(pNode->hasFunctor() == false) //Nothing to do
        {
            //renderNode
            drawNode(pNode, denv, part);
        }
        else
        {
            //make decision
            //if(0 > 1)
            if(cbb > scr_percent) // Rendering major occluders
            {
                drawNode(pNode, denv, part);
                //scr_percent+=cbb;
            }
            else
            {

                Real32 pcov;
                pcov = sqrt(scr_percent) - sqrt(cbb);
                pcov *= pcov;
                //std::cout << "cbb:" << cbb << " scr_percent:" << scr_percent <<" pcov:" << pcov << std::endl;
                //if(scr_percent - pcov > 0.001)
                if(pcov > _coveredProbThreshold || cbb < 0.001) // If within threshold or reall small
                {
                    //Get triangles
                    DrawableStatsAttachment *st =
                        DrawableStatsAttachment::get(pNode->getNode()->getCore());
                    st->validate();
                    UInt32 triangles = st->getTriangles();

                    if(cbb * _vpWidth * _vpHeight < _minFeatureSize) //small feature culling
                    {
                        StatCollector *sc = _ract->getStatCollector();
                        if(sc != NULL)
                            sc->getElem(statNOccTriangles)->
                                add(triangles);
                        if(_ract->getOcclusionCullingDebug() && pNode->getNode())
                        {
                            pNode->getNode()->setTravMask(
                                pNode->getNode()->getTravMask() |
                                _ract->getOcclusionCulledDebugMask()
                                );
                        }
                        pNode->setIsRendered(true);
                    }
                    else if( triangles <= _minTriangleCount )
                    {
                        drawNode(pNode, denv, part);
                    }
                    else if((_testPendingNodes.size() == _numTestSamples - 1)) // Make sure we have room to draw a test
                    {
                        drawTestResults(denv, part);
                        if(_testPendingNodes.size() == _numTestSamples - 1) // If we are waiting on a result, draw a node
                        {
                            drawNode(pNode, denv, part);
                        }
                        else
                        {
                            drawTestNode(pNode, denv, part); // Made room, go ahead and draw a test node
                        }
                    }
                    else
                    {
                        drawTestNode(pNode, denv, part); //Plenty of room in buffer to draw a test node
                    }
                }
                else
                {
                    drawNode(pNode, denv, part); // Probably not being covered up...draw the real node
                    //scr_percent+=cbb;
                }
            }
            scr_percent += ((1.0 - scr_percent) * cbb);
        }

//DRAW CHILDREN OR GO TO TOP AND DO IT AGAIN
        if(pNode->getFirstChild() != NULL)
        {
            OCRenderTreeNode *child =
                static_cast<OCRenderTreeNode *>(pNode->getFirstChild());

            testNode(child, denv, part, scr_percent);
        }

        pNode = static_cast<OCRenderTreeNode *>(pNode->getBrother());
    }
}