//- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ #if defined(D3D9_SUPPORTED) #include #include #include #include #include #include #include #include #include #include #include #include #include #include // For monitor geometry list #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////////////// // // Monitors on Maya scene graph // // Handle node dirty changes void geometryDirtyCallback( void* clientData ) { GeometryItem *item = (GeometryItem *)clientData; if (item) { MMessage::removeCallback( item->m_objectDirtyMonitor ); item->m_objectDirtyMonitor = 0; item->m_objectPath = MDagPath(); // Assign in valid dag path to mark as "bad" } } // Handle node attr change void geomteryChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData) { GeometryItem *item = (GeometryItem *)clientData; if (item) { MMessage::removeCallback( item->m_objectChangeMonitor ); item->m_objectChangeMonitor = 0; item->m_objectPath = MDagPath(); // Assign in valid dag path to mark as "bad" } } void textureChangedCallback( MNodeMessage::AttributeMessage msg, MPlug & plug, MPlug & otherPlug, void* clientData) { TextureItem *item = (TextureItem *)clientData; if (item) { MMessage::removeCallback( item->m_objectChangeMonitor ); item->m_objectChangeMonitor = 0; item->m_mayaNode = MObject::kNullObj; // Assign in valid dag path to mark as "bad" } } // Handle node delete void geometryDeleteCallback( MObject &node, MDGModifier& modifier, void* clientData ) { GeometryItem *item = (GeometryItem *)clientData; if (item) { MMessage::removeCallback( item->m_objectDeleteMonitor ); item->m_objectDeleteMonitor = 0; item->m_objectPath = MDagPath(); // Assign in valid dag path to mark as "bad" } } void textureDeleteCallback( MObject &node, MDGModifier& modifier, void* clientData ) { TextureItem *item = (TextureItem *)clientData; if (item) { MMessage::removeCallback( item->m_objectDeleteMonitor ); item->m_objectDeleteMonitor = 0; item->m_mayaNode = MObject::kNullObj; // Assign in valid dag path to mark as "bad" } } /////////////////////////////// D3DResourceManager::D3DResourceManager() { // All lights are off m_numberLightsEnabled = 0; initializeDefaultCamera(); } /* virtual */ D3DResourceManager::~D3DResourceManager() { const bool onlyInvalidItems = false; clearResources(onlyInvalidItems, true); } void D3DResourceManager::initializeDefaultCamera() { // Set the default camera being 10 up and 10 back, with Y-up (to match Maya). m_camera.m_vEyePt = D3DXVECTOR3( 0.0f, 10.0f, -10.0f ); m_camera.m_vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); m_camera.m_vUpVec = D3DXVECTOR3 ( 0.0f, 1.0f, 0.0f ); // Set up default clip planes, and FOV to match Maya's m_camera.m_FieldOfView = 45.0f; m_camera.m_nearClip = 0.1f; m_camera.m_farClip = 1000.0f; } bool D3DResourceManager::translateCamera( const MDagPath &cameraPath ) // // Description: // Translate Maya's camera // { bool translatedCamera = false; if (cameraPath.isValid()) { MStatus status; MFnCamera camera (cameraPath, &status); if ( !status ) { status.perror("MFnCamera constructor"); } else { translatedCamera = true; MPoint eyePoint = camera.eyePoint( MSpace::kWorld ); MPoint lookAtPt = camera.centerOfInterestPoint( MSpace::kWorld ); MVector upDirection = camera.upDirection ( MSpace::kWorld ); double horizontalFieldOfView = MAngle( camera.horizontalFieldOfView() ).asDegrees(); double nearClippingPlane = camera.nearClippingPlane(); double farClippingPlane = camera.farClippingPlane(); // Convert API values to internal native storage. // m_camera.m_vEyePt = D3DXVECTOR3((float)eyePoint.x, (float)eyePoint.y, (float)eyePoint.z); m_camera.m_vLookatPt = D3DXVECTOR3((float)lookAtPt.x, (float)lookAtPt.y, (float)lookAtPt.z); m_camera.m_vUpVec = D3DXVECTOR3((float)upDirection.x, (float)upDirection.y, (float)upDirection.z); m_camera.m_FieldOfView = (float)horizontalFieldOfView; m_camera.m_nearClip = (float)nearClippingPlane; m_camera.m_farClip = (float)farClippingPlane; } } else { initializeDefaultCamera(); } return translatedCamera; } void D3DResourceManager::enableLights( bool val, LPDIRECT3DDEVICE9 D3D ) { unsigned i; for (i=0; iLightEnable( i, val); } } bool D3DResourceManager::cleanupLighting(LPDIRECT3DDEVICE9 D3D) { unsigned int i=0; for (i=0; iLightEnable( i, false); } LightItemList::const_iterator it, end_it; end_it = m_lightItemList.end(); for (it = m_lightItemList.begin(); it != end_it; it++) { LightItem *item = *it; if (item) { delete item; } } m_lightItemList.clear(); return true; } bool D3DResourceManager::setupLighting(LPDIRECT3DDEVICE9 D3D) // // Description: // Set up lighting / materials. // { // Set up Maya lights: // Nasty, need to scan for lights MStatus status; MItDag dagIterator( MItDag::kDepthFirst, MFn::kLight, &status ); MDagPath lightPath; for (unsigned int i=0; i<8; i++) { D3D->LightEnable( i, false); } m_numberLightsEnabled = 0; HRESULT hr; for (; !dagIterator.isDone(); dagIterator.next()) { if ( !dagIterator.getPath(lightPath) ) continue; LightItem *lightItem = new LightItem; if (!lightItem) break; lightItem->m_objectDeleteMonitor = NULL; lightItem->m_objectDirtyMonitor = NULL; ZeroMemory(&(lightItem->m_lightDesc), sizeof(lightItem->m_lightDesc)); D3DLIGHT9 *d3dLight = &(lightItem->m_lightDesc); d3dLight->Range = 10000.0f; d3dLight->Falloff = 0.0f; d3dLight->Diffuse.a = 1.0f; d3dLight->Ambient.a = 1.0f; d3dLight->Specular.a = 1.0f; d3dLight->Attenuation0 = 0.0f; d3dLight->Attenuation1 = 0.0f; d3dLight->Attenuation2 = 0.0f; // This code doesn't do all of the light attributes, but the // general ones are pretty much supported. // MFnLight fnLight( lightPath ); if ( lightPath.hasFn(MFn::kAmbientLight)) { MColor colorVal = fnLight.color(); float intensity = fnLight.intensity(); d3dLight->Type = D3DLIGHT_POINT; d3dLight->Ambient.r = colorVal.r * intensity; d3dLight->Ambient.g = colorVal.g * intensity; d3dLight->Ambient.b = colorVal.b * intensity; d3dLight->Specular.r = 0.0f; d3dLight->Specular.g = 0.0f; d3dLight->Specular.b = 0.0f; d3dLight->Diffuse.r = d3dLight->Ambient.r; d3dLight->Diffuse.g = d3dLight->Ambient.g; d3dLight->Diffuse.b = d3dLight->Ambient.b; d3dLight->Attenuation0 = 1.0; } else if (lightPath.hasFn(MFn::kDirectionalLight) ) { MColor colorVal = fnLight.color(); float intensity = fnLight.intensity(); d3dLight->Type = D3DLIGHT_DIRECTIONAL; d3dLight->Diffuse.r = colorVal.r * intensity; d3dLight->Diffuse.g = colorVal.g * intensity; d3dLight->Diffuse.b = colorVal.b * intensity; d3dLight->Specular.r = d3dLight->Diffuse.r; d3dLight->Specular.g = d3dLight->Diffuse.g; d3dLight->Specular.b = d3dLight->Diffuse.b; d3dLight->Ambient.r = 0.0f; d3dLight->Ambient.g = 0.0f; d3dLight->Ambient.b = 0.0f; } else if (lightPath.hasFn(MFn::kPointLight)) { d3dLight->Type = D3DLIGHT_POINT; MColor colorVal = fnLight.color(); float intensity = fnLight.intensity(); d3dLight->Type = D3DLIGHT_POINT; d3dLight->Diffuse.r = colorVal.r * intensity; d3dLight->Diffuse.g = colorVal.g * intensity; d3dLight->Diffuse.b = colorVal.b * intensity; d3dLight->Specular.r = d3dLight->Diffuse.r; d3dLight->Specular.g = d3dLight->Diffuse.g; d3dLight->Specular.b = d3dLight->Diffuse.b; d3dLight->Ambient.r = 0.0f; d3dLight->Ambient.g = 0.0f; d3dLight->Ambient.b = 0.0f; d3dLight->Falloff = 0; // Should set attenuation based on "Decay Rate" attrib on light. TO ADD d3dLight->Attenuation0 = 1.0; d3dLight->Attenuation1 = 0.0f; d3dLight->Attenuation2 = 0.0f; } else if (lightPath.hasFn(MFn::kSpotLight)) { d3dLight->Type = D3DLIGHT_SPOT; MColor colorVal = fnLight.color(); float intensity = fnLight.intensity(); d3dLight->Type = D3DLIGHT_SPOT; d3dLight->Diffuse.r = colorVal.r * intensity; d3dLight->Diffuse.g = colorVal.g * intensity; d3dLight->Diffuse.b = colorVal.b * intensity; d3dLight->Specular = d3dLight->Diffuse; d3dLight->Ambient.r = 0.0f; d3dLight->Ambient.g = 0.0f; d3dLight->Ambient.b = 0.0f; MFnSpotLight fnSpotLight( lightPath ); // Differs from OpenGL in that we don't want half the angle (divide by 2) // in our setup. d3dLight->Phi = (float) (fnSpotLight.coneAngle() ) + (float) (fnSpotLight.penumbraAngle() ); d3dLight->Theta = d3dLight->Phi - (float) (fnSpotLight.penumbraAngle() ); // Should set attenuation based on "Decay Rate" attrib on light. TO ADD d3dLight->Attenuation0 = 1.0; float dropOffVal = (float) fnSpotLight.dropOff() / 1000.0f; d3dLight->Attenuation1 = dropOffVal; d3dLight->Falloff = 1.0f; } else { delete lightItem; lightItem = NULL; continue; } // Setup common position and direction information. if (lightItem && d3dLight) { MTransformationMatrix worldMatrix = lightPath.inclusiveMatrix(); MVector translation = worldMatrix.translation( MSpace::kWorld ); MVector direction( 0.0, 0.0, -1.0 ); direction *= worldMatrix.asMatrix(); direction.normalize(); d3dLight->Position.x = (float)translation.x; d3dLight->Position.y = (float)translation.y; d3dLight->Position.z = (float)translation.z; d3dLight->Direction.x = (float)direction.x; d3dLight->Direction.y = (float)direction.y; d3dLight->Direction.z = (float)direction.z; } hr = D3D->SetLight( m_numberLightsEnabled, d3dLight); if (!SUCCEEDED(hr)) { delete lightItem; lightItem = NULL; break; } hr = D3D->LightEnable(m_numberLightsEnabled, TRUE); if (!SUCCEEDED(hr)) { delete lightItem; lightItem = NULL; break; } m_numberLightsEnabled++; // Only allow up to 8 lights to be built for now if (m_numberLightsEnabled >= 8) break; m_lightItemList.push_back( lightItem ); } if (m_numberLightsEnabled == 0) { // Setup a headlight. D3DLIGHT9 Light; Light.Type = D3DLIGHT_DIRECTIONAL; Light.Specular.r = 1.0f; Light.Specular.g = 1.0f; Light.Specular.b = 1.0f; Light.Specular.a = 1.0f; Light.Diffuse.r = 1.0f; Light.Diffuse.g = 1.0f; Light.Diffuse.b = 1.0f; Light.Diffuse.a = 1.0f; Light.Ambient.r = 0.0f; Light.Ambient.g = 0.0f; Light.Ambient.b = 0.0f; Light.Ambient.a = 0.0f; Light.Range = 100000; Light.Falloff = 0; Light.Direction = m_camera.m_vLookatPt - m_camera.m_vEyePt; D3D->SetLight( 0, &Light); D3D->LightEnable( 0, true); // And a backlight. D3DLIGHT9 Light2; Light2.Type = D3DLIGHT_DIRECTIONAL; Light2.Specular.r = 1.0f; Light2.Specular.g = 1.0f; Light2.Specular.b = 1.0f; Light2.Specular.a = 1.0f; Light2.Diffuse.r = 1.0f; Light2.Diffuse.g = 1.0f; Light2.Diffuse.b = 1.0f; Light2.Diffuse.a = 1.0f; Light2.Ambient.r = 0.0f; Light2.Ambient.g = 0.0f; Light2.Ambient.b = 0.0f; Light2.Ambient.a = 0.0f; Light2.Range = 100000; Light2.Falloff = 0; Light2.Direction = m_camera.m_vEyePt - m_camera.m_vLookatPt; D3D->SetLight( 1, &Light2); D3D->LightEnable( 1, true); m_numberLightsEnabled = 2; } D3D->SetRenderState( D3DRS_LIGHTING, TRUE ); // Make sure specular is on. D3D->SetRenderState( D3DRS_SPECULARENABLE, TRUE ); D3D->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); D3D->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); // Set lighting to local-viewer D3D->SetRenderState(D3DRS_LOCALVIEWER, TRUE); // Make sure to auto-normalize normals D3D->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE ); return true; } // // Get the geometry buffers for this bad boy // D3DGeometry* D3DResourceManager::getGeometry( const MDagPath& dagPath, LPDIRECT3DDEVICE9 D3D) { D3DGeometry* Geometry = NULL; // Look for a cached mesh ... // // Check to see if object is in the list, if not added a // new item and cache some geometry GeometryItem *itemFound = NULL; GeometryItemList::const_iterator it, end_it; end_it = m_geometryItemList.end(); for (it = m_geometryItemList.begin(); it != end_it; it++) { GeometryItem *item = *it; if (item && item->m_objectPath == dagPath) { itemFound = item; } } // Build a new item, and add it to the list if (!itemFound) { itemFound = new GeometryItem; itemFound->m_objectPath = dagPath; Geometry = itemFound->m_objectGeometry = new D3DGeometry(); if (Geometry) { Geometry->Populate( dagPath, D3D); } MFnDagNode dagNode(dagPath); itemFound->m_objectDeleteMonitor = MNodeMessage::addNodeAboutToDeleteCallback( dagNode.object(), geometryDeleteCallback, (void *)itemFound ); // Add callback for node deleted. // Don't get attr change messages during playback, so use node dirty also..sigh //itemFound->m_objectChangeMonitor = // MNodeMessage::addAttributeChangedCallback( dagNode.object(), geometryChangedCallback, (void *)itemFound); // Add callback for attr changed. itemFound->m_objectChangeMonitor = 0; itemFound->m_objectChangeMonitor = MNodeMessage::addNodeDirtyCallback( dagNode.object(), geometryDirtyCallback, (void *)itemFound); // Add callback for node changed. m_geometryItemList.push_back( itemFound ); } else { Geometry = itemFound->m_objectGeometry; } // Create a new set of buffers for this mesh // return Geometry; } // // Get the DirectX texture for a Maya texture node // D3DTexture* D3DResourceManager::getTexture( MObject& textureNode) { D3DTexture* Texture = NULL; // Look for a cached texture ... // // Check to see if object is in the list, if not added a // new item and cache some texture TextureItem *itemFound = NULL; TextureItemList::const_iterator it, end_it; end_it = m_textureItemList.end(); for (it = m_textureItemList.begin(); it != end_it; it++) { TextureItem *item = *it; if (item && item->m_mayaNode.object() == textureNode) { itemFound = item; } } // Build a new item, and add it to the list if (!itemFound) { itemFound = new TextureItem(); itemFound->m_mayaNode = textureNode; Texture = itemFound->m_texture = new D3DTexture( textureNode); itemFound->m_objectDeleteMonitor = MNodeMessage::addNodeAboutToDeleteCallback( textureNode, textureDeleteCallback, (void *)itemFound ); // Add callback for node deleted. itemFound->m_objectChangeMonitor = MNodeMessage::addAttributeChangedCallback( textureNode, textureChangedCallback, (void *)itemFound); // Add callback for attr changed. m_textureItemList.push_back( itemFound ); } else { Texture = itemFound->m_texture; } // Create a new set of buffers for this mesh // return Texture; } bool D3DResourceManager::initializePostEffects( const MString &effectsLocation, LPDIRECT3DDEVICE9 D3D) // // Description: // Initialize all effects found in a given directory. // { HRESULT hres; LPD3DXBUFFER pBufferErrors = NULL; // Shader flags for debugging DWORD dwShaderFlags = 0; #ifdef DEBUG_VS dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT; #endif #ifdef DEBUG_PS dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT; #endif // Should do a proper directory search for now it's just hard coded. MStringArray effectNames; effectNames.append("PostProcess_SobelFilter"); effectNames.append("PostProcess_ToneMapFilter"); effectNames.append("PostProcess_InvertFilter"); for (unsigned int i=0; iGetBufferPointer(); MGlobal::displayInfo(MString("Compiler errors:\n") + MString(pCompilErrors) ); } } else { // Create a new effect item // PostEffectItem *pei = new PostEffectItem; if (pei) { pei->fEffect = effect; pei->fName = effectNames[i]; m_PostEffectItemList.push_back( pei ); } } } return (m_PostEffectItemList.size() > 0); } const MStringArray & D3DResourceManager::getListOfEnabledPostEffects() { // Find out which ones are enabled... // Should get via some UI interface. For now use Maya optionVars. // // e.g. optionVar -sv "D3D_EFFECTS_LIST" "PostProcess_ToneMapFilter" ; // e.g. optionVar -sv "D3D_EFFECTS_LIST" "PostProcess_ToneMapFilter,PostProcess_SobelFilter" ; // e.g. optionVar -sv "D3D_EFFECTS_LIST" "" ; // Clear the list m_EnabledPostEffectItemList.clear(); const MString effectListVar("D3D_EFFECTS_LIST"); //MString effectList("PostProcess_ToneMapFilter, PostProcess_SobelFilter"); MString effectList; if (!MGlobal::getOptionVarValue(effectListVar, effectList)) { // Create an option var if none previously existed. MGlobal::setOptionVarValue(effectListVar, effectList); } else { // Parse the effect list to get back a list of enabled effects // (in order). Note that there is not restriction on effect // list order, and duplicates are allowed. effectList.split(' ', m_EnabledPostEffectItemList); } return m_EnabledPostEffectItemList; } ////////////////////////////////////////////////////////// void D3DResourceManager::clearResources(bool onlyInvalidItems, bool clearShaders) { GeometryItemList::const_iterator git, end_git; end_git = m_geometryItemList.end(); for (git = m_geometryItemList.begin(); git != end_git; git++) { GeometryItem *item = *git; if (item) { if (!onlyInvalidItems || (onlyInvalidItems && !(item->m_objectPath.isValid() ))) { if (item->m_objectGeometry) { delete item->m_objectGeometry; item->m_objectGeometry = NULL; } item->m_objectPath = MDagPath(); // Assign invalid dag path // Kill the delete monitor if (item->m_objectDeleteMonitor) { MMessage::removeCallback( item->m_objectDeleteMonitor ); item->m_objectDeleteMonitor = 0; } // Kill the attr changed monitor if (item->m_objectChangeMonitor) { MMessage::removeCallback( item->m_objectChangeMonitor ); item->m_objectChangeMonitor = 0; } // Kill node dirty monitor if (item->m_objectDirtyMonitor) { MMessage::removeCallback( item->m_objectDirtyMonitor ); item->m_objectDirtyMonitor = 0; } } } } if (!onlyInvalidItems) m_geometryItemList.clear(); TextureItemList::const_iterator tit, end_tit; end_tit = m_textureItemList.end(); for (tit = m_textureItemList.begin(); tit != end_tit; tit++) { TextureItem *item = *tit; if (item) { if (!onlyInvalidItems || (onlyInvalidItems && !(item->m_mayaNode.isValid() ))) { if (item->m_texture) { delete item->m_texture; item->m_texture = NULL; } item->m_mayaNode = MObject::kNullObj; // Kill the delete monitor if (item->m_objectDeleteMonitor) { MMessage::removeCallback( item->m_objectDeleteMonitor ); item->m_objectDeleteMonitor = 0; } // Kill the attr changed monitor if (item->m_objectChangeMonitor) { MMessage::removeCallback( item->m_objectChangeMonitor ); item->m_objectChangeMonitor = 0; } } } } if (!onlyInvalidItems) m_textureItemList.clear(); if (clearShaders) { // Clean up post effects list PostEffectItemList::const_iterator eit, end_eit; end_eit = m_PostEffectItemList.end(); for (eit = m_PostEffectItemList.begin(); eit != end_eit; eit++) { PostEffectItem *item = *eit; if (item) { if (item->fEffect) { item->fEffect->Release(); item->fEffect = NULL; } delete item; } } m_PostEffectItemList.clear(); m_EnabledPostEffectItemList.clear(); } } #endif /* D3D9_SUPPORTED */