#include "gpuCacheShapeNode.h"
#include "gpuCacheStrings.h"
#include "gpuCacheConfig.h"
#include "gpuCacheRasterSelect.h"
#include "gpuCacheGLPickingSelect.h"
#include "gpuCacheUtil.h"
#include "gpuCacheSubSceneOverride.h"
#include "gpuCacheDrawTraversal.h"
#include "gpuCacheGLFT.h"
#include "gpuCacheUtil.h"
#include <maya/M3dView.h>
#include <maya/MAnimControl.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MDrawData.h>
#include <maya/MFileIO.h>
#include <maya/MFileObject.h>
#include <maya/MFnDagNode.h>
#include <maya/MMaterial.h>
#include <maya/MMatrix.h>
#include <maya/MSelectionList.h>
#include <maya/MSelectionMask.h>
#include <maya/MHWGeometryUtilities.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MGlobal.h>
#include <maya/MHardwareRenderer.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MDagPathArray.h>
#include <maya/MDGMessage.h>
#include <maya/MEventMessage.h>
#include <maya/MModelMessage.h>
#include <maya/MUiMessage.h>
#include <maya/MItDag.h>
#include <maya/MFnCamera.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MFnPluginData.h>
#include <maya/MMaterialArray.h>
#include <maya/MObjectArray.h>
#include <maya/MAttributeSpec.h>
#include <maya/MAttributeSpecArray.h>
#include <maya/MAttributeIndex.h>
#include <maya/MPxSurfaceShapeUI.h>
#include <maya/MPointArray.h>
#include <maya/MVectorArray.h>
#include <maya/MExternalContentInfoTable.h>
#include <maya/MExternalContentLocationTable.h>
#include <cassert>
#include <climits>
#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>
#define MCHECKERROR(STAT,MSG)                   \
    if (!STAT) {                                \
        perror(MSG);                            \
        return MS::kFailure;                    \
    }
#define MREPORTERROR(STAT,MSG)                  \
    if (!STAT) {                                \
        perror(MSG);                            \
    }
#define MCHECKERRORVOID(STAT,MSG)               \
    if (!STAT) {                                \
        perror(MSG);                            \
        return;                                 \
    }
namespace {
using namespace GPUCache;
using namespace GPUCache::ShapeNodePrivate;
    
    
    
    class DrawWireframeState : public DrawTraversalState
    {
    public:
        DrawWireframeState(
            const Frustum&  frustrum,
            const double    seconds)
            : DrawTraversalState(frustrum, seconds, kPruneNone)
        {}
    };
        
    class DrawWireframeTraversal
        : public DrawTraversal<DrawWireframeTraversal, DrawWireframeState>
    {
    public:
        typedef DrawTraversal<DrawWireframeTraversal, DrawWireframeState> BaseClass;
        DrawWireframeTraversal(
            DrawWireframeState&     state,
            bool                    isReflection,
            Frustum::ClippingResult parentClippingResult)
            : BaseClass(state, xform, isReflection, parentClippingResult)
        {}
        
        void draw(const boost::shared_ptr<const ShapeSample>& sample)
        {
            if (!sample->visibility()) return;
            gGLFT->glLoadMatrixd(xform().matrix[0]);
            if (sample->isBoundingBoxPlaceHolder()) {
                state().vboProxy().drawBoundingBox(sample);
                GlobalReaderCache::theCache().hintShapeReadOrder(subNode());
                return;
            }
            assert(sample->positions());
            assert(sample->normals());
            state().vboProxy().drawWireframe(sample);
        }
    };
    
    
    
    class DrawShadedTypes 
    {
    public:
        enum ColorType {
            kSubNodeColor,
            kDefaultColor,
            kBlackColor,
            kXrayColor
        };
    
        enum NormalsType {
            kFrontNormals,
            kBackNormals
        };
    };
    class DrawShadedState : public DrawTraversalState, public DrawShadedTypes
    {
    public:
        DrawShadedState(
            const Frustum&             frustrum,
            const double               seconds,
            const TransparentPruneType transparentPrune,
            const ColorType            colorType,
            const MColor&              defaultDiffuseColor,
 
            const NormalsType          normalsType)
            : DrawTraversalState(frustrum, seconds, transparentPrune),
              fColorType(colorType),
              fDefaultDiffuseColor(defaultDiffuseColor),
              fNormalsType(normalsType)
        {}
        ColorType      colorType() const           { return fColorType; }
        const MColor&  defaultDiffuseColor()
 const { 
return fDefaultDiffuseColor; } 
 
        NormalsType    normalsType() const         { return fNormalsType; }
        
    private:
        const ColorType      fColorType;
        const MColor         fDefaultDiffuseColor;
 
        const NormalsType    fNormalsType;
    };
        
    class DrawShadedTraversal
        : public DrawTraversal<DrawShadedTraversal, DrawShadedState>,
          public DrawShadedTypes
    {
    public:
        typedef DrawTraversal<DrawShadedTraversal, DrawShadedState> BaseClass;
        DrawShadedTraversal(
            DrawShadedState&        state,
            bool                    isReflection,
            Frustum::ClippingResult parentClippingResult)
            : BaseClass(state, xform, isReflection, parentClippingResult)
        {}
        
        void draw(const boost::shared_ptr<const ShapeSample>& sample)
        {
            if (!sample->visibility()) return;
            gGLFT->glLoadMatrixd(xform().matrix[0]);
            if (sample->isBoundingBoxPlaceHolder()) {
                state().vboProxy().drawBoundingBox(sample, true);
                GlobalReaderCache::theCache().hintShapeReadOrder(subNode());
                return;
            }
            assert(sample->positions());
            assert(sample->normals());
            
            switch (state().colorType()) {
                case kSubNodeColor:
                    diffuseColor = sample->diffuseColor();
                    break;
                case kDefaultColor:
                    diffuseColor = state().defaultDiffuseColor();
                    break;
                case kBlackColor:
                    diffuseColor =
                        MColor(0.0f, 0.0f, 0.0f, sample->diffuseColor()[3]);
 
                    break;
                case kXrayColor:
                    diffuseColor = 
MColor(sample->diffuseColor()[0],
                                          sample->diffuseColor()[1],
                                          sample->diffuseColor()[2],
                                          0.3f);
                    break;
                default:
                    assert(0);
                    break;
            }
            if (diffuseColor[3] <= 0.0 ||
                (diffuseColor[3] >= 1.0 &&
                    state().transparentPrune() == DrawShadedState::kPruneOpaque) ||
                (diffuseColor[3] <  1.0 &&
                    state().transparentPrune() == DrawShadedState::kPruneTransparent)) {
                return;
            }
            gGLFT->glColor4f(diffuseColor[0]*diffuseColor[3],
                             diffuseColor[1]*diffuseColor[3],
                             diffuseColor[2]*diffuseColor[3],
                             diffuseColor[3]);
            
            
            gGLFT->glFrontFace(isReflection() ? MGL_CW : MGL_CCW);
            for (size_t groupId = 0; groupId < sample->numIndexGroups(); ++groupId ) {
                state().vboProxy().drawTriangles(
                    sample, groupId,
                    state().normalsType() == kFrontNormals ?
                    VBOProxy::kFrontNormals : VBOProxy::kBackNormals,
                    VBOProxy::kNoUVs);
            }
        }
    };
    
    
    
