#include <stdio.h>
#include <iostream>
#include <D3DViewportRenderer.h>
#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MRenderingInfo.h>
#include <maya/MRenderTarget.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/MFnMesh.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MBoundingBox.h>
#include <maya/MImage.h>
#include <maya/MDrawTraversal.h>
#include <maya/MGeometryManager.h>
#include <maya/MGeometry.h>
#include <maya/MGeometryData.h>
#include <maya/MGeometryPrimitive.h>
#include <maya/MNodeMessage.h> 
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MFnSet.h>
#include <maya/MFnNumericData.h>
#include <maya/MItDependencyGraph.h>
#include <maya/MMatrix.h>
#include <stdio.h>
#include <maya/MFnLight.h>
#include <maya/MFnSpotLight.h>
#include <maya/MPxHardwareShader.h>
#include <maya/MRenderProfile.h>
#if defined(D3D9_SUPPORTED)
struct ScreenSpaceVertex
{
    D3DXVECTOR4 position; 
    D3DXVECTOR2 texCoord; 
    static const DWORD FVF;
};
const DWORD ScreenSpaceVertex::FVF = D3DFVF_XYZRHW | D3DFVF_TEX1;
#endif
D3DViewportRenderer::D3DViewportRenderer()
:       MViewportRenderer("D3DViewportRenderer")
{
        
        fUIName.set( "Direct3D Renderer");
        
        fRenderingOverride = MViewportRenderer::kOverrideAllDrawing;
        
        m_API = MViewportRenderer::kDirect3D;
        m_Version = 9.0f;
        
        m_renderWidth = 640;
        m_renderHeight = 480;
#if defined(D3D9_SUPPORTED)
        m_hWnd = 0;
        m_pD3D = 0;
        m_pD3DDevice = 0;
        m_pTextureOutput = 0;
        m_pTextureOutputSurface = 0;
        
        m_readBackBuffer.create(m_renderWidth, m_renderHeight, 4);
        m_readBackBuffer.setRGBA( false );
        m_pBoundsBuffer = 0;
        m_pGeometry = 0;
        m_wantFloatingPointTargets = false;
        m_pTextureInterm = 0;
        m_pTextureIntermSurface = 0;
        m_pTexturePost = 0;
        m_pDepthStencilSurface = 0;
        m_SystemMemorySurface = 0;
        m_requireDepthStencilReadback = false;
#endif
}
D3DViewportRenderer::~D3DViewportRenderer()
{
        uninitialize();
}
LRESULT CALLBACK D3DWindowProc( HWND   hWnd, 
                                                         UINT   msg, 
                                                         WPARAM wParam, 
                                                         LPARAM lParam )
{
    switch( msg )
        {
                case WM_CLOSE:
                {
                        
                }
                break;
        case WM_DESTROY:
                {
            
                }
        break;
                
                default:
                {
                        return DefWindowProc( hWnd, msg, wParam, lParam );
                }
                break;
        }
        return 0;
}
#if defined(D3D9_SUPPORTED)
bool
D3DViewportRenderer::buildRenderTargets(unsigned int width, unsigned int height)
{
        HRESULT hr = -1;
        
        if (width == m_renderWidth &&
                height == m_renderHeight &&
                m_pTextureInterm && 
                m_pTextureOutput &&
                m_pTexturePost)
        {
                return true;
        }
        
        m_renderWidth = width;
        m_renderHeight = height;
        
        
        
        
        if (m_pTextureInterm)
        {
                m_pTextureInterm->Release();
                m_pTextureInterm = NULL;
        }
        if (m_pTextureIntermSurface)
        {
                m_pTextureIntermSurface->Release();
                m_pTextureIntermSurface = NULL;
        }
        if (!m_pTextureInterm)
        {
                hr = D3DXCreateTexture( m_pD3DDevice, 
                        m_renderWidth, 
                        m_renderHeight, 
                        1, 
                        D3DUSAGE_RENDERTARGET, 
                        m_intermediateTargetFormat, 
                        D3DPOOL_DEFAULT, 
                        &m_pTextureInterm );
                
                
                m_intermediateTargetFormat = m_outputTargetFormat;
                if ( FAILED(hr) )
                {
                        hr = D3DXCreateTexture( m_pD3DDevice, 
                                m_renderWidth, 
                                m_renderHeight, 
                                1, 
                                D3DUSAGE_RENDERTARGET, 
                                m_intermediateTargetFormat, 
                                D3DPOOL_DEFAULT, 
                                &m_pTextureInterm );
                }
                if ( FAILED(hr) )
                {
                        MGlobal::displayWarning("Direct3D renderer : Failed to create intermediate texture for offscreen render target.");
                        return false;
                }
        }
        if (m_pTextureInterm)
        {
                hr = m_pTextureInterm->GetSurfaceLevel( 0, &m_pTextureIntermSurface );
        }
        if ( FAILED(hr) )
        {
                MGlobal::displayWarning("Direct3D renderer : Failed to get surface for off-screen render target.");
                return false;
        }
        
        
        
        
        
        
        if (m_wantFloatingPointTargets)
        {
                if (m_pTextureOutput)
                {
                        m_pTextureOutput->Release();
                        m_pTextureOutput = NULL;
                }
                if (m_pTextureOutputSurface)
                {
                        m_pTextureOutputSurface->Release();
                        m_pTextureOutputSurface = NULL;
                }
                if (!m_pTextureOutput)
                {
                        
                        hr = D3DXCreateTexture( m_pD3DDevice, 
                                m_renderWidth, 
                                m_renderHeight, 
                                1, 
                                D3DUSAGE_RENDERTARGET, 
                                m_outputTargetFormat, 
                                D3DPOOL_DEFAULT, 
                                &m_pTextureOutput );
                        if ( FAILED(hr) )
                        {
                                MGlobal::displayWarning("Direct3D renderer : Failed to create texture for offscreen render target.");
                                return false;
                        }
                }
                
                
                if (m_pTextureOutput)
                {
                        hr = m_pTextureOutput->GetSurfaceLevel( 0, &m_pTextureOutputSurface );
                }
                if ( FAILED(hr) )
                {
                        MGlobal::displayWarning("Direct3D renderer : Failed to get surface for off-screen render target.");
                        return false;
                }
        }
        else
        {
                m_pTextureOutput = m_pTextureInterm;
                m_pTextureOutputSurface = m_pTextureIntermSurface;
        }
        
        
        
        if (m_pTexturePost)
        {
                m_pTexturePost->Release();
                m_pTexturePost = NULL;
        }
        if (!m_pTexturePost)
        {
                hr = D3DXCreateTexture( m_pD3DDevice, 
                        m_renderWidth, 
                        m_renderHeight, 
                        1, 
                        D3DUSAGE_RENDERTARGET, 
                        m_intermediateTargetFormat, 
                        D3DPOOL_DEFAULT, 
                        &m_pTexturePost );
                if ( FAILED(hr) )
                {
                        MGlobal::displayWarning("Direct3D renderer : Failed to create texture for offscreen post-processing.");
                        return false;
                }
        }
        
        if (m_SystemMemorySurface)
        {
                m_SystemMemorySurface->Release();
                m_SystemMemorySurface = 0;
        }
        if (!m_SystemMemorySurface)
        {
                hr = m_pD3DDevice->CreateOffscreenPlainSurface( m_renderWidth,
                        m_renderHeight, m_outputTargetFormat, D3DPOOL_SYSTEMMEM,
                        &m_SystemMemorySurface, NULL );
                if (FAILED(hr))
                {
                        MGlobal::displayWarning("Direct3D renderer : Failed to create system memory readback surface.");
                        return false;
                }
        }
        return (m_pTextureOutput && m_pTextureOutputSurface && m_pTextureInterm && 
                        m_pTextureIntermSurface && m_pTexturePost && m_SystemMemorySurface);
#if defined(DEPTH_REQUIRED)
        
        if (m_pDepthStencilSurface)
        {
                m_pDepthStencilSurface->Release();
                m_pDepthStencilSurface = 0;
        }
        if (m_requireDepthStencilReadback && !m_pDepthStencilSurface)
        {
                hr = m_pD3DDevice->CreateDepthStencilSurface( 
                                                m_renderWidth, m_renderHeight, m_depthStencilFormat, D3DMULTISAMPLE_NONE, 
                                                0, FALSE, 
                                                &m_pDepthStencilSurface, NULL );
                if (FAILED(hr))
                {
                        MGlobal::displayWarning("Direct3D renderer : Failed to create depth/stencil surface. Depth read back will not be available.");
                }
        }
#endif
}
#endif
   
