- Main Page
- Related Pages
- Modules
- Classes
- Examples

# D3DResourceManager.cpp

    //-
    // ==========================================================================
    // Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
    //
    // Use of this software is subject to the terms of the Autodesk
    // license agreement provided at the time of installation or download,
    // or which otherwise accompanies this software in either electronic
    // or hard copy form.
    // ==========================================================================
    //+
    #if defined(D3D9_SUPPORTED)

    #pragma warning (disable:4239)
    #include <stdio.h>

    #include <D3DResourceManager.h>

    #include <maya/MGlobal.h>
    #include <maya/MString.h>
    #include <maya/MFnCamera.h>
    #include <maya/MAngle.h>
    #include <maya/MPoint.h>
    #include <maya/MVector.h>
    #include <maya/MItDag.h>
    #include <maya/MMatrix.h>
    #include <maya/MDagPath.h>
    #include <maya/MFnDagNode.h>
    #include <maya/MBoundingBox.h>
    #include <maya/MNodeMessage.h> // For monitor geometry list
    #include <maya/MPlug.h>
    #include <maya/MPlugArray.h>
    #include <maya/MFnLight.h>
    #include <maya/MFnSpotLight.h>
    #include <maya/MColor.h>
    #include <maya/MFloatMatrix.h>

    //
    // Monitors on Maya scene graph
    //

    // Handle node dirty changes
    void geometryDirtyCallback( void* clientData )
    {
        GeometryItem *item = (GeometryItem *)clientData;
        if (item)
        {
            MMessage::removeCallback( item->m_objectDirtyMonitor );
            item->m_objectDirtyMonitor = 0;
            item->m_objectPath = MDagPath(); // Assign in valid dag path to mark as "bad"
        }
    }

    // Handle node attr change
    void geomteryChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData)
    {
        GeometryItem *item = (GeometryItem *)clientData;
        if (item)
        {
            MMessage::removeCallback( item->m_objectChangeMonitor );
            item->m_objectChangeMonitor = 0;
            item->m_objectPath = MDagPath(); // Assign in valid dag path to mark as "bad"
        }
    }
    void textureChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData)
    {
        TextureItem *item = (TextureItem *)clientData;
        if (item)
        {
            MMessage::removeCallback( item->m_objectChangeMonitor );
            item->m_objectChangeMonitor = 0;
            item->m_mayaNode = MObject::kNullObj; // Assign in valid dag path to mark as "bad"
        }
    }

    // Handle node delete
    void geometryDeleteCallback( MObject &node,
                            MDGModifier& modifier,
                            void* clientData )
    {
        GeometryItem *item = (GeometryItem *)clientData;
        if (item)
        {
            MMessage::removeCallback( item->m_objectDeleteMonitor );
            item->m_objectDeleteMonitor = 0;
            item->m_objectPath = MDagPath(); // Assign in valid dag path to mark as "bad"
        }
    }

    void textureDeleteCallback( MObject &node,
                            MDGModifier& modifier,
                            void* clientData )
    {
        TextureItem *item = (TextureItem *)clientData;
        if (item)
        {
            MMessage::removeCallback( item->m_objectDeleteMonitor );
            item->m_objectDeleteMonitor = 0;
            item->m_mayaNode = MObject::kNullObj; // Assign in valid dag path to mark as "bad"
        }
    }

    D3DResourceManager::D3DResourceManager()
    {
        // All lights are off
        m_numberLightsEnabled = 0;

        initializeDefaultCamera();
    }

    /* virtual */
    D3DResourceManager::~D3DResourceManager()
    {
        const bool onlyInvalidItems = false;
        clearResources(onlyInvalidItems, true);
    }

    void
    D3DResourceManager::initializeDefaultCamera()
    {
        // Set the default camera being 10 up and 10 back, with Y-up (to match Maya).
        m_camera.m_vEyePt = D3DXVECTOR3( 0.0f, 10.0f, -10.0f );
        m_camera.m_vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
        m_camera.m_vUpVec = D3DXVECTOR3 ( 0.0f, 1.0f, 0.0f );

        // Set up default clip planes, and FOV to match Maya's
        m_camera.m_FieldOfView = 45.0f;
        m_camera.m_nearClip = 0.1f;
        m_camera.m_farClip = 1000.0f;
    }

    bool
    D3DResourceManager::translateCamera( const MDagPath &cameraPath )
    //
    // Description:
    //      Translate Maya's camera
    //
    {
        bool translatedCamera = false;
        if (cameraPath.isValid())
        {
            MStatus status;
            MFnCamera camera (cameraPath, &status);
            if ( !status ) {
                status.perror("MFnCamera constructor");
            }
            else
            {
                translatedCamera = true;

                MPoint eyePoint = camera.eyePoint( MSpace::kWorld );
                MPoint lookAtPt = camera.centerOfInterestPoint( MSpace::kWorld );
                MVector upDirection = camera.upDirection ( MSpace::kWorld );
                MFloatMatrix projMatrix = camera.projectionMatrix();

                double horizontalFieldOfView = MAngle( /* camera.verticalFieldOfView() / */ camera.horizontalFieldOfView()
                    ).asDegrees();
                double nearClippingPlane = camera.nearClippingPlane();
                double farClippingPlane = camera.farClippingPlane();

                // Convert API values to internal native storage.
                //
                m_camera.m_vEyePt = D3DXVECTOR3((float)eyePoint.x, (float)eyePoint.y, (float)eyePoint.z);
                m_camera.m_vLookatPt = D3DXVECTOR3((float)lookAtPt.x, (float)lookAtPt.y, (float)lookAtPt.z);
                m_camera.m_vUpVec = D3DXVECTOR3((float)upDirection.x, (float)upDirection.y, (float)upDirection.z);
                m_camera.m_FieldOfView = (float)horizontalFieldOfView;
                m_camera.m_nearClip = (float)nearClippingPlane;
                m_camera.m_farClip = (float)farClippingPlane;
                m_camera.m_isOrtho = camera.isOrtho();
            }
        }
        else
        {
            initializeDefaultCamera();
        }
        return translatedCamera;
    }

    void
    D3DResourceManager::enableLights( bool val, LPDIRECT3DDEVICE9 D3D )
    {
        unsigned i;
        for (i=0; i<m_numberLightsEnabled; i++)
        {
            D3D->LightEnable( i, val);
        }
    }

    bool D3DResourceManager::cleanupLighting(LPDIRECT3DDEVICE9 D3D)
    {
        unsigned int i=0;
        for (i=0; i<m_numberLightsEnabled; i++)
        {
            D3D->LightEnable( i, false);
        }

        LightItemList::const_iterator it, end_it;
        end_it = m_lightItemList.end();
        for (it = m_lightItemList.begin(); it != end_it;  it++)
        {
            LightItem *item = *it;
            if (item)
            {
                delete item;
            }
        }
        m_lightItemList.clear();

        return true;
    }

    bool D3DResourceManager::setupLighting(LPDIRECT3DDEVICE9 D3D)
    //
    // Description:
    //      Set up lighting / materials.
    //
    {

        // Set up Maya lights:
        // Nasty, need to scan for lights
        MStatus status;

        MItDag dagIterator( MItDag::kDepthFirst, MFn::kLight, &status );
        MDagPath lightPath;

        for (unsigned int i=0; i<8; i++)
        {
            D3D->LightEnable( i, false);
        }
        m_numberLightsEnabled = 0;

        HRESULT hr;
        for (; !dagIterator.isDone(); dagIterator.next())
        {
            if ( !dagIterator.getPath(lightPath) )
                continue;

            LightItem *lightItem = new LightItem;
            if (!lightItem)
                break;

            lightItem->m_objectDeleteMonitor = NULL;
            lightItem->m_objectDirtyMonitor = NULL;
            ZeroMemory(&(lightItem->m_lightDesc), sizeof(lightItem->m_lightDesc));

            D3DLIGHT9 *d3dLight = &(lightItem->m_lightDesc);
            d3dLight->Range = 10000.0f;
            d3dLight->Falloff = 0.0f;
            d3dLight->Diffuse.a = 1.0f;
            d3dLight->Ambient.a = 1.0f;
            d3dLight->Specular.a = 1.0f;
            d3dLight->Attenuation0 = 0.0f;
            d3dLight->Attenuation1 = 0.0f;
            d3dLight->Attenuation2 = 0.0f;

            // This code doesn't do all of the light attributes, but the
            // general ones are pretty much supported.
            //
            MFnLight    fnLight( lightPath );
            if ( lightPath.hasFn(MFn::kAmbientLight))
            {
                MColor      colorVal = fnLight.color();
                float intensity = fnLight.intensity();

                d3dLight->Type = D3DLIGHT_POINT;
                d3dLight->Ambient.r = colorVal.r * intensity;
                d3dLight->Ambient.g = colorVal.g * intensity;
                d3dLight->Ambient.b = colorVal.b * intensity;
                d3dLight->Specular.r = 0.0f;
                d3dLight->Specular.g = 0.0f;
                d3dLight->Specular.b = 0.0f;
                d3dLight->Diffuse.r = d3dLight->Ambient.r;
                d3dLight->Diffuse.g = d3dLight->Ambient.g;
                d3dLight->Diffuse.b = d3dLight->Ambient.b;
                d3dLight->Attenuation0 = 1.0;
            }
            else if (lightPath.hasFn(MFn::kDirectionalLight) )
            {
                MColor      colorVal = fnLight.color();
                float intensity = fnLight.intensity();

                d3dLight->Type = D3DLIGHT_DIRECTIONAL;
                d3dLight->Diffuse.r = colorVal.r * intensity;
                d3dLight->Diffuse.g = colorVal.g * intensity;
                d3dLight->Diffuse.b = colorVal.b * intensity;
                d3dLight->Specular.r = d3dLight->Diffuse.r;
                d3dLight->Specular.g = d3dLight->Diffuse.g;
                d3dLight->Specular.b = d3dLight->Diffuse.b;
                d3dLight->Ambient.r = 0.0f;
                d3dLight->Ambient.g = 0.0f;
                d3dLight->Ambient.b = 0.0f;
            }
            else if (lightPath.hasFn(MFn::kPointLight))
            {
                d3dLight->Type = D3DLIGHT_POINT;

                MColor      colorVal = fnLight.color();
                float intensity = fnLight.intensity();

                d3dLight->Type = D3DLIGHT_POINT;
                d3dLight->Diffuse.r = colorVal.r * intensity;
                d3dLight->Diffuse.g = colorVal.g * intensity;
                d3dLight->Diffuse.b = colorVal.b * intensity;
                d3dLight->Specular.r = d3dLight->Diffuse.r;
                d3dLight->Specular.g = d3dLight->Diffuse.g;
                d3dLight->Specular.b = d3dLight->Diffuse.b;
                d3dLight->Ambient.r = 0.0f;
                d3dLight->Ambient.g = 0.0f;
                d3dLight->Ambient.b = 0.0f;
                d3dLight->Falloff = 0;
                // Should set attenuation based on "Decay Rate" attrib on light. TO ADD
                d3dLight->Attenuation0 = 1.0;
                d3dLight->Attenuation1 = 0.0f;
                d3dLight->Attenuation2 = 0.0f;
            }
            else if (lightPath.hasFn(MFn::kSpotLight))
            {
                d3dLight->Type = D3DLIGHT_SPOT;

                MColor      colorVal = fnLight.color();
                float intensity = fnLight.intensity();

                d3dLight->Type = D3DLIGHT_SPOT;
                d3dLight->Diffuse.r = colorVal.r * intensity;
                d3dLight->Diffuse.g = colorVal.g * intensity;
                d3dLight->Diffuse.b = colorVal.b * intensity;
                d3dLight->Specular = d3dLight->Diffuse;
                d3dLight->Ambient.r = 0.0f;
                d3dLight->Ambient.g = 0.0f;
                d3dLight->Ambient.b = 0.0f;

                MFnSpotLight fnSpotLight( lightPath );
                // Differs from OpenGL in that we don't want half the angle (divide by 2)
                // in our setup.
                d3dLight->Phi = (float) (fnSpotLight.coneAngle() ) +
                                (float) (fnSpotLight.penumbraAngle() );
                d3dLight->Theta = d3dLight->Phi - (float) (fnSpotLight.penumbraAngle() );

                // Should set attenuation based on "Decay Rate" attrib on light. TO ADD
                d3dLight->Attenuation0 = 1.0;
                float dropOffVal = (float) fnSpotLight.dropOff() / 1000.0f;
                d3dLight->Attenuation1 = dropOffVal;
                d3dLight->Falloff = 1.0f;
            }
            else
            {
                delete lightItem;
                lightItem = NULL;
                continue;
            }

            // Setup common position and direction information.
            if (lightItem && d3dLight)
            {
                MTransformationMatrix worldMatrix = lightPath.inclusiveMatrix();

                MVector translation = worldMatrix.translation( MSpace::kWorld );
                MVector direction( 0.0, 0.0, -1.0 );
                direction *= worldMatrix.asMatrix();
                direction.normalize();
                d3dLight->Position.x = (float)translation.x;
                d3dLight->Position.y = (float)translation.y;
                d3dLight->Position.z = (float)translation.z;
                d3dLight->Direction.x = (float)direction.x;
                d3dLight->Direction.y = (float)direction.y;
                d3dLight->Direction.z = (float)direction.z;
            }

            hr = D3D->SetLight( m_numberLightsEnabled, d3dLight);
            if (!SUCCEEDED(hr))
            {
                delete lightItem;
                lightItem = NULL;
                break;
            }
            hr = D3D->LightEnable(m_numberLightsEnabled, TRUE);
            if (!SUCCEEDED(hr))
            {
                delete lightItem;
                lightItem = NULL;
                break;
            }
            m_numberLightsEnabled++;

            // Only allow up to 8 lights to be built for now
            if (m_numberLightsEnabled >= 8)
                break;

            m_lightItemList.push_back( lightItem );
        }

        if (m_numberLightsEnabled == 0)
        {
            // Setup a headlight.
            D3DLIGHT9 Light;
            Light.Type = D3DLIGHT_DIRECTIONAL;
            Light.Specular.r = 1.0f; Light.Specular.g = 1.0f; Light.Specular.b = 1.0f; Light.Specular.a = 1.0f;
            Light.Diffuse.r = 1.0f; Light.Diffuse.g = 1.0f; Light.Diffuse.b = 1.0f; Light.Diffuse.a = 1.0f;
            Light.Ambient.r = 0.0f; Light.Ambient.g = 0.0f; Light.Ambient.b = 0.0f; Light.Ambient.a = 0.0f;
            Light.Range = 100000;
            Light.Falloff = 0;
            Light.Direction = m_camera.m_vLookatPt - m_camera.m_vEyePt;
            D3D->SetLight( 0, &Light);
            D3D->LightEnable( 0, true);

            // And a backlight.
            D3DLIGHT9 Light2;
            Light2.Type = D3DLIGHT_DIRECTIONAL;
            Light2.Specular.r = 1.0f; Light2.Specular.g = 1.0f; Light2.Specular.b = 1.0f; Light2.Specular.a = 1.0f;
            Light2.Diffuse.r = 1.0f; Light2.Diffuse.g = 1.0f; Light2.Diffuse.b = 1.0f; Light2.Diffuse.a = 1.0f;
            Light2.Ambient.r = 0.0f; Light2.Ambient.g = 0.0f; Light2.Ambient.b = 0.0f; Light2.Ambient.a = 0.0f;
            Light2.Range = 100000;
            Light2.Falloff = 0;
            Light2.Direction = m_camera.m_vEyePt - m_camera.m_vLookatPt;
            D3D->SetLight( 1, &Light2);
            D3D->LightEnable( 1, true);

            m_numberLightsEnabled = 2;
        }

        D3D->SetRenderState( D3DRS_LIGHTING, TRUE );

        // Make sure specular is on.
        D3D->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
        D3D->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
        D3D->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
        // Set lighting to local-viewer
        D3D->SetRenderState(D3DRS_LOCALVIEWER, TRUE);
        // Make sure to auto-normalize normals
        D3D->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );

        return true;
    }

    //
    // Get the geometry buffers for this bad boy
    //
    D3DGeometry* D3DResourceManager::getGeometry( const MDagPath& dagPath, LPDIRECT3DDEVICE9 D3D)
    {
        D3DGeometry* Geometry = NULL;

        // Look for a cached mesh ...
        //
        // Check to see if object is in the list, if not added a
        // new item and cache some geometry
        GeometryItem *itemFound = NULL;

        GeometryItemList::const_iterator it, end_it;
        end_it = m_geometryItemList.end();
        for (it = m_geometryItemList.begin(); it != end_it;  it++)
        {
            GeometryItem *item = *it;
            if (item && item->m_objectPath == dagPath)
            {
                itemFound = item;
            }
        }
        // Build a new item, and add it to the list
        if (!itemFound)
        {
            itemFound = new GeometryItem;
            itemFound->m_objectPath = dagPath;
            Geometry = itemFound->m_objectGeometry = new D3DGeometry();
            if (Geometry)
            {
                Geometry->Populate( dagPath, D3D);
            }

            MFnDagNode dagNode(dagPath);
            MObject &obj = (MObject &) dagNode.object();
            itemFound->m_objectDeleteMonitor =
                MNodeMessage::addNodeAboutToDeleteCallback( obj, geometryDeleteCallback, (void *)itemFound ); // Add callback for node deleted.
            // Don't get attr change messages during playback, so use node dirty also..sigh
            //itemFound->m_objectChangeMonitor =
            //  MNodeMessage::addAttributeChangedCallback( obj, geometryChangedCallback, (void *)itemFound); // Add callback for attr changed.
            itemFound->m_objectChangeMonitor = 0;
            itemFound->m_objectChangeMonitor =
                MNodeMessage::addNodeDirtyCallback( obj, geometryDirtyCallback, (void *)itemFound); // Add callback for node changed.
            m_geometryItemList.push_back( itemFound );
        }
        else
        {
            Geometry = itemFound->m_objectGeometry;
        }

        // Create a new set of buffers for this mesh
        //
        return Geometry;
    }

    //
    // Get the DirectX texture for a Maya texture node
    //
    D3DTexture* D3DResourceManager::getTexture( MObject& textureNode)
    {
        D3DTexture* Texture = NULL;

        // Look for a cached texture ...
        //
        // Check to see if object is in the list, if not added a
        // new item and cache some texture
        TextureItem *itemFound = NULL;

        TextureItemList::const_iterator it, end_it;
        end_it = m_textureItemList.end();
        for (it = m_textureItemList.begin(); it != end_it;  it++)
        {
            TextureItem *item = *it;
            if (item && item->m_mayaNode.object() == textureNode)
            {
                itemFound = item;
            }
        }
        // Build a new item, and add it to the list
        if (!itemFound)
        {
            itemFound = new TextureItem();
            itemFound->m_mayaNode = textureNode;
            Texture = itemFound->m_texture = new D3DTexture( textureNode);

            itemFound->m_objectDeleteMonitor =
                MNodeMessage::addNodeAboutToDeleteCallback( textureNode, textureDeleteCallback, (void *)itemFound ); // Add callback for node deleted.
            itemFound->m_objectChangeMonitor =
                MNodeMessage::addAttributeChangedCallback( textureNode, textureChangedCallback, (void *)itemFound); // Add callback for attr changed.

            m_textureItemList.push_back( itemFound );
        }
        else
        {
            Texture = itemFound->m_texture;
        }

        // Create a new set of buffers for this mesh
        //
        return Texture;
    }

    bool
    D3DResourceManager::initializeDefaultSurfaceEffect( const MString &effectsLocation, LPDIRECT3DDEVICE9 D3D,
                                                        const MString & effectName )
    //
    // Description:
    //      Initialize default surface effects found in a given directory.
    //
    {
        HRESULT hres;
        LPD3DXBUFFER pBufferErrors = NULL;

        // Shader flags for debugging
        DWORD dwShaderFlags = 0;
        #ifdef DEBUG_VS
        dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
        #endif
        #ifdef DEBUG_PS
        dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
        #endif

        ID3DXEffect* effect = NULL;

        MString effectLocation = effectsLocation + "\\" + effectName + ".fx";
        hres = D3DXCreateEffectFromFile( D3D,
            effectLocation.asChar(),
            NULL,
            NULL,
            dwShaderFlags,
            NULL,
            &effect,
            &pBufferErrors );
        if (FAILED(hres))
        {
            MGlobal::displayInfo("Failed to compile FX file: " + effectLocation);
            if (pBufferErrors)
            {
                const char *pCompilErrors = (const char*)pBufferErrors->GetBufferPointer();
                MGlobal::displayInfo(MString("Compiler errors:\n") + MString(pCompilErrors) );
            }
        }
        else
        {
            // Create a new effect item
            //
            MGlobal::displayInfo("Maya default pixel shader loaded: " + effectLocation);
            SurfaceEffectItem *pei = new SurfaceEffectItem;
            if (pei)
            {
                pei->fEffect = effect;
                pei->fName = effectName;

                m_SurfaceEffectItemList.push_back( pei );
            }
        }

        return (m_SurfaceEffectItemList.size() > 0);
    }

    bool
    D3DResourceManager::initializePostEffects( const MString &effectsLocation, LPDIRECT3DDEVICE9 D3D)
    //
    // Description:
    //      Initialize all effects found in a given directory.
    //
    {
        HRESULT hres;
        LPD3DXBUFFER pBufferErrors = NULL;

        // Shader flags for debugging
        DWORD dwShaderFlags = 0;
        #ifdef DEBUG_VS
        dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
        #endif
        #ifdef DEBUG_PS
        dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
        #endif

        // Should do a proper directory search for now it's just hard coded.
        MStringArray effectNames;
        effectNames.append("PostProcess_SobelFilter");
        effectNames.append("PostProcess_ToneMapFilter");
        effectNames.append("PostProcess_InvertFilter");

        for (unsigned int i=0; i<effectNames.length(); i++)
        {
            ID3DXEffect* effect = NULL;

            MString effectLocation = effectsLocation + "\\" + effectNames[i] + ".fx";
            hres = D3DXCreateEffectFromFile( D3D,
                                       effectLocation.asChar(),
                                       NULL,
                                       NULL,
                                       dwShaderFlags,
                                       NULL,
                                       &effect,
                                       &pBufferErrors );
            if (FAILED(hres))
            {
                MGlobal::displayInfo("Failed to compiler FX file" + effectLocation);
                if (pBufferErrors)
                {
                    const char *pCompilErrors = (const char*)pBufferErrors->GetBufferPointer();
                    MGlobal::displayInfo(MString("Compiler errors:\n") + MString(pCompilErrors) );
                }
            }
            else
            {
                // Create a new effect item
                //
                PostEffectItem *pei = new PostEffectItem;
                if (pei)
                {
                    pei->fEffect = effect;
                    pei->fName = effectNames[i];

                    m_PostEffectItemList.push_back( pei );
                }
            }
        }

        return (m_PostEffectItemList.size() > 0);
    }

    const MStringArray &
    D3DResourceManager::getListOfEnabledPostEffects()
    {
        // Find out which ones are enabled...
        // Should get via some UI interface. For now use Maya optionVars.
        //
        // e.g. optionVar -sv "D3D_EFFECTS_LIST" "PostProcess_ToneMapFilter" ;
        // e.g. optionVar -sv "D3D_EFFECTS_LIST" "PostProcess_ToneMapFilter,PostProcess_SobelFilter" ;
        // e.g. optionVar -sv "D3D_EFFECTS_LIST" "" ; // Clear the list
        m_EnabledPostEffectItemList.clear();

        const MString effectListVar("D3D_EFFECTS_LIST");
        //MString effectList("PostProcess_ToneMapFilter, PostProcess_SobelFilter");
        MString effectList;
        if (!MGlobal::getOptionVarValue(effectListVar, effectList))
        {
            // Create an option var if none previously existed.
            MGlobal::setOptionVarValue(effectListVar, effectList);
        }
        else
        {
            // Parse the effect list to get back a list of enabled effects
            // (in order). Note that there is not restriction on effect
            // list order, and duplicates are allowed.
            effectList.split(' ', m_EnabledPostEffectItemList);
        }

        return m_EnabledPostEffectItemList;
    }

    void
    D3DResourceManager::clearResources(bool onlyInvalidItems, bool clearShaders)
    {
        GeometryItemList::const_iterator git, end_git;
        end_git = m_geometryItemList.end();
        for (git = m_geometryItemList.begin(); git != end_git;  git++)
        {
            GeometryItem *item = *git;
            if (item)
            {
                if (!onlyInvalidItems || (onlyInvalidItems && !(item->m_objectPath.isValid() )))
                {
                    if (item->m_objectGeometry)
                    {
                        delete item->m_objectGeometry;
                        item->m_objectGeometry = NULL;
                    }
                    item->m_objectPath = MDagPath(); // Assign invalid dag path

                    // Kill the delete monitor
                    if (item->m_objectDeleteMonitor)
                    {
                        MMessage::removeCallback( item->m_objectDeleteMonitor );
                        item->m_objectDeleteMonitor = 0;
                    }
                    // Kill the attr changed monitor
                    if (item->m_objectChangeMonitor)
                    {
                        MMessage::removeCallback( item->m_objectChangeMonitor );
                        item->m_objectChangeMonitor = 0;
                    }
                    // Kill node dirty monitor
                    if (item->m_objectDirtyMonitor)
                    {
                        MMessage::removeCallback( item->m_objectDirtyMonitor );
                        item->m_objectDirtyMonitor = 0;
                    }
                }
            }
        }
        if (!onlyInvalidItems)
            m_geometryItemList.clear();

        TextureItemList::const_iterator tit, end_tit;
        end_tit = m_textureItemList.end();
        for (tit = m_textureItemList.begin(); tit != end_tit;  tit++)
        {
            TextureItem *item = *tit;
            if (item)
            {
                if (!onlyInvalidItems || (onlyInvalidItems && !(item->m_mayaNode.isValid() )))
                {
                    if (item->m_texture)
                    {
                        delete item->m_texture;
                        item->m_texture = NULL;
                    }

                    item->m_mayaNode = MObject::kNullObj;

                    // Kill the delete monitor
                    if (item->m_objectDeleteMonitor)
                    {
                        MMessage::removeCallback( item->m_objectDeleteMonitor );
                        item->m_objectDeleteMonitor = 0;
                    }
                    // Kill the attr changed monitor
                    if (item->m_objectChangeMonitor)
                    {
                        MMessage::removeCallback( item->m_objectChangeMonitor );
                        item->m_objectChangeMonitor = 0;
                    }
                }
            }
        }
        if (!onlyInvalidItems)
            m_textureItemList.clear();

        if (clearShaders)
        {
            // Clean up post effects list
            {
            PostEffectItemList::const_iterator eit, end_eit;
            end_eit = m_PostEffectItemList.end();
            for (eit = m_PostEffectItemList.begin(); eit != end_eit;  eit++)
            {
                PostEffectItem *item = *eit;
                if (item)
                {
                    if (item->fEffect)
                    {
                        item->fEffect->Release();
                        item->fEffect = NULL;
                    }
                    delete item;
                }
            }
            m_PostEffectItemList.clear();
            m_EnabledPostEffectItemList.clear();
        }

            // Clean up surface effects list
            {
                SurfaceEffectItemList::const_iterator eit, end_eit;
                end_eit = m_SurfaceEffectItemList.end();
                for (eit = m_SurfaceEffectItemList.begin(); eit != end_eit;  eit++)
                {
                    SurfaceEffectItem *item = *eit;
                    if (item)
                    {
                        if (item->fEffect)
                        {
                            item->fEffect->Release();
                            item->fEffect = NULL;
                        }
                        delete item;
                    }
                }
                m_SurfaceEffectItemList.clear();
            }
        }
    }

    #endif /* D3D9_SUPPORTED */