    class ReadBufferVisitor : public SubNodeVisitor
    {
    public:
        ReadBufferVisitor(
double seconds, BufferCache* buffer, 
MMatrix xformMatrix) 
            : fSeconds(seconds), fMyBufferCache(buffer), fthisXForm(xformMatrix) {}
        virtual void visit(const XformData&   xform,
            const SubNode&     subNode)
        {
            const boost::shared_ptr<const XformSample>& sample =
                xform.getSample(fSeconds);
            
            ReadBufferVisitor newVisitor(fSeconds, fMyBufferCache, sample->xform() * fthisXForm);
            
            BOOST_FOREACH(const SubNode::Ptr& child,
                subNode.getChildren() ) {
                    child->accept(newVisitor);
            }
        }
        virtual void visit(const ShapeData&   shape,
            const SubNode&     subNode)
        {
            const boost::shared_ptr<const ShapeSample>& sample =
                shape.getSample(fSeconds);
            if (!sample) return;
            
            fMyBufferCache->fNumTriangles.push_back(sample->numTriangles());
            fMyBufferCache->fNumEdges.push_back(sample->numWires());
            fMyBufferCache->fTotalNumVerts+=sample->numVerts();
            fMyBufferCache->fTotalNumTris+=sample->numTriangles();
            VertexBuffer::ReadInterfacePtr vertexPositionRead= sample->positions()->readableInterface();
            if (sample->triangleVertIndices(0) && sample->wireVertIndices()) {
                    fMyBufferCache->fPositions.push_back(vertexPositionRead);
                    IndexBuffer::ReadInterfacePtr triangleIndexRead = sample->triangleVertIndices(0)->readableInterface();
                    IndexBuffer::ReadInterfacePtr edgeIndexRead = sample->wireVertIndices()->readableInterface();
                    fMyBufferCache->fTriangleVertIndices.push_back(triangleIndexRead);
                    fMyBufferCache->fEdgeVertIndices.push_back(edgeIndexRead);
                    fMyBufferCache->fBoundingBoxes.push_back(sample->boundingBox());
                    fMyBufferCache->fXFormMatrix.push_back(fthisXForm);
                    fMyBufferCache->fXFormMatrixInverse.push_back(fthisXForm.inverse());
                    fMyBufferCache->fUseCachedBuffers = true;
                    fMyBufferCache->fNumShapes ++;
            }
        }
    private:
        BufferCache* fMyBufferCache;
        double fSeconds;
    };
    
    
    
    class NbPrimitivesVisitor : public SubNodeVisitor
    {
    public:
        NbPrimitivesVisitor(double seconds) 
            : fSeconds(seconds),
              fNumWires(0),
              fNumTriangles(0)
        {}
        size_t numWires()       { return fNumWires; }
        size_t numTriangles()   { return fNumTriangles; }
        
        virtual void visit(const XformData&   xform,
                           const SubNode&     subNode)
        {
            
            BOOST_FOREACH(const SubNode::Ptr& child,
                          subNode.getChildren() ) {
                child->accept(*this);
            }
        }
        
        virtual void visit(const ShapeData&   shape,
                           const SubNode&     subNode)
        {
            const boost::shared_ptr<const ShapeSample>& sample =
                shape.getSample(fSeconds);
            if (!sample) return;
            fNumWires       += sample->numWires();
            fNumTriangles   += sample->numTriangles();
        }
        
    private:
    
        const double    fSeconds;
        size_t          fNumWires;
        size_t          fNumTriangles;
    };
    
    
    
    class SnapTraversalState : public DrawTraversalState 
    {
    public:
        SnapTraversalState(const Frustum&  frustrum,
                           const double    seconds,
            : DrawTraversalState(frustrum, seconds, kPruneNone),
              fLocalToPort(localToPort),
              fInclusiveMatrix(inclusiveMatrix),
              fSnapInfo(snapInfo),
              fSelected(false)
        {}
        const MMatrix& localToPort()
 const      { 
return fLocalToPort; }
 
        const MMatrix& inclusiveMatrix()
 const  { 
return fInclusiveMatrix; }
 
        
        bool selected() const { return fSelected; }
        void setSelected()    { fSelected  = true; }
        
    private:
        bool            fSelected;
    };
    class SnapTraversal
        : public DrawTraversal<SnapTraversal, SnapTraversalState>
    {
    public:
        typedef DrawTraversal<SnapTraversal, SnapTraversalState> BaseClass;
        SnapTraversal(
            SnapTraversalState&     state,
            bool                    isReflection,
            Frustum::ClippingResult parentClippingResult)
            : BaseClass(state, xform, false, parentClippingResult)
        {}
        void draw(const boost::shared_ptr<const ShapeSample>& sample)
        {
            if (!sample->visibility()) return;
            if (sample->isBoundingBoxPlaceHolder()) return;
            assert(sample->positions());
            VertexBuffer::ReadInterfacePtr readable = sample->positions()->readableInterface();
            const float* const positions = readable->get();
            
            unsigned int srx, sry, srw, srh;
            state().snapInfo().selectRect(srx, sry, srw, srh);
            double srxl = srx;
            double sryl = sry;
            double srxh = srx + srw;
            double sryh = sry + srh;
            const MMatrix localToPort     = xform() * state().localToPort();
 
            const MMatrix inclusiveMatrix = xform() * state().inclusiveMatrix();
 
            
            
            
            
            size_t numVertices = sample->numVerts();
            for (size_t vertexIndex=0; vertexIndex<numVertices; vertexIndex++)
            {
                const float* const currentPoint = &positions[vertexIndex*3];
                
                
                MPoint loPt(currentPoint[0], currentPoint[1], currentPoint[2]);
 
                MPoint pt = loPt * localToPort;
 
                if (pt.
x >= srxl && pt.
x <= srxh &&
 
                    pt.
y >= sryl && pt.
y <= sryh &&
                    pt.
z >= 0.0  && pt.
z <= 1.0) {
                    MPoint wsPt = loPt * inclusiveMatrix;
 
                    state().snapInfo().setSnapPoint(wsPt);
                    state().setSelected();
                }
            }
        }
    };
    
    
    
    class WaitCursor
    {
    public:
        WaitCursor()
        {
        }
        ~WaitCursor()
        {
        }
    private:
        
