#if defined(D3D9_SUPPORTED)
#pragma warning (disable:4239)
#include <stdio.h>
#include <D3DResourceManager.h>
#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MFnCamera.h>
#include <maya/MAngle.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MItDag.h>
#include <maya/MMatrix.h>
#include <maya/MDagPath.h>
#include <maya/MFnDagNode.h>
#include <maya/MBoundingBox.h>
#include <maya/MNodeMessage.h>
#include <maya/MPlug.h>
#include <maya/MPlugArray.h>
#include <maya/MFnLight.h>
#include <maya/MFnSpotLight.h>
#include <maya/MColor.h>
#include <maya/MFloatMatrix.h>
void geometryDirtyCallback( void* clientData )
{
GeometryItem *item = (GeometryItem *)clientData;
if (item)
{
MMessage::removeCallback( item->m_objectDirtyMonitor );
item->m_objectDirtyMonitor = 0;
item->m_objectPath = MDagPath();
}
}
void geomteryChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData)
{
GeometryItem *item = (GeometryItem *)clientData;
if (item)
{
MMessage::removeCallback( item->m_objectChangeMonitor );
item->m_objectChangeMonitor = 0;
item->m_objectPath = MDagPath();
}
}
void textureChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData)
{
TextureItem *item = (TextureItem *)clientData;
if (item)
{
MMessage::removeCallback( item->m_objectChangeMonitor );
item->m_objectChangeMonitor = 0;
item->m_mayaNode = MObject::kNullObj;
}
}
void geometryDeleteCallback( MObject &node,
MDGModifier& modifier,
void* clientData )
{
GeometryItem *item = (GeometryItem *)clientData;
if (item)
{
MMessage::removeCallback( item->m_objectDeleteMonitor );
item->m_objectDeleteMonitor = 0;
item->m_objectPath = MDagPath();
}
}
void textureDeleteCallback( MObject &node,
MDGModifier& modifier,
void* clientData )
{
TextureItem *item = (TextureItem *)clientData;
if (item)
{
MMessage::removeCallback( item->m_objectDeleteMonitor );
item->m_objectDeleteMonitor = 0;
item->m_mayaNode = MObject::kNullObj;
}
}
D3DResourceManager::D3DResourceManager()
{
m_numberLightsEnabled = 0;
initializeDefaultCamera();
}
D3DResourceManager::~D3DResourceManager()
{
const bool onlyInvalidItems = false;
clearResources(onlyInvalidItems, true);
}
void
D3DResourceManager::initializeDefaultCamera()
{
m_camera.m_vEyePt = D3DXVECTOR3( 0.0f, 10.0f, -10.0f );
m_camera.m_vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
m_camera.m_vUpVec = D3DXVECTOR3 ( 0.0f, 1.0f, 0.0f );
m_camera.m_FieldOfView = 45.0f;
m_camera.m_nearClip = 0.1f;
m_camera.m_farClip = 1000.0f;
}
bool
D3DResourceManager::translateCamera( const MDagPath &cameraPath )
{
bool translatedCamera = false;
if (cameraPath.isValid())
{
MStatus status;
MFnCamera camera (cameraPath, &status);
if ( !status ) {
status.perror("MFnCamera constructor");
}
else
{
translatedCamera = true;
MPoint eyePoint = camera.eyePoint( MSpace::kWorld );
MPoint lookAtPt = camera.centerOfInterestPoint( MSpace::kWorld );
MVector upDirection = camera.upDirection ( MSpace::kWorld );
MFloatMatrix projMatrix = camera.projectionMatrix();
double horizontalFieldOfView = MAngle( camera.horizontalFieldOfView()
).asDegrees();
double nearClippingPlane = camera.nearClippingPlane();
double farClippingPlane = camera.farClippingPlane();
m_camera.m_vEyePt = D3DXVECTOR3((float)eyePoint.x, (float)eyePoint.y, (float)eyePoint.z);
m_camera.m_vLookatPt = D3DXVECTOR3((float)lookAtPt.x, (float)lookAtPt.y, (float)lookAtPt.z);
m_camera.m_vUpVec = D3DXVECTOR3((float)upDirection.x, (float)upDirection.y, (float)upDirection.z);
m_camera.m_FieldOfView = (float)horizontalFieldOfView;
m_camera.m_nearClip = (float)nearClippingPlane;
m_camera.m_farClip = (float)farClippingPlane;
m_camera.m_isOrtho = camera.isOrtho();
}
}
else
{
initializeDefaultCamera();
}
return translatedCamera;
}
void
D3DResourceManager::enableLights( bool val, LPDIRECT3DDEVICE9 D3D )
{
unsigned i;
for (i=0; i<m_numberLightsEnabled; i++)
{
D3D->LightEnable( i, val);
}
}
bool D3DResourceManager::cleanupLighting(LPDIRECT3DDEVICE9 D3D)
{
unsigned int i=0;
for (i=0; i<m_numberLightsEnabled; i++)
{
D3D->LightEnable( i, false);
}
LightItemList::const_iterator it, end_it;
end_it = m_lightItemList.end();
for (it = m_lightItemList.begin(); it != end_it; it++)
{
LightItem *item = *it;
if (item)
{
delete item;
}
}
m_lightItemList.clear();
return true;
}
bool D3DResourceManager::setupLighting(LPDIRECT3DDEVICE9 D3D)
{
MStatus status;
MItDag dagIterator( MItDag::kDepthFirst, MFn::kLight, &status );
MDagPath lightPath;
for (unsigned int i=0; i<8; i++)
{
D3D->LightEnable( i, false);
}
m_numberLightsEnabled = 0;
HRESULT hr;
for (; !dagIterator.isDone(); dagIterator.next())
{
if ( !dagIterator.getPath(lightPath) )
continue;
LightItem *lightItem = new LightItem;
if (!lightItem)
break;
lightItem->m_objectDeleteMonitor = NULL;
lightItem->m_objectDirtyMonitor = NULL;
ZeroMemory(&(lightItem->m_lightDesc), sizeof(lightItem->m_lightDesc));
D3DLIGHT9 *d3dLight = &(lightItem->m_lightDesc);
d3dLight->Range = 10000.0f;
d3dLight->Falloff = 0.0f;
d3dLight->Diffuse.a = 1.0f;
d3dLight->Ambient.a = 1.0f;
d3dLight->Specular.a = 1.0f;
d3dLight->Attenuation0 = 0.0f;
d3dLight->Attenuation1 = 0.0f;
d3dLight->Attenuation2 = 0.0f;
MFnLight fnLight( lightPath );
if ( lightPath.hasFn(MFn::kAmbientLight))
{
MColor colorVal = fnLight.color();
float intensity = fnLight.intensity();
d3dLight->Type = D3DLIGHT_POINT;
d3dLight->Ambient.r = colorVal.r * intensity;
d3dLight->Ambient.g = colorVal.g * intensity;
d3dLight->Ambient.b = colorVal.b * intensity;
d3dLight->Specular.r = 0.0f;
d3dLight->Specular.g = 0.0f;
d3dLight->Specular.b = 0.0f;
d3dLight->Diffuse.r = d3dLight->Ambient.r;
d3dLight->Diffuse.g = d3dLight->Ambient.g;
d3dLight->Diffuse.b = d3dLight->Ambient.b;
d3dLight->Attenuation0 = 1.0;
}
else if (lightPath.hasFn(MFn::kDirectionalLight) )
{
MColor colorVal = fnLight.color();
float intensity = fnLight.intensity();
d3dLight->Type = D3DLIGHT_DIRECTIONAL;
d3dLight->Diffuse.r = colorVal.r * intensity;
d3dLight->Diffuse.g = colorVal.g * intensity;
d3dLight->Diffuse.b = colorVal.b * intensity;
d3dLight->Specular.r = d3dLight->Diffuse.r;
d3dLight->Specular.g = d3dLight->Diffuse.g;
d3dLight->Specular.b = d3dLight->Diffuse.b;
d3dLight->Ambient.r = 0.0f;
d3dLight->Ambient.g = 0.0f;
d3dLight->Ambient.b = 0.0f;
}
else if (lightPath.hasFn(MFn::kPointLight))
{
d3dLight->Type = D3DLIGHT_POINT;
MColor colorVal = fnLight.color();
float intensity = fnLight.intensity();
d3dLight->Type = D3DLIGHT_POINT;
d3dLight->Diffuse.r = colorVal.r * intensity;
d3dLight->Diffuse.g = colorVal.g * intensity;
d3dLight->Diffuse.b = colorVal.b * intensity;
d3dLight->Specular.r = d3dLight->Diffuse.r;
d3dLight->Specular.g = d3dLight->Diffuse.g;
d3dLight->Specular.b = d3dLight->Diffuse.b;
d3dLight->Ambient.r = 0.0f;
d3dLight->Ambient.g = 0.0f;
d3dLight->Ambient.b = 0.0f;
d3dLight->Falloff = 0;
d3dLight->Attenuation0 = 1.0;
d3dLight->Attenuation1 = 0.0f;
d3dLight->Attenuation2 = 0.0f;
}
else if (lightPath.hasFn(MFn::kSpotLight))
{
d3dLight->Type = D3DLIGHT_SPOT;
MColor colorVal = fnLight.color();
float intensity = fnLight.intensity();
d3dLight->Type = D3DLIGHT_SPOT;
d3dLight->Diffuse.r = colorVal.r * intensity;
d3dLight->Diffuse.g = colorVal.g * intensity;
d3dLight->Diffuse.b = colorVal.b * intensity;
d3dLight->Specular = d3dLight->Diffuse;
d3dLight->Ambient.r = 0.0f;
d3dLight->Ambient.g = 0.0f;
d3dLight->Ambient.b = 0.0f;
MFnSpotLight fnSpotLight( lightPath );
d3dLight->Phi = (float) (fnSpotLight.coneAngle() ) +
(float) (fnSpotLight.penumbraAngle() );
d3dLight->Theta = d3dLight->Phi - (float) (fnSpotLight.penumbraAngle() );
d3dLight->Attenuation0 = 1.0;
float dropOffVal = (float) fnSpotLight.dropOff() / 1000.0f;
d3dLight->Attenuation1 = dropOffVal;
d3dLight->Falloff = 1.0f;
}
else
{
delete lightItem;
lightItem = NULL;
continue;
}
if (lightItem && d3dLight)
{
MTransformationMatrix worldMatrix = lightPath.inclusiveMatrix();
MVector translation = worldMatrix.translation( MSpace::kWorld );
MVector direction( 0.0, 0.0, -1.0 );
direction *= worldMatrix.asMatrix();
direction.normalize();
d3dLight->Position.x = (float)translation.x;
d3dLight->Position.y = (float)translation.y;
d3dLight->Position.z = (float)translation.z;
d3dLight->Direction.x = (float)direction.x;
d3dLight->Direction.y = (float)direction.y;
d3dLight->Direction.z = (float)direction.z;
}
hr = D3D->SetLight( m_numberLightsEnabled, d3dLight);
if (!SUCCEEDED(hr))
{
delete lightItem;
lightItem = NULL;
break;
}
hr = D3D->LightEnable(m_numberLightsEnabled, TRUE);
if (!SUCCEEDED(hr))
{
delete lightItem;
lightItem = NULL;
break;
}
m_numberLightsEnabled++;
if (m_numberLightsEnabled >= 8)
break;
m_lightItemList.push_back( lightItem );
}
if (m_numberLightsEnabled == 0)
{
D3DLIGHT9 Light;
Light.Type = D3DLIGHT_DIRECTIONAL;
Light.Specular.r = 1.0f; Light.Specular.g = 1.0f; Light.Specular.b = 1.0f; Light.Specular.a = 1.0f;
Light.Diffuse.r = 1.0f; Light.Diffuse.g = 1.0f; Light.Diffuse.b = 1.0f; Light.Diffuse.a = 1.0f;
Light.Ambient.r = 0.0f; Light.Ambient.g = 0.0f; Light.Ambient.b = 0.0f; Light.Ambient.a = 0.0f;
Light.Range = 100000;
Light.Falloff = 0;
Light.Direction = m_camera.m_vLookatPt - m_camera.m_vEyePt;
D3D->SetLight( 0, &Light);
D3D->LightEnable( 0, true);
D3DLIGHT9 Light2;
Light2.Type = D3DLIGHT_DIRECTIONAL;
Light2.Specular.r = 1.0f; Light2.Specular.g = 1.0f; Light2.Specular.b = 1.0f; Light2.Specular.a = 1.0f;
Light2.Diffuse.r = 1.0f; Light2.Diffuse.g = 1.0f; Light2.Diffuse.b = 1.0f; Light2.Diffuse.a = 1.0f;
Light2.Ambient.r = 0.0f; Light2.Ambient.g = 0.0f; Light2.Ambient.b = 0.0f; Light2.Ambient.a = 0.0f;
Light2.Range = 100000;
Light2.Falloff = 0;
Light2.Direction = m_camera.m_vEyePt - m_camera.m_vLookatPt;
D3D->SetLight( 1, &Light2);
D3D->LightEnable( 1, true);
m_numberLightsEnabled = 2;
}
D3D->SetRenderState( D3DRS_LIGHTING, TRUE );
D3D->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
D3D->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
D3D->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
D3D->SetRenderState(D3DRS_LOCALVIEWER, TRUE);
D3D->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
return true;
}
D3DGeometry* D3DResourceManager::getGeometry( const MDagPath& dagPath, LPDIRECT3DDEVICE9 D3D)
{
D3DGeometry* Geometry = NULL;
GeometryItem *itemFound = NULL;
GeometryItemList::const_iterator it, end_it;
end_it = m_geometryItemList.end();
for (it = m_geometryItemList.begin(); it != end_it; it++)
{
GeometryItem *item = *it;
if (item && item->m_objectPath == dagPath)
{
itemFound = item;
}
}
if (!itemFound)
{
itemFound = new GeometryItem;
itemFound->m_objectPath = dagPath;
Geometry = itemFound->m_objectGeometry = new D3DGeometry();
if (Geometry)
{
Geometry->Populate( dagPath, D3D);
}
MFnDagNode dagNode(dagPath);
MObject &obj = (MObject &) dagNode.object();
itemFound->m_objectDeleteMonitor =
MNodeMessage::addNodeAboutToDeleteCallback( obj, geometryDeleteCallback, (void *)itemFound );
itemFound->m_objectChangeMonitor = 0;
itemFound->m_objectChangeMonitor =
MNodeMessage::addNodeDirtyCallback( obj, geometryDirtyCallback, (void *)itemFound);
m_geometryItemList.push_back( itemFound );
}
else
{
Geometry = itemFound->m_objectGeometry;
}
return Geometry;
}
D3DTexture* D3DResourceManager::getTexture( MObject& textureNode)
{
D3DTexture* Texture = NULL;
TextureItem *itemFound = NULL;
TextureItemList::const_iterator it, end_it;
end_it = m_textureItemList.end();
for (it = m_textureItemList.begin(); it != end_it; it++)
{
TextureItem *item = *it;
if (item && item->m_mayaNode.object() == textureNode)
{
itemFound = item;
}
}
if (!itemFound)
{
itemFound = new TextureItem();
itemFound->m_mayaNode = textureNode;
Texture = itemFound->m_texture = new D3DTexture( textureNode);
itemFound->m_objectDeleteMonitor =
MNodeMessage::addNodeAboutToDeleteCallback( textureNode, textureDeleteCallback, (void *)itemFound );
itemFound->m_objectChangeMonitor =
MNodeMessage::addAttributeChangedCallback( textureNode, textureChangedCallback, (void *)itemFound);
m_textureItemList.push_back( itemFound );
}
else
{
Texture = itemFound->m_texture;
}
return Texture;
}
bool
D3DResourceManager::initializeDefaultSurfaceEffect( const MString &effectsLocation, LPDIRECT3DDEVICE9 D3D,
const MString & effectName )
{
HRESULT hres;
LPD3DXBUFFER pBufferErrors = NULL;
DWORD dwShaderFlags = 0;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
ID3DXEffect* effect = NULL;
MString effectLocation = effectsLocation + "\\" + effectName + ".fx";
hres = D3DXCreateEffectFromFile( D3D,
effectLocation.asChar(),
NULL,
NULL,
dwShaderFlags,
NULL,
&effect,
&pBufferErrors );
if (FAILED(hres))
{
MGlobal::displayInfo("Failed to compile FX file: " + effectLocation);
if (pBufferErrors)
{
const char *pCompilErrors = (const char*)pBufferErrors->GetBufferPointer();
MGlobal::displayInfo(MString("Compiler errors:\n") + MString(pCompilErrors) );
}
}
else
{
MGlobal::displayInfo("Maya default pixel shader loaded: " + effectLocation);
SurfaceEffectItem *pei = new SurfaceEffectItem;
if (pei)
{
pei->fEffect = effect;
pei->fName = effectName;
m_SurfaceEffectItemList.push_back( pei );
}
}
return (m_SurfaceEffectItemList.size() > 0);
}
bool
D3DResourceManager::initializePostEffects( const MString &effectsLocation, LPDIRECT3DDEVICE9 D3D)
{
HRESULT hres;
LPD3DXBUFFER pBufferErrors = NULL;
DWORD dwShaderFlags = 0;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
MStringArray effectNames;
effectNames.append("PostProcess_SobelFilter");
effectNames.append("PostProcess_ToneMapFilter");
effectNames.append("PostProcess_InvertFilter");
for (unsigned int i=0; i<effectNames.length(); i++)
{
ID3DXEffect* effect = NULL;
MString effectLocation = effectsLocation + "\\" + effectNames[i] + ".fx";
hres = D3DXCreateEffectFromFile( D3D,
effectLocation.asChar(),
NULL,
NULL,
dwShaderFlags,
NULL,
&effect,
&pBufferErrors );
if (FAILED(hres))
{
MGlobal::displayInfo("Failed to compiler FX file" + effectLocation);
if (pBufferErrors)
{
const char *pCompilErrors = (const char*)pBufferErrors->GetBufferPointer();
MGlobal::displayInfo(MString("Compiler errors:\n") + MString(pCompilErrors) );
}
}
else
{
PostEffectItem *pei = new PostEffectItem;
if (pei)
{
pei->fEffect = effect;
pei->fName = effectNames[i];
m_PostEffectItemList.push_back( pei );
}
}
}
return (m_PostEffectItemList.size() > 0);
}
const MStringArray &
D3DResourceManager::getListOfEnabledPostEffects()
{
m_EnabledPostEffectItemList.clear();
const MString effectListVar("D3D_EFFECTS_LIST");
MString effectList;
if (!MGlobal::getOptionVarValue(effectListVar, effectList))
{
MGlobal::setOptionVarValue(effectListVar, effectList);
}
else
{
effectList.split(' ', m_EnabledPostEffectItemList);
}
return m_EnabledPostEffectItemList;
}
void
D3DResourceManager::clearResources(bool onlyInvalidItems, bool clearShaders)
{
GeometryItemList::const_iterator git, end_git;
end_git = m_geometryItemList.end();
for (git = m_geometryItemList.begin(); git != end_git; git++)
{
GeometryItem *item = *git;
if (item)
{
if (!onlyInvalidItems || (onlyInvalidItems && !(item->m_objectPath.isValid() )))
{
if (item->m_objectGeometry)
{
delete item->m_objectGeometry;
item->m_objectGeometry = NULL;
}
item->m_objectPath = MDagPath();
if (item->m_objectDeleteMonitor)
{
MMessage::removeCallback( item->m_objectDeleteMonitor );
item->m_objectDeleteMonitor = 0;
}
if (item->m_objectChangeMonitor)
{
MMessage::removeCallback( item->m_objectChangeMonitor );
item->m_objectChangeMonitor = 0;
}
if (item->m_objectDirtyMonitor)
{
MMessage::removeCallback( item->m_objectDirtyMonitor );
item->m_objectDirtyMonitor = 0;
}
}
}
}
if (!onlyInvalidItems)
m_geometryItemList.clear();
TextureItemList::const_iterator tit, end_tit;
end_tit = m_textureItemList.end();
for (tit = m_textureItemList.begin(); tit != end_tit; tit++)
{
TextureItem *item = *tit;
if (item)
{
if (!onlyInvalidItems || (onlyInvalidItems && !(item->m_mayaNode.isValid() )))
{
if (item->m_texture)
{
delete item->m_texture;
item->m_texture = NULL;
}
item->m_mayaNode = MObject::kNullObj;
if (item->m_objectDeleteMonitor)
{
MMessage::removeCallback( item->m_objectDeleteMonitor );
item->m_objectDeleteMonitor = 0;
}
if (item->m_objectChangeMonitor)
{
MMessage::removeCallback( item->m_objectChangeMonitor );
item->m_objectChangeMonitor = 0;
}
}
}
}
if (!onlyInvalidItems)
m_textureItemList.clear();
if (clearShaders)
{
{
PostEffectItemList::const_iterator eit, end_eit;
end_eit = m_PostEffectItemList.end();
for (eit = m_PostEffectItemList.begin(); eit != end_eit; eit++)
{
PostEffectItem *item = *eit;
if (item)
{
if (item->fEffect)
{
item->fEffect->Release();
item->fEffect = NULL;
}
delete item;
}
}
m_PostEffectItemList.clear();
m_EnabledPostEffectItemList.clear();
}
{
SurfaceEffectItemList::const_iterator eit, end_eit;
end_eit = m_SurfaceEffectItemList.end();
for (eit = m_SurfaceEffectItemList.begin(); eit != end_eit; eit++)
{
SurfaceEffectItem *item = *eit;
if (item)
{
if (item->fEffect)
{
item->fEffect->Release();
item->fEffect = NULL;
}
delete item;
}
}
m_SurfaceEffectItemList.clear();
}
}
}
#endif