MStatus 
D3DViewportRenderer::initialize()
{
        MStatus status = MStatus::kFailure;
#if defined(D3D9_SUPPORTED)
        
        
        MString wantFloatingPoint("D3D_RENDERER_FLOAT_TARGETS");
        int value;
        if (!MGlobal::getOptionVarValue(wantFloatingPoint, value))
        {
                m_wantFloatingPointTargets = true;
        }
        else
        {
                m_wantFloatingPointTargets = (value != 0);
        }
        m_wantFloatingPointTargets = false;
        
        
        if (!m_hWnd)
        {
                
                WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, (WNDPROC) D3DWindowProc, 0L, 0L, 
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                                          "D3D Viewport Renderer", NULL };
                if (RegisterClassEx( &wc ))
                {
                        m_hWnd = CreateWindow( "D3D Viewport Renderer", "D3D Viewport Renderer", 
                                                                        WS_OVERLAPPEDWINDOW, 0, 0, m_renderWidth, m_renderHeight,
                                                                        NULL, NULL, wc.hInstance, NULL );
                }
        }
        
        if (m_hWnd)
        {
                if (!m_pD3D)
                        m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
        }
        HRESULT hr;
        
        if (m_wantFloatingPointTargets)
        {
                m_intermediateTargetFormat = D3DFMT_A16B16G16R16F;
        }
        else
        {
                m_intermediateTargetFormat = D3DFMT_A8R8G8B8;
        }
        
        m_outputTargetFormat = D3DFMT_A8R8G8B8;
        if (m_requireDepthStencilReadback)
        {
                m_depthStencilFormat = D3DFMT_D32; 
        }
        else
                m_depthStencilFormat = D3DFMT_D24S8; 
        
        if (m_pD3D)
        {
                if (!m_pD3DDevice)
                {
                        D3DPRESENT_PARAMETERS d3dpp; 
                        ZeroMemory( &d3dpp, sizeof(d3dpp) );
                        d3dpp.BackBufferFormat           = m_outputTargetFormat;
                        d3dpp.Windowed                           = TRUE; 
                        d3dpp.BackBufferWidth        = 1920; 
                        d3dpp.BackBufferHeight       = 1680;
                        d3dpp.SwapEffect                         = D3DSWAPEFFECT_DISCARD;
                        d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_IMMEDIATE;
                        d3dpp.EnableAutoDepthStencil = TRUE;
                        d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; 
                        
                        
                        hr = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd,
                                                                                D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE,
                                                                                &d3dpp, &m_pD3DDevice );
                        
                        
                        if (FAILED(hr))
                        {
                                hr = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd,
                                                                                D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE,
                                                                                &d3dpp, &m_pD3DDevice );
                        }
                        if ( FAILED(hr) )
                                m_pD3DDevice = 0;
                }
        }
        
        if (m_pD3DDevice)
        {
                m_pD3DDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
                bool builtRenderTargets = buildRenderTargets(640, 480); 
                if (builtRenderTargets)
                {
                        MString shaderLocation(MString(getenv("MAYA_LOCATION")) + MString("\\bin\\HLSL"));
                        
                        bool loaded = m_resourceManager.initializePostEffects( shaderLocation, m_pD3DDevice );
                        
                        const MString defaultSurfaceEffect("Maya_fixedFunction");
                        loaded = m_resourceManager.initializeDefaultSurfaceEffect( shaderLocation, m_pD3DDevice, defaultSurfaceEffect);
                        
                        
                        if (m_hWnd && m_pD3D && m_pD3DDevice && m_pTextureOutput && m_pTextureOutputSurface && 
                                m_pTextureInterm && m_pTextureIntermSurface )
                        {
                                status = MStatus::kSuccess;
                        }
                }
        }
        
        if (status != MStatus::kSuccess)
        {
                uninitialize();
        }
#else
        status = MStatus::kSuccess;
#endif
        return status;
}
   
MStatus 
D3DViewportRenderer::uninitialize()
{       
#if defined(D3D9_SUPPORTED)
        
        
        
        if ( m_pTextureOutput )
        {
                if (m_pTextureOutput != m_pTextureInterm)               
                        m_pTextureOutput->Release();
                m_pTextureOutput = 0;
        }
        if ( m_pTextureOutputSurface )
        {
                if (m_pTextureOutputSurface != m_pTextureIntermSurface)
                        m_pTextureOutputSurface->Release();
                m_pTextureOutputSurface = 0;
        }
        if ( m_pTextureInterm )
        {
        m_pTextureInterm->Release();
                m_pTextureInterm = 0;
        }
        if ( m_pTextureIntermSurface )
        {
        m_pTextureIntermSurface->Release();
                m_pTextureIntermSurface = 0;
        }
        if ( m_pTexturePost )
        {
        m_pTexturePost->Release();
                m_pTexturePost = 0;
        }
        if ( m_SystemMemorySurface )
        {
                m_SystemMemorySurface->Release();
                m_SystemMemorySurface = 0;
        }
        if (m_pDepthStencilSurface)
        {
                m_pDepthStencilSurface->Release();
                m_pDepthStencilSurface = 0;
        }
        if ( m_pBoundsBuffer != NULL )
        {
        m_pBoundsBuffer->Release(); 
                m_pBoundsBuffer = 0;
        }
        if (m_pGeometry)
        {
                m_pGeometry->Release();
                m_pGeometry = 0;
        }
        m_resourceManager.clearResources(false, true); 
    if ( m_pD3DDevice )
        {
        m_pD3DDevice->Release();
                m_pD3DDevice = 0;
        }
    if ( m_pD3D )
        {
        m_pD3D->Release();      
                m_pD3D = 0;
        }
        
        
        if (m_hWnd)
        {
                ReleaseDC( m_hWnd, GetDC(m_hWnd ));
                DestroyWindow(m_hWnd);
                UnregisterClass("D3D Viewport Renderer", GetModuleHandle(NULL));
                m_hWnd = 0;
        }
#endif
        return MStatus::kSuccess;
}
 
MStatus 
D3DViewportRenderer::render(const MRenderingInfo &renderInfo)
{
        MStatus status;
        
        
#if defined(D3D9_SUPPORTED)
        const MRenderTarget & target = renderInfo.renderTarget();
        unsigned int currentWidth = target.width();
        unsigned int currentHeight = target.height();
        
        if (!buildRenderTargets(currentWidth, currentHeight))
                return MStatus::kFailure;
#endif
        
        
        
        
#if defined(D3D9_SUPPORTED)
        MViewportRenderer::RenderingAPI targetAPI = renderInfo.renderingAPI();
        
        
        
        
        const MDagPath &cameraPath = renderInfo.cameraPath();
        if ( m_resourceManager.translateCamera( cameraPath ) )
        {
                if ( renderToTarget( renderInfo ) )
                {
                        
                        
                        
                        
                        bool requireReadBack = (targetAPI != MViewportRenderer::kDirect3D);
                        if ( requireReadBack )
                        {
                                if (readFromTargetToSystemMemory())
                                {
                                        
                                        if (targetAPI == MViewportRenderer::kOpenGL)
                                        {
                                                
                                                
                                                unsigned int targetW = target.width();
                                                unsigned int targetH = target.height();                                                 
                                                unsigned int m_readBackBufferWidth, m_readBackBufferHeight;
                                                m_readBackBuffer.getSize(m_readBackBufferWidth, m_readBackBufferHeight);
                                                if (m_readBackBufferWidth && m_readBackBufferHeight)
                                                {
                                                        if (m_readBackBufferWidth > targetW ||
                                                                m_readBackBufferHeight > targetH)
                                                        {
                                                                m_readBackBuffer.resize(targetW, targetH);
                                                                target.writeColorBuffer( m_readBackBuffer, 0, 0 );
                                                        }
                                                        else
                                                        {
                                                                target.writeColorBuffer( m_readBackBuffer, 
                                                                        (short)(targetW/2 - m_readBackBufferWidth/2),
                                                                        (short)(targetH/2 - m_readBackBufferHeight/2));
                                                        }
                                                        status = MStatus::kSuccess;
                                                }
                                        }
                                        
                                        else
                                        {
                                                
                                                status = MStatus::kFailure;
                                        }
                                }
                                else
                                        status = MStatus::kFailure;                             
                        }
                        
                        
                        else 
                        {
                                status = MStatus::kSuccess;
                        }
                }
                else
                        status = MStatus::kFailure;
        }
        else
        {
                MGlobal::displayWarning("Direct3D renderer : No valid render camera to use. Nothing rendered\n");
                status = MStatus::kFailure;
        }
#else
                status = MStatus::kSuccess;
#endif
        return status;
}
 