        WaitCursor(const WaitCursor&);
        const WaitCursor& operator=(const WaitCursor&);
    };
}
namespace GPUCache {
const MTypeId ShapeNode::id(0x580000C4);
 
const MString ShapeNode::drawDbClassificationGeometry(
 
    "drawdb/geometry/gpuCache" );
const MString ShapeNode::drawDbClassificationSubScene(
 
    "drawdb/subscene/gpuCache" );
const MString ShapeNode::drawRegistrantId(
"gpuCache" );
 
MCallbackId ShapeNode::fsModelEditorChangedCallbackId;
const char* ShapeNode::nodeTypeName = "gpuCache";
const char* ShapeNode::selectionMaskName = "gpuCache";
static std::vector<MCallbackId> s3dViewPostRenderCallbackIds;
static std::vector<MCallbackId> s3dViewDeletedCallbackIds;
static int sNb3dViewPostRenderCallbacks = 0;
enum ModelEditorState {
    kDefaultViewportOnly,
    kViewport2Only,
    kDefaultViewportAndViewport2
};
static ModelEditorState sModelEditorState = kDefaultViewportAndViewport2;
static void viewPostRender(
const MString &str, 
void* )
 
{
    VBOBuffer::nextRefresh();
}
static void clearPostRenderCallbacks()
{
    {
        std::vector<MCallbackId>::iterator it  = s3dViewPostRenderCallbackIds.begin();
        std::vector<MCallbackId>::iterator end = s3dViewPostRenderCallbackIds.end();
        for (; it != end; ++it) {
        }
        s3dViewPostRenderCallbackIds.clear();
    }
    {
        std::vector<MCallbackId>::iterator it  = s3dViewDeletedCallbackIds.begin();
        std::vector<MCallbackId>::iterator end = s3dViewDeletedCallbackIds.end();
        for (; it != end; ++it) {
        }
        s3dViewDeletedCallbackIds.clear();
    }
    sNb3dViewPostRenderCallbacks = 0;
}
static void uiDeleted(void* clientData)
{
    MUintPtrSz idx = reinterpret_cast<MUintPtrSz>(clientData);
    s3dViewPostRenderCallbackIds[idx] = MCallbackId();
    s3dViewDeletedCallbackIds[idx] = MCallbackId();
    --sNb3dViewPostRenderCallbacks;
    assert(sNb3dViewPostRenderCallbacks >= 0);
}
static void modelEditorChanged(void* )
{
    
    
    
        
    static bool sVBOsClean             = false;
    static bool sViewport2BuffersClean = false;
    
    
    bool hasDefaultViewport = false;
    bool hasViewport2       = false;
    for (unsigned int i = 0; i < viewCount; i++) {
        
            hasDefaultViewport = true;
        }
            hasViewport2 = true;
        }
    }
    
    if (hasDefaultViewport) {
        sVBOsClean = false;
    }
    
    if (hasViewport2) {
        sViewport2BuffersClean = false;
    }
    
    if (!hasDefaultViewport && !sVBOsClean) {
        VBOBuffer::clear();
        
        
        sVBOsClean = true;
    }
    
    if (!hasViewport2 && !sViewport2BuffersClean)  {
        SubSceneOverride::clear();
        sViewport2BuffersClean = true;
    }
    
    if (hasDefaultViewport && hasViewport2) {
        sModelEditorState = kDefaultViewportAndViewport2;
    }
    else if (hasDefaultViewport) {
        sModelEditorState = kDefaultViewportOnly;
    }
    else if (hasViewport2) {
        sModelEditorState = kViewport2Only;
    }
    else {
        sModelEditorState = kDefaultViewportAndViewport2;
    }
}
static void nodeAddedToModel(
MObject& node, 
void* clientData)
 
{
    ShapeNode* shapeNode = (ShapeNode*)dagNode.userNode();
    assert(shapeNode);
    if (!shapeNode) return;
    shapeNode->addedToModelCB();
}
static void nodeRemovedFromModel(
MObject& node, 
void* clientData)
 
{
    ShapeNode* shapeNode = (ShapeNode*)dagNode.userNode();
    assert(shapeNode);
    if (!shapeNode) return;
    shapeNode->removedFromModelCB();
}
static void TimeChangeCallback(
MTime& time, 
void* clientData)
 
{
    assert(clientData);
}
void* ShapeNode::creator()
{
    return new ShapeNode;
}
{
    
    aCacheFileName = typedAttrFn.
create(
"cacheFileName", 
"cfn",
    MCHECKERROR(stat, "MPxNode::addAttribute(aCacheFileName)");
    
    aCacheGeomPath = typedAttrFn.
create(
"cacheGeomPath", 
"cmp",
    MCHECKERROR(stat, "MPxNode::addAttribute(aCacheFileName)");
    if (Config::vp2OverrideAPI() != Config::kMPxDrawOverride) {
            "modelEditorChanged", modelEditorChanged, NULL, &stat);
        MCHECKERROR(stat, "MEventMessage::addEventCallback(modelEditorChanged)");
    }
    
    modelEditorChanged(NULL);
    stat = DisplayPref::initCallback();
    MCHECKERROR(stat, "DisplayPref::initCallbacks()");
    
    return stat;
}
{
    if (Config::vp2OverrideAPI() != Config::kMPxDrawOverride) {
    }
    DisplayPref::removeCallback();
    clearPostRenderCallbacks();
    
    
    
    
    
    
    
    
    assert( CacheFileRegistry::theCache().size() == 0 );
    CacheFileRegistry::theCache().clear();
    
}
MStatus ShapeNode::init3dViewPostRenderCallbacks()
 
{
        clearPostRenderCallbacks();
        static MString listEditorPanelsCmd = 
"gpuCacheListModelEditorPanels";
 
        MCHECKERROR(exitStatus, "gpuCacheListModelEditorPanels");
    
            sNb3dViewPostRenderCallbacks = editorPanels.
length();
            for (int i=0; i<sNb3dViewPostRenderCallbacks; ++i) {
                    editorPanels[i], viewPostRender, NULL, &status);
                MREPORTERROR(status, "MUiMessage::add3dViewPostRenderMsgCallback()");
                    s3dViewDeletedCallbackIds.push_back(MCallbackId());
                    s3dViewPostRenderCallbackIds.push_back(MCallbackId());
                    continue;
                }
                s3dViewPostRenderCallbackIds.push_back(callbackId);
                    editorPanels[i], uiDeleted, reinterpret_cast<void*>(MUintPtrSz(i)), &status);
                MREPORTERROR(status, "MUiMessage::addUiDeletedCallback()");
                    s3dViewDeletedCallbackIds.push_back(MCallbackId());
                    continue;
                }
                s3dViewDeletedCallbackIds.push_back(callbackId);
            }
        }
    }
    return exitStatus;
}
ShapeNode::ShapeNode()
:   fCachedGeometry()
,   fCacheReadingState(kCacheReadingDone)
,   fTimeChangeCallbackId(0)
{
    fBufferCache = NULL;
}
ShapeNode::~ShapeNode()
{
    while(!fSpatialSub.empty()){
        delete fSpatialSub.back();
        fSpatialSub.pop_back();
    }
    delete fBufferCache;
}
void ShapeNode::postConstructor()
{
    setRenderable(true);
    
    
    
    
    Config::initialize();
}
bool ShapeNode::isBounded() const
{
    return true;
}
unsigned int ShapeNode::getIntersectionAccelerator(
    const       gpuCacheIsectAccelParams& accelParams,
                double      seconds
) const
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
{
    if (!fCacheFileEntry || fCacheFileEntry->fReadState != CacheFileEntry::kReadingDone) {
        return 0;
    }
    if( fBufferCache !=NULL && (fBufferCache->fUseCachedBuffers && fBufferCache->fBufferReadTime==seconds) && (!fSpatialSub.empty()) && (fSpatialSub[0]->matchesParams(accelParams)) )
    {
        return fSpatialSub.size();
    }
    else
    {
        while(!fSpatialSub.empty()){
            delete fSpatialSub.back(); fSpatialSub.pop_back();
        }
        const SubNode::Ptr subNode = getCachedGeometry();
        if(readBuffers(subNode,seconds)){
            for(unsigned int s=0; s < fBufferCache->fNumShapes; s++){
                const index_t* srcTriangleVertIndices = fBufferCache->fTriangleVertIndices[s]->get();
                const float* srcPositions = fBufferCache->fPositions[s]->get();
                fSpatialSub.push_back (new gpuCacheSpatialSubdivision(fBufferCache->fNumTriangles[s], srcTriangleVertIndices, srcPositions, fBufferCache->fBoundingBoxes[s], accelParams));
            }
            return fSpatialSub.size();
        }
    }
    return 0;
}
bool ShapeNode::getEdgeSnapPoint(
const MPoint &rayPointSrc, 
const MVector &rayDirectionSrc, 
MPoint &theClosestPoint) {
 
    gpuCacheIsectAccelParams accelParams = gpuCacheIsectAccelParams::autoUniformGridParams(); 
    unsigned int numAccels = getIntersectionAccelerator(accelParams, seconds);
    bool foundPoint = false;
    if(numAccels > 0 && numAccels == fBufferCache->fNumShapes) {
        unsigned int closestShape=0;
        double minDist = std::numeric_limits<double>::max();
        bool *checkedBox = new bool[fBufferCache->fNumShapes];
        double *allDists = new double[fBufferCache->fNumShapes];
        for(unsigned int s=0; s<fBufferCache->fNumShapes; s++){
            checkedBox[s] = false;
            if(fBufferCache->fNumTriangles[s]>0){
                allDists[s] = gpuCacheIsectUtil::getEdgeSnapPointOnBox(rayPointSrc, rayDirectionSrc, xformBBox, closestPointOnBox);
                if(allDists[s] < minDist){
                    minDist = allDists[s];
                    closestShape = s;
                }
            } else {
                allDists[s] = std::numeric_limits<double>::max();
            }
        }
        std::vector<int> potentialShapes;
        for(unsigned int s=0; s<fBufferCache->fNumShapes; s++){
            if(allDists[s]==minDist){
                potentialShapes.push_back(s);
                checkedBox[s]=true;
            }
        }
        double coef_plane = rayDirectionSrc * rayPointSrc;
        minDist = std::numeric_limits<double>::max();
        while(!potentialShapes.empty()){    
            closestShape = potentialShapes.back();
            potentialShapes.pop_back();
            
            if(allDists[closestShape]<=minDist){
                const index_t* srcTriangleVertIndices = fBufferCache->fTriangleVertIndices[closestShape]->get();
                const float* srcPositions = fBufferCache->fPositions[closestShape]->get();
                double dist = fSpatialSub[closestShape]->getEdgeSnapPoint(fBufferCache->fNumTriangles[closestShape], srcTriangleVertIndices, srcPositions,
                    rayPointSrc*fBufferCache->fXFormMatrixInverse[closestShape], rayDirectionSrc*fBufferCache->fXFormMatrixInverse[closestShape], clsPoint);
                clsPoint *= fBufferCache->fXFormMatrix[closestShape];
                
                double d = coef_plane - rayDirectionSrc * clsPoint;
                MPoint projectedClsPoint = clsPoint + rayDirectionSrc * d;
 
                dist = rayPointSrc.distanceTo(projectedClsPoint);
                if(dist < minDist){
                    minDist = dist;
                    theClosestPoint = clsPoint;
                    foundPoint = true;
                    for(unsigned int s=0; s<fBufferCache->fNumShapes; s++){
                        if(!checkedBox[s] && allDists[s]<=minDist){
                            std::vector<int>::iterator it = potentialShapes.begin();
                            while (it != potentialShapes.end() && allDists[s]<allDists[*it])
                            {
                                it++;
                            }
                            potentialShapes.insert(it,s);
                            checkedBox[s]=true;
                        }
                    }
                }
            }
        }
        delete[] checkedBox;
        delete[] allDists;
    }
    return foundPoint;
}
bool ShapeNode::closestPoint( 
const MPoint &raySource, 
const MVector &rayDirection, 
MPoint &theClosestPoint, 
MVector &theClosestNormal, 
bool findClosestOnMiss, 
double tolerance) 
 
