#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