bool    
D3DViewportRenderer::nativelySupports( MViewportRenderer::RenderingAPI api, 
                                                                           float version )
{
        
        return ((api == m_API) && (version == m_Version) );
}
 bool      
D3DViewportRenderer::override( MViewportRenderer::RenderingOverride override )
{
        
        return (override == fRenderingOverride);
}
#if defined(D3D9_SUPPORTED)
bool                                    
D3DViewportRenderer::translateCamera( const MRenderingInfo &renderInfo )
{
        const MDagPath &cameraPath = renderInfo.cameraPath();
        if (cameraPath.isValid())
                return m_resourceManager.translateCamera( cameraPath );
        else
                return false;
}
bool D3DViewportRenderer::drawCube(float minVal[3], float maxVal[3], bool filled, bool useDummyGeometry,
                                                                   float color[3], LPDIRECT3DVERTEXBUFFER9 buffer )
{
        if (!m_pD3DDevice)
                return false;
        D3DMATERIAL9 Material;
        Material.Emissive.r = color[0]; 
        Material.Emissive.g = color[1]; 
        Material.Emissive.b = color[2]; 
        Material.Emissive.a = 1.0f; 
        Material.Ambient.r = color[0]; 
        Material.Ambient.g = color[1]; 
        Material.Ambient.b = color[2]; 
        Material.Ambient.a = 1.0f; 
        m_pD3DDevice->SetMaterial( &Material);
        m_pD3DDevice->LightEnable( 0, false);
        m_pD3DDevice->LightEnable( 1, false);
        m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
        
        
        if (!filled)
        {
                m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
        }
        else
        {
                m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );          
        }
        m_pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
        m_pD3DDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
        
        if (!m_pGeometry)
        {
                if (useDummyGeometry)
                {
                        
                        
                        
                }
        }
        if (useDummyGeometry && m_pGeometry)
        {
                m_pGeometry->DrawSubset(0);
                return true;
        }
        
        
        LPDIRECT3DVERTEXBUFFER9 bufferToFill = m_pBoundsBuffer;
        if (!bufferToFill)
        {
                m_pD3DDevice->CreateVertexBuffer( 24*sizeof(PlainVertex),0, PlainVertex::FVF_Flags,
                                                                                        D3DPOOL_DEFAULT, &bufferToFill, NULL );
        }
        if (!bufferToFill)
        {
                return false;
        }
        
        PlainVertex cube[] =
        {
                { minVal[0], maxVal[1], minVal[2]},
                { maxVal[0], maxVal[1], minVal[2]},
                { minVal[0], minVal[1], minVal[2] },
                { maxVal[0], minVal[1], minVal[2] },
                {minVal[0], maxVal[1], maxVal[2] },
                {minVal[0],minVal[1], maxVal[2] },
                { maxVal[0], maxVal[1], maxVal[2] },
                { maxVal[0],minVal[1], maxVal[2] },
                {minVal[0], maxVal[1], maxVal[2] },
                { maxVal[0], maxVal[1], maxVal[2] },
                {minVal[0], maxVal[1],minVal[2] },
                { maxVal[0], maxVal[1],minVal[2] },
                {minVal[0],minVal[1], maxVal[2] },
                {minVal[0],minVal[1],minVal[2] },
                { maxVal[0],minVal[1], maxVal[2] },
                { maxVal[0],minVal[1],minVal[2] },
                { maxVal[0], maxVal[1],minVal[2] },
                { maxVal[0], maxVal[1], maxVal[2] },
                { maxVal[0],minVal[1],minVal[2] },
                { maxVal[0],minVal[1], maxVal[2] },
                {minVal[0], maxVal[1],minVal[2] },
                {minVal[0],minVal[1],minVal[2] },
                {minVal[0], maxVal[1], maxVal[2] },
                {minVal[0],minVal[1], maxVal[2] }
        };
        void *pVertices = NULL;
        
        
        
        bufferToFill->Lock( 0, sizeof(cube), (void**)&pVertices, 0 );
        memcpy( pVertices, cube, sizeof(cube) );
        bufferToFill->Unlock();
    m_pD3DDevice->SetStreamSource( 0, bufferToFill, 0, sizeof(PlainVertex) );
    m_pD3DDevice->SetFVF( PlainVertex::FVF_Flags );
        m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,  0, 2 );
        m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,  4, 2 );
        m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,  8, 2 );
        m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 12, 2 );
        m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 16, 2 );
        m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 20, 2 );
        m_pD3DDevice->LightEnable( 0, true);
        m_pD3DDevice->LightEnable( 1, true);
        return true;
}
void                                    
D3DViewportRenderer::clearResources(bool onlyInvalidItems, bool clearShaders)
{
        m_resourceManager.clearResources( onlyInvalidItems, clearShaders );
}
MObject findShader( MObject& setNode )
{
        MFnDependencyNode fnNode(setNode);
        MPlug shaderPlug = fnNode.findPlug("surfaceShader");
                        
        if (!shaderPlug.isNull()) {                     
                MPlugArray connectedPlugs;
                bool asSrc = false;
                bool asDst = true;
                shaderPlug.connectedTo( connectedPlugs, asDst, asSrc );
                if (connectedPlugs.length() != 1)
                        MGlobal::displayError("Error getting shader");
                else 
                        return connectedPlugs[0].node();
        }                       
        
        return MObject::kNullObj;
}
bool D3DViewportRenderer::setSurfaceMaterialShader( const MDagPath &dagPath, D3DGeometry* Geometry,
                                                                                                        const D3DXMATRIXA16 &objectToWorld, 
                                                                                                        const D3DXMATRIXA16 &objectToWorldInvTranspose, 
                                                                                                        const D3DXMATRIXA16 &worldViewProjection,
                                                                                                        const D3DXVECTOR4 &worldEyePosition)
{
        if (!Geometry)
                return false;
        const SurfaceEffectItemList & surfaceEffects = m_resourceManager.getSurfaceEffectItemList();
        bool havePixelShader = (surfaceEffects.size() > 0);
        if (havePixelShader)
        {
                
                SurfaceEffectItem *defaultItem = surfaceEffects.front();
                if (defaultItem)
                {
                        ID3DXEffect* effect = defaultItem->fEffect;
                        if (effect)
                        {
                                
                                HRESULT hres = effect->SetTechnique("MayaPhong");
                                if (hres != D3D_OK)
                                        havePixelShader = false;
                                else
                                {
                                        
                                        D3DXHANDLE handle;
                                        handle = effect->GetParameterBySemantic( NULL, "WorldView" );
                                        effect->SetMatrix( handle, &objectToWorld );
                                        handle = effect->GetParameterBySemantic( NULL, "WorldViewInverseTranspose" );
                                        effect->SetMatrix( handle, &objectToWorldInvTranspose );
                                        handle = effect->GetParameterBySemantic( NULL, "WorldViewProjection" );
                                        effect->SetMatrix( handle, &worldViewProjection );
                                        
                                        
                                        
                                        MItDag dagIterator( MItDag::kDepthFirst, MFn::kLight );
                                        MDagPath lightPath;
                                        for (; !dagIterator.isDone(); dagIterator.next())
                                        {
                                                if ( !dagIterator.getPath(lightPath) )
                                                        continue;
                                                MFnLight    fnLight( lightPath );
                                                MTransformationMatrix worldMatrix = lightPath.inclusiveMatrix();
                                                MVector translation = worldMatrix.translation( MSpace::kWorld );
                                                MVector direction( 0.0, 0.0, 1.0 ); 
                                                direction *= worldMatrix.asMatrix();
                                                direction.normalize();
                                                
                                                D3DXVECTOR4 e_val((float)direction.x, (float)direction.y, (float)direction.z, 1.0f );
                                                hres = effect->SetVector( "lightDir", &e_val );
                                                MColor      colorVal = fnLight.color();
                                                float intensity = fnLight.intensity();
                                                D3DXVECTOR4 c_val( colorVal.r * intensity, colorVal.g * intensity, colorVal.b * intensity, 1.0f );
                                                hres = effect->SetVector( "lightColor", &c_val );
                                        }
        
                                        
                                        
                                        bool isTransparent = false;
                                        MFnMesh fnMesh(dagPath);
                                        MObjectArray sets;
                                        MObjectArray comps;
                                        unsigned int instanceNum = dagPath.instanceNumber();
                                        if (!fnMesh.getConnectedSetsAndMembers(instanceNum, sets, comps, true))
                                                MGlobal::displayError("ERROR: MFnMesh::getConnectedSetsAndMembers");
                                        if (sets.length())
                                        {
                                                MObject set = sets[0];
                                                MObject comp = comps[0];
                                                MStatus status;
                                                MObject shaderNode = findShader(set);
                                                if (shaderNode != MObject::kNullObj)
                                                {                                                               
                                                        float rgb[3];
                                                        MPlug colorPlug = MFnDependencyNode(shaderNode).findPlug("color", &status);
                                                        D3DTexture* Texture = NULL;
                                                        if (status != MS::kFailure)
                                                        {
                                                                MItDependencyGraph It( colorPlug, MFn::kFileTexture, MItDependencyGraph::kUpstream);
                                                                if( !It.isDone())
                                                                {
                                                                        Texture = m_resourceManager.getTexture( It.thisNode());
                                                                        hres = effect->SetTexture( "diffuseTexture", Texture->Texture( m_pD3DDevice ));
                                                                        D3DXVECTOR4 e_val(1.0f, 1.0f, 1.0f, 1.0f );
                                                                        hres = effect->SetVector( "diffuseMaterial", &e_val);
                                                                        
                                                                        hres = effect->SetTechnique("MayaPhongTextured");
                                                                }
                                                                else
                                                                {
                                                                        MObject data;
                                                                        colorPlug.getValue( data);
                                                                        MFnNumericData val(data);
                                                                        val.getData( rgb[0], rgb[1], rgb[2]);
                                                                        
                                                                        D3DXVECTOR4 e_val(rgb[0], rgb[1], rgb[2], 1.0f );
                                                                        hres = effect->SetVector( "diffuseMaterial", &e_val);
                                                                }
                                                        }
                                                        MPlug diffusePlug = MFnDependencyNode(shaderNode).findPlug("diffuse", &status);
                                                        if (status != MS::kFailure)
                                                        {
                                                                MObject data;
                                                                float diff;
                                                                diffusePlug.getValue( diff );
                                                                
                                                                
                                                                
                                                        }
                                                        MPlug ambientColorPlug = MFnDependencyNode(shaderNode).findPlug("ambientColor", &status);
                                                        if (status != MS::kFailure)
                                                        {
                                                                MObject data;
                                                                ambientColorPlug .getValue( data);
                                                                MFnNumericData val(data);
                                                                val.getData( rgb[0], rgb[1], rgb[2]);
                                                                D3DXVECTOR4 e_val( rgb[0], rgb[1], rgb[2], 1.0f );
                                                                effect->SetVector( "ambientMaterial", &e_val );
                                                        }
                                                        MPlug transparencyPlug = MFnDependencyNode(shaderNode).findPlug("transparency", &status);
                                                        if (status != MS::kFailure)
                                                        {
                                                                MObject data;
                                                                transparencyPlug.getValue( data);
                                                                MFnNumericData val(data);
                                                                val.getData( rgb[0], rgb[1], rgb[2]);
                                                                D3DXVECTOR4 e_val( 1.0f - rgb[0], 1.0f - rgb[1], 1.0f - rgb[2], 1.0f );
                                                                effect->SetVector( "transparency", &e_val );
                                                                if (rgb[0] < 1.0f || rgb[1] < 1.0f || rgb[2] < 1.0f)
                                                                        isTransparent = true;
                                                        }
                                                        MPlug incandescencePlug = MFnDependencyNode(shaderNode).findPlug("incandescence", &status);
                                                        if (status != MS::kFailure)
                                                        {
                                                                MObject data;
                                                                incandescencePlug.getValue( data);
                                                                MFnNumericData val(data);
                                                                val.getData( rgb[0], rgb[1], rgb[2]);
                                                                
                                                                
                                                                
                                                        }
                                                        MPlug specularColorPlug = MFnDependencyNode(shaderNode).findPlug("specularColor", &status);
                                                        if (status != MS::kFailure)
                                                        {
                                                                MObject data;
                                                                specularColorPlug.getValue( data);
                                                                MFnNumericData val(data);
                                                                val.getData( rgb[0], rgb[1], rgb[2]);
                                                                D3DXVECTOR4 e_val( rgb[0], rgb[1], rgb[2], 1.0f );
                                                                effect->SetVector( "specularMaterial", &e_val );
                                                        }                                               
                                                        
                                                        
                                                        if (shaderNode.hasFn(MFn::kLambert))
                                                        {
                                                                effect->SetFloat( "specularPower", 0.0f );
                                                        }
                                                        if (shaderNode.hasFn(MFn::kPhong))
                                                        {
                                                                MPlug cosinePowerPlug = MFnDependencyNode(shaderNode).findPlug("cosinePower", &status);
                                                                if (status != MS::kFailure)
                                                                {
                                                                        MObject data;
                                                                        float cosPower = 0.0f;
                                                                        cosinePowerPlug.getValue( cosPower );
                                                                        hres = effect->SetFloat( "specularPower", cosPower * 4.0f );
                                                                }                                               
                                                        }
                                                        else if (MFn::kBlinn)
                                                        {
                                                                MPlug eccentricityPlug = MFnDependencyNode(shaderNode).findPlug("eccentricity", &status);
                                                                if (status != MS::kFailure)
                                                                {
                                                                        
                                                                        
                                                                        MObject data;
                                                                        float eccentricity = 0.0f;
                                                                        eccentricityPlug.getValue( eccentricity );
                                                                        hres = effect->SetFloat( "specularPower", (eccentricity < 0.03125f) ? 128.0f : 4.0f / eccentricity );
                                                                }
                                                        }
                                                        else 
                                                        {
                                                                MPlug roughnessPlug = MFnDependencyNode(shaderNode).findPlug("roughness", &status);
                                                                if (status != MS::kFailure)
                                                                {
                                                                        MObject data;
                                                                        float roughness = 0.0f;
                                                                        roughnessPlug.getValue( roughness );
                                                                        hres = effect->SetFloat( "specularPower", roughness * 4.0f );
                                                                }
                                                        }
                                                }
                                        }
                                        unsigned int numPasses;
                                        effect->Begin( &numPasses, 0 );
                                        if (hres != D3D_OK)
                                                havePixelShader = false;
                                        else
                                        {
                                                
                                                for (unsigned int p=0; p<numPasses; ++p)
                                                {
                                                        hres = effect->BeginPass( p );
                                                        if (hres == D3D_OK) 
                                                        {
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                Geometry->Render( m_pD3DDevice);
                                                        }
                                                        hres = effect->EndPass();
                                                }
                                        }
                                        hres = effect->End();
                                        if (hres != D3D_OK) 
                                                havePixelShader = false;
                                }
                        }
                }
        }
        return havePixelShader;
}
bool D3DViewportRenderer::setSurfaceMaterial( const MDagPath &dagPath )
{
        D3DMATERIAL9 Material;
        bool isTransparent = false;
        MFnMesh fnMesh(dagPath);
        MObjectArray sets;
        MObjectArray comps;
        unsigned int instanceNum = dagPath.instanceNumber();
        if (!fnMesh.getConnectedSetsAndMembers(instanceNum, sets, comps, true))
                MGlobal::displayError("ERROR : MFnMesh::getConnectedSetsAndMembers");
        for ( unsigned i=0; i<sets.length(); i++ ) 
        {
                MObject set = sets[i];
                MObject comp = comps[i];
                MStatus status;
                MFnSet fnSet( set, &status );
                if (status == MS::kFailure) {
                        MGlobal::displayError("ERROR: MFnSet::MFnSet");
                        continue;
                }
                MObject shaderNode = findShader(set);
                if (shaderNode != MObject::kNullObj)
                {                                                               
                        float rgb[3];
                        MPlug colorPlug = MFnDependencyNode(shaderNode).findPlug("color", &status);
                        D3DTexture* Texture = NULL;
                        if (status != MS::kFailure)
                        {
                                MItDependencyGraph It( colorPlug, MFn::kFileTexture, MItDependencyGraph::kUpstream);
                                if( !It.isDone())
                                {
                                        Texture = m_resourceManager.getTexture( It.thisNode());
                                        m_pD3DDevice->SetTexture( 0, Texture->Texture( m_pD3DDevice));
                                        m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
                                        m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
                                        m_pD3DDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
                                        m_pD3DDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
                                        m_pD3DDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
                                        m_pD3DDevice->SetRenderState(D3DRS_WRAP0, D3DWRAPCOORD_0);
                                        m_pD3DDevice->SetRenderState(D3DRS_WRAP1, D3DWRAPCOORD_1);
                                        Material.Diffuse.r = Material.Diffuse.g = Material.Diffuse.b = Material.Diffuse.a = 1.0f; 
                                }
                                else
                                {
                                        m_pD3DDevice->SetTexture( 0, NULL);
                                        MObject data;
                                        colorPlug.getValue( data);
                                        MFnNumericData val(data);
                                        val.getData( rgb[0], rgb[1], rgb[2]);
                                        Material.Diffuse.r = (float)rgb[0]; 
                                        Material.Diffuse.g = (float)rgb[1]; 
                                        Material.Diffuse.b = (float)rgb[2]; Material.Diffuse.a = 1.0f; 
                                }
                        }
                        MPlug diffusePlug = MFnDependencyNode(shaderNode).findPlug("diffuse", &status);
                        if (status != MS::kFailure)
                        {
                                MObject data;
                                float diff;
                                diffusePlug.getValue( diff );
                                Material.Diffuse.r *= (float)diff;
                                Material.Diffuse.g *= (float)diff; 
                                Material.Diffuse.b *= (float)diff;
                        }
                        MPlug ambientColorPlug = MFnDependencyNode(shaderNode).findPlug("ambientColor", &status);
                        if (status != MS::kFailure)
                        {
                                MObject data;
                                ambientColorPlug .getValue( data);
                                MFnNumericData val(data);
                                val.getData( rgb[0], rgb[1], rgb[2]);
                                Material.Ambient.r = (float)rgb[0]; 
                                Material.Ambient.g = (float)rgb[1]; 
                                Material.Ambient.b = (float)rgb[2]; Material.Ambient.a = 1.0f; 
                        }
                        MPlug transparencyPlug = MFnDependencyNode(shaderNode).findPlug("transparency", &status);
                        if (status != MS::kFailure)
                        {
                                MObject data;
                                transparencyPlug.getValue( data);
                                MFnNumericData val(data);
                                val.getData( rgb[0], rgb[1], rgb[2]);
                                Material.Diffuse.a = 1.0f - (rgb[0] + rgb[1] + rgb[2]) / 3.0f;
                                if (Material.Diffuse.a < 1.0f)
                                        isTransparent = true;
                        }
                        MPlug incandescencePlug = MFnDependencyNode(shaderNode).findPlug("incandescence", &status);
                        if (status != MS::kFailure)
                        {
                                MObject data;
                                incandescencePlug.getValue( data);
                                MFnNumericData val(data);
                                val.getData( rgb[0], rgb[1], rgb[2]);
                                Material.Emissive.r = (float)rgb[0]; 
                                Material.Emissive.g = (float)rgb[1]; 
                                Material.Emissive.b = (float)rgb[2]; Material.Emissive.a = 1.0f; 
                        }
                        MPlug specularColorPlug = MFnDependencyNode(shaderNode).findPlug("specularColor", &status);
                        if (status != MS::kFailure)
                        {
                                MObject data;
                                specularColorPlug.getValue( data);
                                MFnNumericData val(data);
                                val.getData( rgb[0], rgb[1], rgb[2]);
                                Material.Specular.r = (float)rgb[0]; 
                                Material.Specular.g = (float)rgb[1]; 
                                Material.Specular.b = (float)rgb[2]; Material.Specular.a = 1.0f; 
                        }                                               
                        
                        
                        Material.Power = 20.0f;
                        if (shaderNode.hasFn(MFn::kLambert))
                        {
                                Material.Power = 0.0f;
                        }
                        if (shaderNode.hasFn(MFn::kPhong))
                        {
                                MPlug cosinePowerPlug = MFnDependencyNode(shaderNode).findPlug("cosinePower", &status);
                                if (status != MS::kFailure)
                                {
                                        MObject data;
                                        float cosPower = 0.0f;
                                        cosinePowerPlug.getValue( cosPower );
                                        Material.Power = cosPower * 4.0f;
                                }                                               
                        }
                        else if (MFn::kBlinn)
                        {
                                MPlug eccentricityPlug = MFnDependencyNode(shaderNode).findPlug("eccentricity", &status);
                                if (status != MS::kFailure)
                                {
                                        
                                        
                                        MObject data;
                                        float eccentricity = 0.0f;
                                        eccentricityPlug.getValue( eccentricity );
                                        Material.Power = (eccentricity < 0.03125f) ? 128.0f : 4.0f / eccentricity;
                                }
                        }
                        else 
                        {
                                MPlug roughnessPlug = MFnDependencyNode(shaderNode).findPlug("roughness", &status);
                                if (status != MS::kFailure)
                                {
                                        MObject data;
                                        float roughness = 0.0f;
                                        roughnessPlug.getValue( roughness );
                                        Material.Power = roughness * 4.0f;
                                }
                        }
                        break;
                }
        }
        
        
        m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, isTransparent);
        m_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
        m_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
        m_pD3DDevice->SetMaterial( &Material);
        return true;
}
bool D3DViewportRenderer::drawSurface( const MDagPath &dagPath, bool active, bool templated)
{
        bool drewSurface = false;
        if ( !dagPath.hasFn( MFn::kMesh ))
        {
                MMatrix  matrix = dagPath.inclusiveMatrix();
                MFnDagNode dagNode(dagPath);
                MBoundingBox box = dagNode.boundingBox();
                float color[3] = {0.6f, 0.3f, 0.0f};
                if (active)
                {
                        color[0] = 1.0f;
                        color[1] = 1.0f;
                        color[2] = 1.0f;
                }
                else if (templated)
                {
                        color[0] = 1.0f;
                        color[1] = 0.686f;
                        color[2] = 0.686f;
                }
                drawBounds( matrix, box, false, true, color);
                return true;
        }
        if ( dagPath.hasFn( MFn::kMesh ))
        {
                MMatrix  matrix = dagPath.inclusiveMatrix();
                MFnDagNode dagNode(dagPath);
                
                
                bool drewWithHwShader = false;
                {
                        MFnMesh fnMesh(dagPath);
                        MObjectArray sets;
                        MObjectArray comps;
                        unsigned int instanceNum = dagPath.instanceNumber();
                        if (!fnMesh.getConnectedSetsAndMembers(instanceNum, sets, comps, true))
                                MGlobal::displayError("ERROR : MFnMesh::getConnectedSetsAndMembers");
                        for ( unsigned i=0; i<sets.length(); i++ ) 
                        {
                                MObject set = sets[i];
                                MObject comp = comps[i];
                                MStatus status;
                                MFnSet fnSet( set, &status );
                                if (status == MS::kFailure) {
                                        MGlobal::displayError("ERROR: MFnSet::MFnSet");
                                        continue;
                                }
                                MObject shaderNode = findShader(set);
                                if (shaderNode != MObject::kNullObj)
                                {
                                        MPxHardwareShader * hwShader = 
                                                MPxHardwareShader::getHardwareShaderPtr( shaderNode );
                                        if (hwShader)
                                        {
                                                const MRenderProfile & profile = hwShader->profile();
                                                if (profile.hasRenderer( MRenderProfile::kMayaD3D))
                                                {
                                                        
                                                        
                                                        
                                                }
                                        }
                                }
                        }
                }
                
                D3DGeometry* Geometry = m_resourceManager.getGeometry( dagPath, m_pD3DDevice);
                if( Geometry)
                {
                        
                        
                        D3DXMATRIXA16 objectToWorld = D3DXMATRIXA16
                                (
                                (float)matrix.matrix[0][0], (float)matrix.matrix[0][1], (float)matrix.matrix[0][2], (float)matrix.matrix[0][3],
                                (float)matrix.matrix[1][0], (float)matrix.matrix[1][1], (float)matrix.matrix[1][2], (float)matrix.matrix[1][3],
                                (float)matrix.matrix[2][0], (float)matrix.matrix[2][1], (float)matrix.matrix[2][2], (float)matrix.matrix[2][3],
                                (float)matrix.matrix[3][0], (float)matrix.matrix[3][1], (float)matrix.matrix[3][2], (float)matrix.matrix[3][3]
                        );
                        m_pD3DDevice->SetTransform( D3DTS_WORLD, &objectToWorld );
                        m_pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
                        m_pD3DDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
                        m_pD3DDevice->SetRenderState( D3DRS_AMBIENT, 0xFFFFFFFF );
                        m_pD3DDevice->SetRenderState( D3DRS_VERTEXBLEND, FALSE );
                        m_pD3DDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
                        m_pD3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE, 0xFFFFFFFF );
                        if (!drewWithHwShader)
                        {
                                
                                
                                
                                bool drewGeometryWithShader = false;
                                
                                
                                MString usePixelShader("D3D_USE_PIXEL_SHADER");
                                int val = 0;
                                if (MGlobal::getOptionVarValue(usePixelShader, val))
                                {
                                        MMatrix  itmatrix = matrix.inverse().transpose();
                                        D3DXMATRIXA16 objectToWorldInvTransp = D3DXMATRIXA16
                                                (
                                                (float)itmatrix.matrix[0][0], (float)itmatrix.matrix[0][1], (float)itmatrix.matrix[0][2], (float)itmatrix.matrix[0][3],
                                                (float)itmatrix.matrix[1][0], (float)itmatrix.matrix[1][1], (float)itmatrix.matrix[1][2], (float)itmatrix.matrix[1][3],
                                                (float)itmatrix.matrix[2][0], (float)itmatrix.matrix[2][1], (float)itmatrix.matrix[2][2], (float)itmatrix.matrix[2][3],
                                                (float)itmatrix.matrix[3][0], (float)itmatrix.matrix[3][1], (float)itmatrix.matrix[3][2], (float)itmatrix.matrix[3][3]
                                        );
                                        MVector eyePos( 0.0, 0.0, 0.0 );
                                        eyePos *= mm_currentViewMatrix;
                                        D3DXVECTOR4 worldEye( (float)eyePos[0], (float)eyePos[1], (float)eyePos[2], (float)eyePos[3]);
                                        drewGeometryWithShader = setSurfaceMaterialShader( dagPath, Geometry, objectToWorld, objectToWorldInvTransp,
                                                objectToWorld * m_currentViewMatrix * m_currentProjectionMatrix,
                                                worldEye );
                                }
                                
                                if (!drewGeometryWithShader)
                                {
                                        
                                        
                                        D3DMATERIAL9 Material;
                                        if (active)
                                        {
                                                m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
                                                Material.Diffuse.r = 1.0f; Material.Diffuse.g = 1.0f; Material.Diffuse.b = 1.0f; Material.Diffuse.a = 1.0f; 
                                        }
                                        else if (templated)
                                        {
                                                m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
                                                Material.Diffuse.r = 1.0f; Material.Diffuse.g = 0.686f; Material.Diffuse.b = 0.686f; Material.Diffuse.a = 1.0f; 
                                        }
                                        else
                                        {
                                                m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
                                                Material.Diffuse.r = 0.5f; Material.Diffuse.g = 0.5f; Material.Diffuse.b = 0.5f; Material.Diffuse.a = 1.0f; 
                                        }
                                        Material.Ambient.r = 0.0f; Material.Ambient.g = 0.0f; Material.Ambient.b = 0.0f; Material.Ambient.a = 0.0f; 
                                        Material.Specular.r = 1.0f; Material.Specular.g = 1.0f; Material.Specular.b = 1.0f; Material.Specular.a = 1.0f; 
                                        Material.Emissive.r = 0.0f; Material.Emissive.g = 0.0f; Material.Emissive.b = 0.0f; Material.Emissive.a = 0.0f; 
                                        Material.Power = 50.0f;
                                        bool scanForMayaMaterial = true;
                                        if (!templated && scanForMayaMaterial)
                                        {
                                                if (!setSurfaceMaterial( dagPath ))
                                                {
                                                        m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
                                                        m_pD3DDevice->SetMaterial( &Material);
                                                }
                                        }
                                        Geometry->Render( m_pD3DDevice);
                                }
                        }
                        
                        
                        m_pD3DDevice->SetTexture( 0, NULL);
                        m_pD3DDevice->SetRenderState(D3DRS_WRAP0, 0);
                        m_pD3DDevice->SetRenderState(D3DRS_WRAP1, 0);
                        if (active)
                        {
                                bool drawActiveWithBounds = false;
                                if (drawActiveWithBounds)
                                {
                                        MBoundingBox box = dagNode.boundingBox();
                                        float color[3] = {1.0f, 1.0f, 1.0f};
                                        drawBounds( matrix, box, false, false, color );
                                }
                                else
                                {
                                        D3DMATERIAL9 Material;
                                        Material.Emissive.r = 1.0; 
                                        Material.Emissive.g = 1.0; 
                                        Material.Emissive.b = 1.0; 
                                        Material.Emissive.a = 1.0f; 
                                        Material.Ambient.r = 1.0; 
                                        Material.Ambient.g = 1.0; 
                                        Material.Ambient.b = 1.0; 
                                        Material.Ambient.a = 1.0f; 
                                        m_pD3DDevice->SetMaterial( &Material);
                                        m_resourceManager.enableLights( FALSE, m_pD3DDevice );
                                        m_pD3DDevice->SetRenderState( D3DRS_ANTIALIASEDLINEENABLE, TRUE );
                                        m_pD3DDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
                                        m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
                                        m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
                                        m_pD3DDevice->SetRenderState( D3DRS_SLOPESCALEDEPTHBIAS, 100 );
                                        m_pD3DDevice->SetRenderState( D3DRS_DEPTHBIAS, 10 );
                                        Geometry->Render( m_pD3DDevice);                                
                                        m_pD3DDevice->SetRenderState( D3DRS_DEPTHBIAS, 0 );
                                        m_pD3DDevice->SetRenderState( D3DRS_SLOPESCALEDEPTHBIAS, 0 );
                                        m_pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );          
                                        m_resourceManager.enableLights( TRUE, m_pD3DDevice );
                                }
                        }
                } 
        }
        return drewSurface;
}
bool D3DViewportRenderer::drawScene(const MRenderingInfo &renderInfo)
{
        bool useDrawTraversal = true;
        float groundPlaneColor[3] = { 0.8f, 0.8f, 0.8f };
        if (useDrawTraversal)
        {
                const MDagPath &cameraPath = renderInfo.cameraPath();
                if (cameraPath.isValid())
                {
                        
                        
                        
                        
                        MDrawTraversal *trav = new MDrawTraversal;
                        trav->enableFiltering( false );
                        if (!trav)
                        {
                                MGlobal::displayWarning("Direct3D renderer : failed to create a traversal class !\n");
                                return true;
                        }
                        const MRenderTarget &renderTarget = renderInfo.renderTarget();
                        trav->setFrustum( cameraPath, renderTarget.width(), 
                                                          renderTarget.height() );
                        if (!trav->frustumValid())
                        {
                                MGlobal::displayWarning("Direct3D renderer : Frustum is invalid !\n");
                                return true;
                        }
                        trav->traverse();
                        unsigned int numItems = trav->numberOfItems();
                        unsigned int i;
                        for (i=0; i<numItems; i++)
                        {
                                MDagPath path;
                                trav->itemPath(i, path);
                                if (path.isValid())
                                {
                                        bool drawIt = false;
                                        
                                        
                                        if ( path.hasFn( MFn::kViewManip ))
                                                continue;
                                        
                                        
                                        
                                        bool active = false;
                                        bool templated = false;
                                        if ( path.hasFn( MFn::kMesh) || 
                                                 path.hasFn( MFn::kNurbsSurface) || 
                                                 path.hasFn( MFn::kSubdiv) )
                                        {
                                                drawIt = true;
                                                if (trav->itemHasStatus( i, MDrawTraversal::kActiveItem ))
                                                {
                                                        active = true;
                                                }
                                                else if (trav->itemHasStatus( i, MDrawTraversal::kTemplateItem ))
                                                {
                                                        templated = true;
                                                }
                                                else
                                                {
                                                        if (path.hasFn( MFn::kMesh ))
                                                                ;
                                                        else if (path.hasFn( MFn::kNurbsSurface))
                                                                ;
                                                        else
                                                                ;
                                                }
                                        }
                                        
                                        
                                        
                                        else if (path.hasFn( MFn::kSketchPlane ) ||
                                                         path.hasFn( MFn::kGroundPlane ))
                                        {
                                                MMatrix  matrix = path.inclusiveMatrix();
                                                MFnDagNode dagNode(path);
                                                MBoundingBox box = dagNode.boundingBox();
                                                drawBounds( matrix, box, false, false, groundPlaneColor );
                                        }
                                        if (drawIt)
                                        {
                                                drawSurface( path, active, templated );
                                        }
                                }
                        }
                        if (trav)
                                delete trav;
                        
                        bool onlyInvalidItems = true;
                        clearResources( onlyInvalidItems, false );
                }
        }
        else
        {
                
                
                MItDag::TraversalType traversalType = MItDag::kDepthFirst;
                MFn::Type filter = MFn::kMesh;
                MStatus status;
                MItDag dagIterator( traversalType, filter, &status);
                for ( ; !dagIterator.isDone(); dagIterator.next() ) 
                {
                        MDagPath dagPath;
                        status = dagIterator.getPath(dagPath);
                        if ( !status ) {
                                status.perror("MItDag::getPath");
                                continue;
                        }
                        MFnDagNode dagNode(dagPath, &status);
                        if ( !status ) {
                                status.perror("MFnDagNode constructor");
                                continue;
                        }
                        MMatrix  matrix = dagPath.inclusiveMatrix();
                        MBoundingBox box = dagNode.boundingBox();
                        drawBounds( matrix, box, false, false, NULL );
                }
        }
        return true;
}
bool D3DViewportRenderer::drawBounds(const MMatrix &matrix, const MBoundingBox &box, bool filled, bool useDummyGeometry,
                                                                         float color[3],
                                                                         LPDIRECT3DVERTEXBUFFER9 buffer )
{
        
        
        D3DXMATRIXA16 mat = D3DXMATRIXA16
                (
                (float)matrix.matrix[0][0], (float)matrix.matrix[0][1], (float)matrix.matrix[0][2], (float)matrix.matrix[0][3],
                (float)matrix.matrix[1][0], (float)matrix.matrix[1][1], (float)matrix.matrix[1][2], (float)matrix.matrix[1][3],
                (float)matrix.matrix[2][0], (float)matrix.matrix[2][1], (float)matrix.matrix[2][2], (float)matrix.matrix[2][3],
                (float)matrix.matrix[3][0], (float)matrix.matrix[3][1], (float)matrix.matrix[3][2], (float)matrix.matrix[3][3]
                );
        m_pD3DDevice->SetTransform( D3DTS_WORLD, &mat );
        
        
        MPoint  minPt = box.min();
        MPoint  maxPt = box.max();
        float minVal[3] = { (float)minPt.x, (float)minPt.y, (float)minPt.z };
        float maxVal[3] = { (float)maxPt.x, (float)maxPt.y, (float)maxPt.z };
        drawCube( minVal, maxVal, filled, useDummyGeometry, color, buffer );
        return true;
}
bool D3DViewportRenderer::renderToTarget( const MRenderingInfo &renderInfo )
{
        
        
        if (renderInfo.renderingAPI() == MViewportRenderer::kDirect3D)
        {
                
                
                
                
                return false;
        }
        
        
        
        if (!m_pD3DDevice || !m_pTextureOutput || !m_pTextureInterm)
                return false;
        
        HRESULT hres;
        
        
        hres = m_pD3DDevice->SetRenderTarget( 0, m_pTextureIntermSurface );
        if (m_requireDepthStencilReadback && m_pDepthStencilSurface)
                hres = m_pD3DDevice->SetDepthStencilSurface( m_pDepthStencilSurface );
        hres = m_pD3DDevice->BeginScene();
        if (hres == D3D_OK)
        {
                
                setupMatrices( renderInfo );
                
                
                hres = m_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 
                                                                        D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 1.0f, 0 );
                
                
                m_resourceManager.setupLighting(m_pD3DDevice);
                if (hres == D3D_OK)
                {
                        
                        drawScene(renderInfo);
                }
                m_resourceManager.cleanupLighting(m_pD3DDevice);
        }
        
        hres = m_pD3DDevice->EndScene();
        if (hres != D3D_OK)
                return false;
        
        postRenderToTarget();
        return true;
}
bool D3DViewportRenderer::setupMatrices( const MRenderingInfo &info )
{
        if (!m_pD3DDevice)
                return false;
        const MMatrix & view = info.viewMatrix(); 
        const MMatrix & projection = info.projectionMatrix();
        
        D3DXMATRIXA16 vm( (float)view.matrix[0][0], (float)view.matrix[0][1], (float)view.matrix[0][2], (float)view.matrix[0][3], 
                (float)view.matrix[1][0], (float)view.matrix[1][1], (float)view.matrix[1][2], (float)view.matrix[1][3], 
                (float)view.matrix[2][0], (float)view.matrix[2][1], (float)view.matrix[2][2], (float)view.matrix[2][3], 
                (float)view.matrix[3][0], (float)view.matrix[3][1], (float)view.matrix[3][2], (float)view.matrix[3][3]);
        D3DXMATRIXA16 pm( (float)projection.matrix[0][0], (float)projection.matrix[0][1], (float)projection.matrix[0][2], (float)projection.matrix[0][3], 
                (float)projection.matrix[1][0], (float)projection.matrix[1][1], (float)projection.matrix[1][2], (float)projection.matrix[1][3], 
                (float)projection.matrix[2][0], (float)projection.matrix[2][1], (float)projection.matrix[2][2], (float)projection.matrix[2][3], 
                (float)projection.matrix[3][0], (float)projection.matrix[3][1], (float)projection.matrix[3][2], (float)projection.matrix[3][3]);
        m_pD3DDevice->SetTransform( D3DTS_PROJECTION, &pm );
        m_pD3DDevice->SetTransform( D3DTS_VIEW, &vm  );
        return true;
}
void D3DViewportRenderer::drawFullScreenQuad(float leftU, float topV, 
                                                                                         float rightU, float bottomV,
                                                                                         float targetWidth, float targetHeight,
                                                                                         LPDIRECT3DDEVICE9 D3D)
{
    float width = targetWidth - 0.5f;
    float height = targetHeight - 0.5f;
    
    ScreenSpaceVertex screenQuad[4];
    screenQuad[0].position = D3DXVECTOR4(-0.5f, -0.5f, 0.5f, 1.0f);
    screenQuad[0].texCoord = D3DXVECTOR2(leftU, topV);
    screenQuad[1].position = D3DXVECTOR4(width, -0.5f, 0.5f, 1.0f);
    screenQuad[1].texCoord = D3DXVECTOR2(rightU, topV);
    screenQuad[2].position = D3DXVECTOR4(-0.5f, height, 0.5f, 1.0f);
    screenQuad[2].texCoord = D3DXVECTOR2(leftU, bottomV);
    screenQuad[3].position = D3DXVECTOR4(width, height, 0.5f, 1.0f);
    screenQuad[3].texCoord = D3DXVECTOR2(rightU, bottomV);
    D3D->SetRenderState(D3DRS_ZENABLE, FALSE);
    D3D->SetFVF(ScreenSpaceVertex::FVF);
    D3D->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, screenQuad, sizeof(ScreenSpaceVertex));
    D3D->SetRenderState(D3DRS_ZENABLE, TRUE);
}
bool D3DViewportRenderer::postRenderToTarget()
{
        if (!m_pTexturePost)
                return false;
        IDirect3DSurface9 *postSurface = NULL;
        HRESULT hres = m_pTexturePost->GetSurfaceLevel( 0, &postSurface );
        if (hres != D3D_OK)
                return false;   
        IDirect3DSurface9 *currentSurface[2] = { m_pTextureIntermSurface, postSurface };
        LPDIRECT3DTEXTURE9  currentTexture[2] = { m_pTextureInterm, m_pTexturePost };
        
        
        
        unsigned int currentTarget = 0;
        unsigned int newTarget = 0;
        
        
        D3DSURFACE_DESC surfaceDesc;
        m_pTextureOutputSurface->GetDesc( &surfaceDesc );
        float quad_renderWidth = (float)surfaceDesc.Width;
        float quad_renderHeight = (float)surfaceDesc.Height;
        unsigned int numEffectsApplied = 0;
        const MStringArray &enabledEffects = m_resourceManager.getListOfEnabledPostEffects();
        const PostEffectItemList &postEffectList = m_resourceManager.getPostEffectItemList();
        unsigned int numOfEnabledEffects = enabledEffects.length();
        unsigned int numEffects = (unsigned int) postEffectList.size();
        
        
        if (!m_wantFloatingPointTargets && !numOfEnabledEffects || !numEffects)
                return false;
        
        m_pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
        for (unsigned int m=0; m<numOfEnabledEffects ; m++)
        {
                ID3DXEffect* effect = NULL;
                PostEffectItem *effectItem = NULL;
                
                
                PostEffectItemList::const_iterator eit, end_eit;
                end_eit = postEffectList.end();
                for (eit = postEffectList.begin(); eit != end_eit;  eit++)
                {
                        PostEffectItem *item = *eit;
                        if (item)
                        {
                                
                                if (enabledEffects[m] == item->fName)
                                {
                                        effectItem = item;
                                        effect = item->fEffect;
                                        break;
                                }
                        }
                }
                if (effect != NULL)
                {
                        
                        newTarget = ( currentTarget + 1 ) % 2;
                        m_pD3DDevice->SetRenderTarget( 0, currentSurface[newTarget] );
                        
                        m_pD3DDevice->BeginScene();
                        {
                                
                                hres = effect->SetTechnique( "PostProcess" ); 
                                if (hres != D3D_OK)
                                        continue;
                                
                                
                                effect->SetFloat( "duKernel", 1.0f / (float)quad_renderWidth );                         
                                effect->SetFloat( "dvKernel", 1.0f / (float)quad_renderHeight);
                                
                                if (effectItem->fName == MString("PostProcess_ToneMapFilter"))
                                {
                                        double value = 1.0;
                                        MString toneMapExp("PostProcess_ToneMapFilter_Exposure");
                                        if (!MGlobal::getOptionVarValue(toneMapExp, value))
                                                MGlobal::setOptionVarValue(toneMapExp, value);
                                        effect->SetFloat( "exposure", (float)value );                           
                                }
                                else if (effectItem->fName == MString("PostProcess_SobelFilter"))
                                {
                                        double value = 20;
                                        MString thickness("PostProcess_SobelFilter_edgeThickness");
                                        if (!MGlobal::getOptionVarValue(thickness, value))
                                                MGlobal::setOptionVarValue(thickness, value);
                                        effect->SetFloat( "edgeThickness", (float)value);       
                                }
                                
                                unsigned int numPasses;
                                hres = effect->Begin( &numPasses, 0 );
                                if (hres != D3D_OK)
                                        continue;
                                else
                                {
                                        
                                        
                                        hres = effect->SetTexture( "textureSourceColor", currentTexture[currentTarget] );
                                        if (hres != D3D_OK)
                                        {
                                                m_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET , 
                                                        D3DCOLOR_COLORVALUE(1.0f,0.0f,0.0f,1.0f), 1.0f, 0 );
                                                continue;
                                        }
                                        
                                        for (unsigned int p=0; p<numPasses; ++p)
                                        {
                                                hres = effect->BeginPass( p );
                                                if (hres != D3D_OK) 
                                                {
                                                        m_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET , 
                                                                D3DCOLOR_COLORVALUE(1.0f,0.0f,0.0f,1.0f), 1.0f, 0 );
                                                        continue;
                                                }
                                                
                                                drawFullScreenQuad( 0.0f, 0.0f, 1.0f, 1.0f, 
                                                        quad_renderWidth, quad_renderHeight, m_pD3DDevice );
                                                hres = effect->EndPass();
                                                if (hres != D3D_OK) 
                                                {
                                                        m_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET , 
                                                                D3DCOLOR_COLORVALUE(1.0f,0.0f,0.0f,1.0f), 1.0f, 0 );
                                                        continue;
                                                }
                                        }
                                }
                                hres = effect->End();
                                numEffectsApplied++;
                        }
                        m_pD3DDevice->SetTexture( 0, NULL);
                        m_pD3DDevice->EndScene();