{
    if(closestIntersectWithNorm(raySource,rayDirection,theClosestPoint,theClosestNormal)) {
        return true;
    } else if(findClosestOnMiss) {
        if(getEdgeSnapPoint(raySource,rayDirection,theClosestPoint)) {
            return true;
        }
    }
    return false;
}
bool ShapeNode::canMakeLive() const { 
    return true; 
}
bool ShapeNode::readBuffers(const SubNode::Ptr subNode, double seconds)const{
    if(subNode == NULL) return false;
    if(fBufferCache!=NULL && fBufferCache->fUseCachedBuffers && fBufferCache->fBufferReadTime==seconds) return true;
    if(fBufferCache!=NULL){
        delete fBufferCache;
    }
    fBufferCache = new BufferCache(seconds);
    if(fBufferCache == NULL){
        return false;
    } 
    ReadBufferVisitor visitor(seconds, fBufferCache, identMat);
    subNode->accept(visitor);
    if(fBufferCache->fUseCachedBuffers && (fBufferCache->fNumShapes)>1 && (fBufferCache->fTotalNumTris) > 1000000){
    }
    return fBufferCache->fUseCachedBuffers;
}
void ShapeNode::closestPoint(
const MPoint &toThisPoint, 
MPoint &theClosestPoint, 
double tolerance) {
 
    gpuCacheIsectAccelParams accelParams = gpuCacheIsectAccelParams::autoUniformGridParams(); 
    unsigned int numAccels = getIntersectionAccelerator(accelParams, seconds);
    
    if(numAccels > 0 && numAccels == fBufferCache->fNumShapes) {
        unsigned int closestShape=0;
        double minDist = std::numeric_limits<double>::max();
        bool *checkedBox = new bool[fBufferCache->fNumShapes];
        double *allDists = new double[fBufferCache->fNumShapes];
        for(unsigned int s=0; s<fBufferCache->fNumShapes; s++){
            checkedBox[s] = false;
            if(fBufferCache->fNumTriangles[s]>0){
                allDists[s] = gpuCacheIsectUtil::getClosestPointOnBox(toThisPoint,xformBBox,closestPointOnBox);
                if(allDists[s] < minDist){
                    minDist = allDists[s];
                    closestShape = s;
                }
            } else {
                allDists[s] = std::numeric_limits<double>::max();
            }
        }
        std::vector<int> potentialShapes;
        potentialShapes.push_back(closestShape);
        minDist = std::numeric_limits<double>::max();
        while(!potentialShapes.empty()){    
            closestShape = potentialShapes.back();
            potentialShapes.pop_back();
            checkedBox[closestShape]=true;
            if(allDists[closestShape]<minDist){
                const index_t* srcTriangleVertIndices = fBufferCache->fTriangleVertIndices[closestShape]->get();
                const float* srcPositions = fBufferCache->fPositions[closestShape]->get();
                fSpatialSub[closestShape]->closestPointToPoint(fBufferCache->fNumTriangles[closestShape], srcTriangleVertIndices, srcPositions, toThisPoint * fBufferCache->fXFormMatrixInverse[closestShape], clsPoint);
                clsPoint *= fBufferCache->fXFormMatrix[closestShape];
                if(dist < minDist){
                    minDist = dist;
                    theClosestPoint = clsPoint;
                    for(unsigned int s=0; s<fBufferCache->fNumShapes; s++){
                        if(!checkedBox[s] && allDists[s]<minDist){
                            std::vector<int>::iterator it = potentialShapes.begin();
                            while (it != potentialShapes.end() && allDists[s]<allDists[*it])
                            {
                                it++;
                            }
                            potentialShapes.insert(it,s);
                        }
                    }
                }
            }
        }
        delete[] checkedBox;
        delete[] allDists;
    }
}
    gpuCacheIsectAccelParams accelParams = gpuCacheIsectAccelParams::autoUniformGridParams(); 
    unsigned int numAccels = getIntersectionAccelerator(accelParams, seconds); 
    if(numAccels > 0 && numAccels == fBufferCache->fNumShapes) {
        double minDist = std::numeric_limits<double>::max();
        for(unsigned int s=0; s<fBufferCache->fNumShapes; s++){
            const index_t* srcTriangleVertIndices = fBufferCache->fTriangleVertIndices[s]->get();
            const float* srcPositions = fBufferCache->fPositions[s]->get();
            if( fSpatialSub[s]->closestIntersection(fBufferCache->fNumTriangles[s], srcTriangleVertIndices, srcPositions, toThisPoint * fBufferCache->fXFormMatrixInverse[s], thisDirection * fBufferCache->fXFormMatrixInverse[s], 
                999999, clsPoint, clsNormal)){
                    clsPoint *= fBufferCache->fXFormMatrix[s];
                    clsNormal *= fBufferCache->fXFormMatrix[s];
                    if(dist < minDist){
                        minDist = dist;
                        theClosestPoint = clsPoint;
                        theClosestNormal = clsNormal;
                    }
            }
        } 
    }
    return returnStatus;
}
{
    
    const SubNode::Ptr subNode = getCachedGeometry();
    if (!subNode) {
    }
    const SubNodeData::Ptr subNodeData = subNode->getData();
    
    const XformData::Ptr xform =
        boost::dynamic_pointer_cast<const XformData>(subNodeData);
    if (xform) {
        const boost::shared_ptr<const XformSample>& sample =
            xform->getSample(seconds);
        return sample->boundingBox();
    }
    
    const ShapeData::Ptr shape =
        boost::dynamic_pointer_cast<const ShapeData>(subNodeData);
    if (shape) {
        const boost::shared_ptr<const ShapeSample>& sample =
            shape->getSample(seconds);
        return sample->boundingBox();
    }
    
}
bool ShapeNode::getInternalValueInContext(
const MPlug& plug,
 
{
    if (plug == aCacheFileName) {
        return true;
    }
    else if (plug == aCacheGeomPath) {
        return true;
    }
}
bool ShapeNode::setInternalValues(
)
{
    const MString oldFileName = fCacheFileName;
 
    const MString oldResolvedFileName = fResolvedCacheFileName;
 
    const MString oldGeomPath = fCacheGeomPath;
 
    
    if( newResolvedFileName.
length() == 0 )
 
    {
        newResolvedFileName = newFileName;
    }
    
    
    
    
    
    bool fileChanged = (newFileName != oldFileName);
    bool pathChanged = (newGeomPath != oldGeomPath);
    if (!fileChanged && !pathChanged)
    {
        return true;
    }
    if( fileChanged )
    {
        
        if( newResolvedFileName.
length() > 0 )
 
        {
            CacheFileEntry::MPtr entry = CacheFileRegistry::theCache().find(newResolvedFileName);
            if( entry )
            {
                
                fCachedGeometry.reset();
                fCachedMaterial.reset();
                
                fCacheFileName = newFileName;
                fResolvedCacheFileName = newResolvedFileName;
                fCacheGeomPath = newGeomPath;
                fCacheFileEntry = entry;
                
                
                fCacheReadingState = kCacheReadingFile;
                
                
                CacheShapeRegistry::theCache().remove(oldResolvedFileName, thisMObject());
                CacheShapeRegistry::theCache().insert(newResolvedFileName, thisMObject());
                
                
                CacheFileRegistry::theCache().cleanUp(oldResolvedFileName);
                return true;
            }
        }
        
        fCacheFileName = newFileName;
        fResolvedCacheFileName = newResolvedFileName;
        fCacheGeomPath = newGeomPath;
        
        
        CacheShapeRegistry::theCache().remove(oldResolvedFileName, thisMObject());
        CacheShapeRegistry::theCache().insert(newResolvedFileName, thisMObject());
        
        fCachedGeometry.reset();
        fCachedMaterial.reset();
        fCacheFileEntry.reset();
        
        CacheFileRegistry::theCache().cleanUp(oldResolvedFileName);
        
        
        if( newResolvedFileName.
length() > 0 )
 
        {
            
            CacheFileEntry::MPtr newEntry = CacheFileEntry::create( newResolvedFileName );
            CacheFileRegistry::theCache().insert( newResolvedFileName, newEntry );
            fCacheFileEntry = newEntry;
            fCacheReadingState = kCacheReadingFile;
        }
    }
    else
    {
        
        fCacheGeomPath = newGeomPath;
        
        
        fCacheReadingState = kCacheReadingFile;
    }
    return true;
}
bool ShapeNode::setInternalValueInContext(
const MPlug& plug,
 
{
    if (plug == aCacheFileName) {
        return setInternalValues(newFileName, fCacheGeomPath);
    }
    else if (plug == aCacheGeomPath) {
        return setInternalValues(fCacheFileName, newGeomPath);
    }
}
void ShapeNode::refreshCachedGeometry( bool clearFileCache  )
{
    
    const MString cacheFileName = fCacheFileName;
 
    const MString resolvedCacheFileName = fResolvedCacheFileName;
 
    const MString cacheGeomPath = fCacheGeomPath;
 
    
    if (fCacheFileEntry && fCacheFileEntry->fReadState != CacheFileEntry::kReadingDone) {
        GlobalReaderCache::theCache().cancelRead(fCacheFileEntry.get());
        fCacheFileEntry->fReadState = CacheFileEntry::kReadingDone;
    }
    
    if (fCacheReadingState != kCacheReadingDone) {
        fCacheReadingState = kCacheReadingDone;
    }
    
    if( clearFileCache )
    {
        CacheFileRegistry::theCache().remove(resolvedCacheFileName);
    }
    
    CacheShapeRegistry::theCache().remove(resolvedCacheFileName, thisMObject());
    
    fResolvedCacheFileName.clear();
    fCacheGeomPath.clear();
    fCachedGeometry.reset();
    fCachedMaterial.reset();
    fCacheFileEntry.reset();
    
    setInternalValues(cacheFileName, cacheGeomPath);
    
    if( clearFileCache )
    {
        refreshOtherCachedShapes( resolvedCacheFileName );
    }
}
void ShapeNode::refreshOtherCachedShapes( 
const MString& cacheFileName )
 
{
    
    {
        return;
    }
    
    std::vector<MObjectHandle> otherShapes;
    CacheShapeRegistry::theCache().find( cacheFileName, otherShapes );
    for( size_t i = 0; i < otherShapes.size(); i++ )
    {
        if( !otherShapes[i].isValid() )
        {
            continue;
        }
        assert( nodeFn.
typeId() == id );
        ShapeNode* shape = (ShapeNode*) nodeFn.
userNode();
        assert( shape );
        
        shape->refreshCachedGeometry( false );
    }
}
const SubNode::Ptr& ShapeNode::getCachedGeometry() const
{
    
    
    CacheFileEntry::MPtr entry = fCacheFileEntry;
    assert(!(entry && entry->fCacheReaderProxy && (entry->fCachedGeometry || entry->fCachedMaterial)));
    
    if( fCacheReadingState == kCacheReadingFile )
    {
        
        assert(entry);
        if (fCacheFileEntry->fCacheReaderProxy) {
                
                GlobalReaderCache::theCache().scheduleRead(entry.get(), 
                                                           "|", 
                                                           fCacheFileEntry->fCacheReaderProxy);
                entry->fReadState = CacheFileEntry::kReadingHierarchyInProgress;
            }
            else {
                
                WaitCursor waitCursor;
                
                
                GlobalReaderCache::CacheReaderHolder holder(fCacheFileEntry->fCacheReaderProxy);
                const boost::shared_ptr<CacheReader> cacheReader = holder.getCacheReader();
                if (cacheReader && cacheReader->valid()) {
                    entry->fCachedGeometry = cacheReader->readScene(
                        "|", !Config::isIgnoringUVs());
                    entry->fCachedMaterial = cacheReader->readMaterials();
                }
            }
        
            
            
            
            
            
            
            
            
            
            fCacheFileEntry->fCacheReaderProxy.reset();
        }
        
        if (entry->fReadState == CacheFileEntry::kReadingHierarchyInProgress) {
            if (GlobalReaderCache::theCache().pullHierarchy(entry.get(), entry->fCachedGeometry, validatedGeometryPath, entry->fCachedMaterial)) {
                
                entry->fReadState = CacheFileEntry::kReadingShapesInProgress;
                
                if (!entry->fCachedGeometry) {
                    entry->fReadState = CacheFileEntry::kReadingDone;
                }
                
                const_cast<ShapeNode*>(this)->childChanged(kBoundingBoxChanged);
            }
        }
        else if (entry->fReadState == CacheFileEntry::kReadingShapesInProgress) {
            if (GlobalReaderCache::theCache().pullShape(entry.get(), entry->fCachedGeometry)) {
                
                entry->fReadState = CacheFileEntry::kReadingDone;
            }
        }
        
        bool readingDone = (entry->fReadState == CacheFileEntry::kReadingDone);
        bool readingHierarchyDone = readingDone || (entry->fReadState == CacheFileEntry::kReadingShapesInProgress);
        if( readingHierarchyDone )
        {
            
            CreateSubNodeHierarchy(entry->fCachedGeometry, fCacheGeomPath, validatedGeomPath, fCachedGeometry);
            fCachedMaterial = entry->fCachedMaterial;
            
            updateGeomPath( validatedGeomPath );
        }
        if( readingDone )
        {
            fCacheReadingState = kCacheReadingDone;
        }
    }
    return fCachedGeometry;
}
void ShapeNode::updateGeomPath( 
const MString& validatedGeomPath )
 const 
{
    
    if (fCacheGeomPath != validatedGeomPath) {
        if (fCacheGeomPath.length() > 0) {
            
                fCacheGeomPath, fCacheFileName, validatedGeomPath);
        }
        fCacheGeomPath = validatedGeomPath;
        
        
                                        "evalDeferred \"autoUpdateAttrEd;\";");
    }
}
const MaterialGraphMap::Ptr& ShapeNode::getCachedMaterial() const
{
    getCachedGeometry();  
    return fCachedMaterial;
}
const CacheFileEntry::MPtr& ShapeNode::getCacheFileEntry() const
{
    return fCacheFileEntry;
}
const CacheFileEntry::BackgroundReadingState ShapeNode::backgroundReadingState() const
{
    if( fCacheFileEntry )
    {
        return fCacheFileEntry->fReadState;
    }
    return CacheFileEntry::kReadingDone;
}
    bool shortName, bool unresolvedName, bool markCouldBeImageSequence ) const
{
    if(unresolvedName)
    {
    }
    else
    {
        
    }    
    
    return files;
}
void ShapeNode::copyInternalData(
MPxNode* source)
 
