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 */