#if defined(_DEBUG_POST_BUFFERS_)
                        bool dumpToFile= false;
                        if (dumpToFile)
                        {
                                const char fileName[] = "c:\\temp\\d3dDump_newTarget.jpg";
                                HRESULT hres = D3DXSaveSurfaceToFile( fileName, D3DXIFF_JPG,
                                        currentSurface[newTarget], NULL , NULL  );
                                const char fileName2[] = "c:\\temp\\d3dDump_oldTarget.jpg";
                                hres = D3DXSaveSurfaceToFile( fileName2, D3DXIFF_JPG,
                                        currentSurface[currentTarget], NULL , NULL  );
                        }
#endif
                        
                        
                        currentTarget = newTarget;
                }
        }
        
        
        
        
        
        if ((currentSurface[currentTarget] != m_pTextureIntermSurface) || 
                (m_pTextureOutputSurface != m_pTextureIntermSurface))
        {
                m_pD3DDevice->SetRenderTarget( 0, m_pTextureOutputSurface );
                m_pD3DDevice->BeginScene();
                {
                        m_pD3DDevice->SetTexture( 0, currentTexture[currentTarget] );
                        drawFullScreenQuad( 0.0f, 0.0f, 1.0f, 1.0f, 
                                quad_renderWidth, quad_renderHeight, m_pD3DDevice );
                }
                m_pD3DDevice->EndScene();
        }
        
        if (postSurface)
                postSurface->Release();
        
        m_pD3DDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
        return true;
}
bool D3DViewportRenderer::readFromTargetToSystemMemory()
{
        if (!m_pD3DDevice || !m_pTextureOutputSurface || m_renderWidth==0 || m_renderHeight == 0 ||
                !m_SystemMemorySurface)
                return false;
        bool readBuffer = false;
        
        
#if defined(_DUMP_SURFACE_READBACK_CONTENTS_)
        bool dumpToFile= false;
        if (dumpToFile)
        {
                const char fileName[] = "c:\\temp\\d3dDump.jpg";
                HRESULT hres = D3DXSaveSurfaceToFile( fileName, D3DXIFF_JPG,
                                                        m_pTextureOutputSurface, NULL , NULL  );
                if (hres != D3D_OK)
                {
                        MGlobal::displayWarning("Direct3D renderer : Failed to dump surface contents to file !\n");
                }
        }
#endif
        D3DSURFACE_DESC surfaceDesc;
        m_pTextureOutputSurface->GetDesc( &surfaceDesc );
        
        
        D3DLOCKED_RECT rectInfo;
        
        RECT rectToRead;
        rectToRead.top = 0;
        rectToRead.left = 0;
        rectToRead.bottom = m_renderHeight;
        rectToRead.right = m_renderWidth;
        DWORD readFlags = D3DLOCK_READONLY;
        
        
        
        
        HRESULT hres = m_pD3DDevice->GetRenderTargetData( m_pTextureOutputSurface,
                m_SystemMemorySurface );
        if (hres == D3D_OK)
        {
                
                
                
                hres = m_SystemMemorySurface->LockRect( &rectInfo, &rectToRead, readFlags );
                if (hres == D3D_OK)
                {                                       
                        INT pitch = rectInfo.Pitch;
                        BYTE *data = (BYTE *)rectInfo.pBits;
                        
                        
                        
                        
                        
                        const unsigned int bytesPerPixel = 4;
                        
                        unsigned int m_readBackBufferWidth = 0;
                        unsigned int m_readBackBufferHeight = 0;
                        m_readBackBuffer.getSize(m_readBackBufferWidth, m_readBackBufferHeight);
                        BYTE *m_readBackBufferPtr = NULL;
                        bool replaceReadBackBuffer = false;
                        if (!m_readBackBufferWidth || !m_readBackBufferHeight ||
                                m_readBackBufferWidth != m_renderWidth ||
                                m_readBackBufferHeight != m_renderHeight)
                        {
                                
                                m_readBackBuffer.resize(m_renderWidth, m_renderHeight, false);
                                m_readBackBuffer.getSize(m_readBackBufferWidth, m_readBackBufferHeight);
                                if (m_readBackBufferWidth != m_renderWidth ||
                                        m_readBackBufferHeight != m_renderHeight)
                                {
                                        MGlobal::displayError("D3D Renderer : Could not resize MImage buffer for readback !\n");
                                        return false;
                                }
                                m_readBackBufferPtr = (BYTE *)(m_readBackBuffer.pixels());
                        }
                        else
                                m_readBackBufferPtr = (BYTE *)(m_readBackBuffer.pixels());
                        if (m_readBackBufferPtr)
                        {
                                
                                
                                
                                unsigned int myLineSize = m_renderWidth * bytesPerPixel;
                                unsigned int offsetMyData = (m_renderHeight-1) * myLineSize;
                                unsigned int offsetData = 0;
                                unsigned int i;
                                for ( i=0 ; i < m_renderHeight; i++ )
                                {
                                        memcpy( m_readBackBufferPtr + offsetMyData, 
                                                data + offsetData, 
                                                myLineSize );
                                        offsetMyData -= myLineSize;
                                        offsetData += pitch;
                                }
                                readBuffer = true;
                        }
                        if (replaceReadBackBuffer)
                        {
                                m_readBackBuffer.setPixels( m_readBackBufferPtr, m_renderWidth,
                                        m_renderHeight );
                                delete[] m_readBackBufferPtr;                                   
                        }
                        m_readBackBufferPtr = 0;
                        
                        hres = m_SystemMemorySurface->UnlockRect();
                }
        }
        return readBuffer;
}
#endif