{
    if (source && source->
typeId() == id) {
 
        ShapeNode* node = dynamic_cast<ShapeNode*>(source);
        fCacheFileName = node->fCacheFileName;
        fCacheGeomPath = node->fCacheGeomPath;
        
        
        fCachedGeometry   = node->fCachedGeometry;
        fCachedMaterial   = node->fCachedMaterial;
        fCacheFileEntry   = node->fCacheFileEntry;
        
        
        
        fCacheReadingState = kCacheReadingFile;
    }
}
{
}
{
}
bool ShapeNode::excludeAsPluginShape() const
{
    
    
    return false;
}
void ShapeNode::addedToModelCB()
{
    
    CacheShapeRegistry::theCache().insert(fResolvedCacheFileName, thisMObject());
    
    
    
    refreshCachedGeometry(false);
    
}
void ShapeNode::removedFromModelCB()
{
    
    if (fTimeChangeCallbackId)
    {
        fTimeChangeCallbackId = 0;
    }
    
    CacheShapeRegistry::theCache().remove(fResolvedCacheFileName, thisMObject());
    
    
    fCacheFileEntry.reset();
    CacheFileRegistry::theCache().cleanUp(fResolvedCacheFileName);
}
void ShapeNode::timeChangeCB(double timeInSeconds)
{
    fBoundingBox = boundingBox();
    if (prevBoundingBox.
min() != fBoundingBox.min() ||
 
        prevBoundingBox.
max() != fBoundingBox.max())
    {
    }
}
void ShapeNode::dirtyVP2Geometry( 
const MString& fileName )
 
{
    
    
    if( Config::vp2OverrideAPI() == Config::kMPxDrawOverride )
    {
        std::vector<MObjectHandle> shapes;
        CacheShapeRegistry::theCache().find( fileName, shapes );
        size_t nShapes = shapes.size();
        for( size_t i = 0; i < nShapes; i++ )
        {
            if( !shapes[i].isValid() )
            {
                continue;
            }
            MObject shape = shapes[i].object();
 
        }
    }
}
CacheShapeRegistry CacheShapeRegistry::fsSingleton;
CacheShapeRegistry::Map CacheShapeRegistry::fMap;
CacheShapeRegistry::CacheShapeRegistry()
{}
CacheShapeRegistry::~CacheShapeRegistry()
{}
CacheShapeRegistry& CacheShapeRegistry::theCache()
{
    return fsSingleton;
}
void CacheShapeRegistry::getAll( std::vector<MObjectHandle>& shapes )
{
    shapes.clear();
    for( Map::iterator it = fMap.begin(); it != fMap.end(); it++ )
    {
        shapes.push_back( it->second );
    }
}
void CacheShapeRegistry::find( 
const MString& key, std::vector<MObjectHandle>& shapes )
 
{
    shapes.clear();
    std::pair<Map::iterator, Map::iterator> its = fMap.equal_range(key);
    for( Map::iterator it = its.first; it != its.second; it++ )
    {
        shapes.push_back(it->second);
    }
}
{
    Map::value_type item( key, shape );
    fMap.insert( item );
    return true;
}
{
    std::pair<Map::iterator, Map::iterator> its = fMap.equal_range(key);
    for( Map::iterator it = its.first; it != its.second; it++ )
    {
        if( it->first == key &&
            it->second == shape )
        {
            fMap.erase(it);
            return true;
        }
    }
    return false;
}
void CacheShapeRegistry::clear()
{
    fMap.clear();
}
DisplayPref::WireframeOnShadedMode DisplayPref::fsWireframeOnShadedMode;
MCallbackId DisplayPref::fsDisplayPrefChangedCallbackId;
MStatus DisplayPref::initCallback()
 
{
    
    
        "DisplayPreferenceChanged", DisplayPref::displayPrefChanged, NULL, &stat);
    MCHECKERROR(stat, "MEventMessage::addEventCallback(DisplayPreferenceChanged");
    
    displayPrefChanged(NULL);
}
MStatus DisplayPref::removeCallback()
 
{
    
    MCHECKERROR(stat, "MEventMessage::removeCallback(DisplayPreferenceChanged)");
}
void DisplayPref::displayPrefChanged(void*)
{
    
        "displayPref -q -wireframeOnShadedActive", false, false, &stat);
    if (stat) {
        if (wireframeOnShadedActive == "full") {
            fsWireframeOnShadedMode = kWireframeOnShadedFull;
        }
        else if (wireframeOnShadedActive == "reduced") {
            fsWireframeOnShadedMode = kWireframeOnShadedReduced;
        }
        else if (wireframeOnShadedActive == "none") {
            fsWireframeOnShadedMode = kWireframeOnShadedNone;
        }
        else {
            assert(0);
        }
    }
}
DisplayPref::WireframeOnShadedMode DisplayPref::wireframeOnShadedMode()
{
    return fsWireframeOnShadedMode;
}
void* ShapeUI::creator()
{
    return new ShapeUI;
}
ShapeUI::ShapeUI()
{}
ShapeUI::~ShapeUI()
{}
void ShapeUI::getDrawRequests(
const MDrawInfo & info,
 
                              bool objectAndActiveOnly,
{
    
    
    
    
    ShapeNode::init3dViewPostRenderCallbacks();
    
    
    getDrawData( 0, data );
    
    
        return;
    }
    switch ( appearance )
    {
        {
        }break;
        
        {
        } break;
    
        
        
        default:    
        {
            ShapeNode* node = (ShapeNode*)surfaceShape();
            if (!node) break;
            const SubNode::Ptr geom = node->getCachedGeometry();
            if (!geom) break;
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            const DrawToken shadedDrawToken = needWireframe ?
                kDrawSmoothShadedDepthOffset : kDrawSmoothShaded;
            
            
            
            
            
            
            
            
                
                }
                
                
                
                
            }
                
                
            }
            else {
                
                if (geom->transparentType() != SubNode::kTransparent) {
                    
                    
                }
                
                if (geom->transparentType() != SubNode::kOpaque) {
                    
                    
                }
            }
            
            
            if (needWireframe && 
                DisplayPref::wireframeOnShadedMode() != DisplayPref::kWireframeOnShadedNone)
            {
                wireRequest.
setToken( kDrawWireframeOnShaded );
                queue.
add( wireRequest );
            }
        } break;
    }
}
{
    
    InitializeGLFT();
    
    
    DrawToken token = DrawToken(request.
token());
    switch( token )
    {
        case kBoundingBox :
            drawBoundingBox( request, view );
            break;
        case kDrawWireframe :
        case kDrawWireframeOnShaded :
            drawWireframe( request, view );
            break;
        case kDrawSmoothShaded :
            drawShaded( request, view, false );
            break;
        case kDrawSmoothShadedDepthOffset :
            drawShaded( request, view, true );
            break;
    }
}
{
    
    ShapeNode* node = (ShapeNode*)surfaceShape();
    if (!node) return;
    
    {
        
        
        bool lightingWasOn = gGLFT->glIsEnabled( MGL_LIGHTING ) == MGL_TRUE;
        
        
        if ( lightingWasOn ) {
            gGLFT->glDisable( MGL_LIGHTING );
        }
        gGLFT->glEnable( MGL_LINE_STIPPLE );
        gGLFT->glLineStipple(1,  Config::kLineStippleShortDashed);
        VBOProxy vboProxy;
        vboProxy.drawBoundingBox(box);
        
        
        if ( lightingWasOn ) {
            gGLFT->glEnable( MGL_LIGHTING );
        }
        gGLFT->glDisable( MGL_LINE_STIPPLE );
    }
}
{
    
    ShapeNode* node = (ShapeNode*)surfaceShape();
    if ( !node ) return;
    
    const SubNode::Ptr rootNode = node->getCachedGeometry();
    if (!rootNode) return;
    MMatrix localToPort = modelViewMatrix * projMatrix;
 
    {
        
        
        bool lightingWasOn = gGLFT->glIsEnabled( MGL_LIGHTING ) == MGL_TRUE;
        
        
        if ( lightingWasOn ) {
            gGLFT->glDisable( MGL_LIGHTING );
        }
        gGLFT->glEnable( MGL_LINE_STIPPLE );
        if (request.
token() == kDrawWireframeOnShaded) {
 
            
            DisplayPref::WireframeOnShadedMode wireframeOnShadedMode = 
                DisplayPref::wireframeOnShadedMode();
            if (wireframeOnShadedMode == DisplayPref::kWireframeOnShadedReduced) {
                gGLFT->glLineStipple(1, Config::kLineStippleDotted);
            }
            else {
                assert(wireframeOnShadedMode != DisplayPref::kWireframeOnShadedNone);
                gGLFT->glLineStipple(1, Config::kLineStippleShortDashed);
            }
        }
        else {
            gGLFT->glLineStipple(1, Config::kLineStippleShortDashed);
        }
        
        
        {
            Frustum frustum(localToPort.
inverse());
        
            DrawWireframeState state(frustum, seconds);
            DrawWireframeTraversal traveral(state, xform, false, Frustum::kUnknown);
            rootNode->accept(traveral);
        }
        
        
        if ( lightingWasOn ) {
            gGLFT->glEnable( MGL_LIGHTING );
        }
        gGLFT->glDisable( MGL_LINE_STIPPLE );
    }
}
void ShapeUI::drawShaded(
{
    
    ShapeNode* node = (ShapeNode*)surfaceShape();
    if ( !node ) return;
    
    const SubNode::Ptr rootNode = node->getCachedGeometry();
    if (!rootNode) return;
    MMatrix localToNDC = modelViewMatrix * projMatrix;
 
    unsigned int lightCount;
    const bool noLightSoDrawAsBlack =
        && lightCount == 0;
    
    {
        
        
        
        
        
        
        gGLFT->glPushAttrib(MGL_LIGHTING_BIT);
        
        {
            static const float sBlack[4] = {0.0f, 0.0f, 0.0f, 1.0f};
            gGLFT->glMaterialfv(MGL_FRONT_AND_BACK, MGL_SPECULAR, sBlack);
            gGLFT->glMaterialfv(MGL_FRONT_AND_BACK, MGL_EMISSION, sBlack);
        }
        
        DrawShadedState::TransparentPruneType transparentPrune =
                DrawShadedState::kPruneTransparent;
        if (isTransparent) {
            
            gGLFT->glBlendFunc(MGL_ONE, MGL_ONE_MINUS_SRC_ALPHA);
            transparentPrune = DrawShadedState::kPruneOpaque;
            gGLFT->glDepthMask( false );
        }
        DrawShadedTypes::ColorType colorType = DrawShadedTypes::kSubNodeColor;
            if (!noLightSoDrawAsBlack) {
            }
            
            
            
            defaultDiffuseColor[3] = 1.0f;
            transparentPrune = DrawShadedState::kPruneNone;
            colorType = DrawShadedTypes::kDefaultColor;
        }
            transparentPrune = DrawShadedState::kPruneNone;
            if (noLightSoDrawAsBlack) {
                defaultDiffuseColor = 
MColor(0, 0, 0, 0.3f);
                colorType           = DrawShadedTypes::kDefaultColor;
            }
            else {
                colorType = DrawShadedTypes::kXrayColor;
            }
        }
        else if (noLightSoDrawAsBlack) {
            colorType = DrawShadedTypes::kBlackColor;
        }
        if (noLightSoDrawAsBlack) {
            
            
            
            
            gGLFT->glDisable(MGL_LIGHTING);
        }
        
        const bool depthOffsetWasEnabled = gGLFT->glIsEnabled(MGL_POLYGON_OFFSET_FILL);
        if (depthOffset && !depthOffsetWasEnabled) {
            
            gGLFT->glEnable(MGL_POLYGON_OFFSET_FILL);  
        }
        
        gGLFT->glColorMaterial(MGL_FRONT_AND_BACK, MGL_AMBIENT_AND_DIFFUSE);
        gGLFT->glEnable(MGL_COLOR_MATERIAL) ;
        
        
        
        bool needEmulateTwoSidedLighting = false;
        if (Config::emulateTwoSidedLighting()) {
            
            bool  cullFace = (gGLFT->glIsEnabled(MGL_CULL_FACE) == MGL_TRUE);
            MGLint twoSidedLighting = MGL_FALSE;
            gGLFT->glGetIntegerv(MGL_LIGHT_MODEL_TWO_SIDE, &twoSidedLighting);
            
            
            
            needEmulateTwoSidedLighting = (!cullFace && twoSidedLighting);
        }
        {
            Frustum frustum(localToNDC.
inverse());
            if (needEmulateTwoSidedLighting) {
                gGLFT->glEnable(MGL_CULL_FACE);
                gGLFT->glLightModeli(MGL_LIGHT_MODEL_TWO_SIDE, 0);
                
                {
                    gGLFT->glCullFace(MGL_FRONT);
                    DrawShadedState state(frustum, 
                                          seconds, 
                                          transparentPrune,
                                          colorType,
                                          defaultDiffuseColor,
                                          DrawShadedState::kBackNormals);
                    DrawShadedTraversal traveral(
                        state, xform, xform.det3x3() < 0.0, Frustum::kUnknown);
                    rootNode->accept(traveral);
                }
                
                
                {
                    gGLFT->glCullFace(MGL_BACK);
                    DrawShadedState state(frustum, 
                                          seconds, 
                                          transparentPrune,
                                          colorType,
                                          defaultDiffuseColor,
                                          DrawShadedState::kFrontNormals);
                    DrawShadedTraversal traveral(
                        state, xform, xform.det3x3() < 0.0, Frustum::kUnknown);
                    rootNode->accept(traveral);
                }
                
                
                gGLFT->glDisable(MGL_CULL_FACE);
                gGLFT->glLightModeli(MGL_LIGHT_MODEL_TWO_SIDE, 1);
            }
            else {
                DrawShadedState state(frustum, 
                                      seconds, 
                                      transparentPrune,
                                      colorType,
                                      defaultDiffuseColor,
                                      DrawShadedState::kFrontNormals);
                DrawShadedTraversal traveral(
                    state, xform, xform.det3x3() < 0.0, Frustum::kUnknown);
                rootNode->accept(traveral);
            }
        }
        
        
        if (isTransparent) {
            gGLFT->glDepthMask( true );
            gGLFT->glBlendFunc(MGL_SRC_ALPHA, MGL_ONE_MINUS_SRC_ALPHA);
        }
        if (depthOffset && !depthOffsetWasEnabled) {
            gGLFT->glDisable(MGL_POLYGON_OFFSET_FILL);
        }
        
        gGLFT->glFrontFace(MGL_CCW);
        gGLFT->glPopAttrib();
    }
}
MPoint ShapeUI::getPointAtDepth(
 
    double     depth)
{
    
    
    
    
    
    
    
    
    
    
    
    
    
    if (!camera.isOrtho())
    {
        double np = camera.nearClippingPlane();
        double fp = camera.farClippingPlane();
        depth *= np / (fp - depth * (fp - np));
    }
    short x,y;
    res = neardb + depth*(fardb-neardb);
    return res;
}
bool ShapeUI::select(
{
    
    InitializeGLFT();
        return false;
    }
    
        return false;
    }
    
    
    ShapeNode* node = (ShapeNode*)surfaceShape();
    const SubNode::Ptr rootNode = node->getCachedGeometry();
    if (!rootNode) { return false;}
    const bool boundingboxSelection =
    const bool wireframeSelection =
    
    
    VBOProxy::VBOMode vboMode = VBOProxy::kUseVBOIfPossible;
    if (Config::vp2OverrideAPI() != Config::kMPxDrawOverride) {
        vboMode = (sModelEditorState == kViewport2Only) ?
            VBOProxy::kDontUseVBO : VBOProxy::kUseVBOIfPossible;
    }
    
    
    
    
    
    GLfloat minZ;
    {
        Select* selector;
        NbPrimitivesVisitor nbPrimitives(seconds);
        rootNode->accept(nbPrimitives);
        
        if (boundingboxSelection) {
            
            selector = new GLPickingSelect(selectInfo);
            selector->processBoundingBox(rootNode, seconds);
        }
        else if (wireframeSelection) {
            if (nbPrimitives.numWires() < Config::openGLPickingWireframeThreshold()) 
                selector = new GLPickingSelect(selectInfo);
            else
                selector = new RasterSelect(selectInfo);
        
            selector->processEdges(rootNode, seconds, nbPrimitives.numWires(), vboMode);
        }
        else {
            if (nbPrimitives.numTriangles() < Config::openGLPickingSurfaceThreshold())
                selector = new GLPickingSelect(selectInfo);
            else
                selector = new RasterSelect(selectInfo);
            selector->processTriangles(rootNode, seconds, nbPrimitives.numTriangles(), vboMode);
        }
        selector->end();
        minZ = selector->minZ();
        delete selector;
    }
    bool selected = (minZ <= 1.0f);
    if ( selected ) {
        
        {
            {
                {
                    break;
                }
                else
                {
                }
            }
        }        
        MPoint worldSpaceselectionPoint =
 
            getPointAtDepth(selectInfo, minZ);
            selectionItem,
            worldSpaceselectionPoint,
            selectionList, worldSpaceSelectPts,
            mask, false );
    }
    return selected;
}
{
    
    InitializeGLFT();
    
        return false;
    }
    
    
    ShapeNode* node = (ShapeNode*)surfaceShape();
    const SubNode::Ptr rootNode = node->getCachedGeometry();
    if (!rootNode) return false;
    unsigned int vpx, vpy, vpw, vph;
    double w_over_two = vpw * 0.5;
    double h_over_two = vph * 0.5;
    double vpoff_x = w_over_two + vpx;
    double vpoff_y = h_over_two + vpy;
    ndcToPort(0,0) = w_over_two;
    ndcToPort(1,1) = h_over_two;
    ndcToPort(2,2) = 0.5;
    ndcToPort(3,0) = vpoff_x;
    ndcToPort(3,1) = vpoff_y;
    ndcToPort(3,2) = 0.5;
    
    const MMatrix localToNDC  = modelViewMatrix * projMatrix;
 
    const MMatrix localToPort = localToNDC * ndcToPort;
 
    Frustum frustum(localToNDC.
inverse());
    
    SnapTraversalState state(
        frustum, seconds, localToPort, inclusiveMatrix, snapInfo);
    rootNode->accept(visitor);
    return state.selected();
}
{
    addExternalContentForFileAttr(table, aCacheFileName);
}
{
    setExternalContentForFileAttr(aCacheFileName, table);
}
}