// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include #include #include #include #include #include #include "isSharedCmd.h" #include "libShave.h" #include "pluginImpl.h" #include "shaveBackgroundShader.h" #include "shaveBlindData.h" #include "shaveBrushCtxCmd.h" #include "shaveBrushManip.h" #include "shaveCutCtxCmd.h" #include "shaveDebug.h" #include "shaveCallbacks.h" #include "shaveGeometryOverride.h" #include "shaveGlobals.h" #include "shaveHairShape.h" #include "shaveHairUI.h" #include "shaveIconCmd.h" #include "shaveInfo.h" #include "shaveNode.h" #include "shaveNodeCmd.h" #include "shavePadCmd.h" #include "shaveRenderCmd.h" #include "shaveSDK.h" #include "shaveShadowNode.h" #include "shaveStyleCmd.h" #include "shaveTextureStore.h" #include "shaveUtilCmd.h" #include "shaveWriteHairCmd.h" #include "shaveVertexShader.h" #include "shaveVolumeShader.h" /// vlad|22Apr2010 -- include vray stuff #include "shaveVrayNode.h" #include "shaveVrayCmd.h" /// vlad|15Jun2011 -- procedurals #include "shaveProceduralsCmd.h" /// vlad|32apr2013 -- exp to image #include "shavePack2TexCmd.h" #include "shaveExportGame.h" #if !defined(OSMac_CFM_) && (!defined(_DEBUG) || defined(LINUX)) #include "shaveWriteRib.h" #endif #include // We use these flags to keep track of what has been registered. If we // get a failure partway through plugin initialization these will allow // the plugin to be unloaded without incurring even more errors. // static bool blindShaveData_isRegistered = false; static bool isSharedCmd_isRegistered = false; static bool shaveBrushCtxCmd_isRegistered = false; static bool shaveCutCtxCmd_isRegistered = false; static bool shaveIconCmd_isRegistered = false; static bool shaveInfo_isRegistered = false; static bool shaveNodeCmd_isRegistered = false; static bool shavePadCmd_isRegistered = false; static bool ShavePreprocTex_isRegistered = false; static bool shaveRenderCmd_isRegistered = false; static bool shaveStyleCmd_isRegistered = false; static bool shaveUtilCmd_isRegistered = false; static bool shaveWriteHairCmd_isRegistered = false; #if !defined(OSMac_CFM_) && (!defined(_DEBUG) || defined(LINUX)) static bool shaveWriteRib_isRegistered = false; #endif static bool shaveRepair_isRegistered = false; static bool shavePurge_isRegistered = false; static bool shaveBackgroundShader_isRegistered = false; static bool shaveBrushManip_isRegistered = false; static bool shaveGlobals_isRegistered = false; static bool shaveHairShape_isRegistered = false; static bool shaveNode_isRegistered = false; static bool shaveShadowNode_isRegistered = false; static bool shaveVertexShader_isRegistered = false; static bool shaveVolumeShader_isRegistered = false; static void popupError(MString title, MString msg) { MGlobal::displayError(msg); #if 0 // If you once had Shave hair in a scene but no longer do it's still // possible to end up with a 'requires' command in the scene file // which loads Shave. If you later try to edit that scene on a machine // which doesn't have Shave properly installed, you'll get these error // msgs. // // Users can live with the error msgs as they are used to them from // other plugins that fail their 'requires'. However they dislike // having to dismiss dialog boxes to continue working, so we've now // ifdefed out the popup dialogs if (MGlobal::mayaState() == MGlobal::kInteractive) { MString cmd; cmd = MString("confirmDialog -title \"") + title + "\" -button \"OK\" -message \"" + msg + "\""; MGlobal::executeCommand(cmd); } #endif } // // Plugin Registration // MStatus shaveInitializePlugin(MObject obj) { MStatus st; MString msg; MFnPlugin plugin(obj, "2019 Epic Games Maya Shave.", "1.1", "Any"); SHAVEinit(); // Before we go any further, let's make sure that the version of the // scripts matches the version of the plugin. // MString pluginVersion(SHAVEquery_version()); int haveVersionCmd; MGlobal::executeCommand("exists shaveVersion", haveVersionCmd); // Let's say that the user starts Maya and tries to load shave but // finds a mismatch. They leave Maya running while they copy the // correct scripts into their script directory. They then try loading // the plugin again. However, Maya will still have the old version of // the 'shaveVersion' command stored in memory. So we have to source // it to be sure that we get the new one. // if (haveVersionCmd && !MGlobal::executeCommand("source shaveVersion")) haveVersionCmd = false; if (!haveVersionCmd) { msg = "Cannot find the 'shaveVersion.mel' script. Shave appears\\n" "to not be properly installed on this machine. Please try\\n" "reinstalling Shave. If the problem persists then send mail\\n" "to shave-haircut-support@epicgames.com"; popupError("Shave Installation Error", msg); return MS::kFailure; } MString scriptVersion; MGlobal::executeCommand("shaveVersion", scriptVersion); if (scriptVersion != pluginVersion) { msg = MString("There is a mismatch between the Shave plugin, which is") + " for version " + pluginVersion + " of Shave, and the Shave" + " scripts, which are for version " + scriptVersion + " of Shave."; popupError("Shave Version Mismatch", msg); return MS::kFailure; } // // Register Data Types. // // Must be done before registering any nodes which use them. // REGISTER_DATA(blindShaveData) // // Register Nodes. // st = plugin.registerShape( shaveHairShape::nodeTypeName, shaveHairShape::id, &shaveHairShape::creator, &shaveHairShape::initialize, &shaveHairUI::creator, &shaveHairShape::drawDbClassification ); if (!st) st.perror("register shaveHairShape."); else shaveHairShape_isRegistered = true; st = plugin.registerNode( shaveBrushManip::nodeTypeName, shaveBrushManip::id, &shaveBrushManip::creator, &shaveBrushManip::initialize, MPxNode::kManipContainer, &shaveBrushManip::drawDbClassification ); if (!st) st.perror("register shave Brush."); else shaveBrushManip_isRegistered = true; REGISTER_NODE(shaveGlobals, kDependNode, 0) REGISTER_NODE(shaveShadowNode, kDependNode, 0) // // We need this to be able to load and convert pre-4.0 scenes. // REGISTER_NODE(shaveNode, kDependNode,0) // // The following are all render nodes, but only shaveBackgroundShader // is accessible to users. By not giving the others classification // strings they won't show up in the Hypershade window and users // won't be tempted to use them. // MString classification("shader/surface"); REGISTER_NODE(shaveBackgroundShader, kDependNode, &classification) REGISTER_NODE(shaveVertexShader, kDependNode, 0) REGISTER_NODE(shaveVolumeShader, kDependNode, 0) // // Register Commands. // REGISTER_CMD(shaveRepair) REGISTER_CMD(shavePurge) REGISTER_CMD(isSharedCmd) REGISTER_CMD(shaveIconCmd) REGISTER_CMD(shaveInfo); REGISTER_CMD(shaveNodeCmd) REGISTER_CMD(shavePadCmd) REGISTER_CMD(ShavePreprocTex) REGISTER_CMD(shaveRenderCmd) REGISTER_CMD(shaveStyleCmd) REGISTER_CMD(shaveUtilCmd) REGISTER_CMD(shaveWriteHairCmd) #if !defined(OSMac_CFM_) && (!defined(_DEBUG) || defined(LINUX)) REGISTER_CMD(shaveWriteRib) #endif REGISTER_CTX_CMD(shaveBrushCtxCmd); REGISTER_CTX_CMD(shaveCutCtxCmd); #ifdef USE_VRAY // vlad|22Apr2010 - register stuff needed by V-Ray //register the node const MString vclassification(shaveVrayNode::classification); st = plugin.registerNode( shaveVrayNode::typeName, shaveVrayNode::typeId, shaveVrayNode::creator, shaveVrayNode::initialize, MPxNode::kDependNode, &vclassification); if (!st) st.perror("register shaveVrayNode."); //register command st = plugin.registerCommand(shaveVrayCmd::cmd, shaveVrayCmd::creator, shaveVrayCmd::newSyntax); if (!st) st.perror("register shaveVrayCmd."); #endif #ifdef USE_PROCEDURALS st = plugin.registerCommand(shaveProceduralsCmd::cmd, shaveProceduralsCmd::creator, shaveProceduralsCmd::newSyntax); if (!st) st.perror("register shaveProceduralsCmd."); #endif st = MHWRender::MDrawRegistry::registerGeometryOverrideCreator( shaveHairShape::drawDbClassification, shaveHairShape::drawRegistrantId, shaveGeometryOverride::Creator); if (!st) st.perror("register shaveGeometryOverride."); #if MAYA_API_VERSION >= 201600 st = shaveGeometryOverride::registerComponentConverters(); if (!st) { st.perror("register shaveGeometryOverride component converters"); } #endif st = MHWRender::MDrawRegistry::registerGeometryOverrideCreator( shaveBrushManip::drawDbClassification, shaveBrushManip::drawRegistrantId, shaveBrushOverride::Creator); if (!st) st.perror("register shaveBrushOverride."); //register command st = plugin.registerCommand(shavePack2TexCmd::cmd, shavePack2TexCmd::creator, shavePack2TexCmd::newSyntax); if (!st) st.perror("register shavePack2TexCmd."); st = plugin.registerCommand(shaveExportGame::cmd, shaveExportGame::creator, shaveExportGame::newSyntax); if (!st) st.perror("register shaveExportGame."); if (MGlobal::mayaState() == MGlobal::kInteractive) { // Register selection type for the entire hair object. // int meshPriority = MSelectionMask::getSelectionTypePriority("polymesh"); if (!MSelectionMask::registerSelectionType(shaveHairShape::kShapeSelectionMaskName, meshPriority)) { std::cerr << "Error registering '" << shaveHairShape::kShapeSelectionMaskName << "' selection type." << std::endl; } // Add it to Maya's 'Surface' component menu. // st = MGlobal::executeCommand( MString("addSelectTypeItem(\"Surface\", \"") + shaveHairShape::kShapeSelectionMaskName + "\", \"Shave Hair\")" ); if (!st) { st.perror("addSelectTypeItem"); } } // Normally, we initialize SHAVE just before starting a new scene. // However, the plugin will typically be loaded into a scene after it // has already been started, so we have to force the initialization // here. // shaveCallbacks::prepareForNewScene(true); // Allow our CFGX shaders (and anyone else's, really) to be relocated // to the directory set in the SHAVE_SHADER_PATH envariable. // MString shaderPath = MCommonSystemUtils::getEnv("SHAVE_SHADER_PATH"); if (shaderPath.length() > 0) { MHWRender::MRenderer::theRenderer()->getShaderManager()->addShaderPath(shaderPath); } // We used to call the 'shaveUI' command ('shaveInit', actually) // directly, but that caused problems when the plugin was loaded // via a referenced file because the so-called "permanent" nodes, // such as defaultRenderGlobals, might not yet exist which then led to // many problems. By using registerUI() we're guaranteed that Maya // will have finished its own initialization before we do ours. // // However, even while disabled, the nodes can still call certain // basic MEL utility procedures, such as shaveExpandTempFilePath(), // so we must still force the sourcing of 'shaveUI.mel' right away, // rather than waiting until Maya calls shaveUI() for us. MGlobal::executeCommand("source shaveUI.mel"); //goes up 06may2014 plugin.registerUI("shaveUI", "", "shaveUI", ""); return st; } // // Plugin Registration // MStatus shaveUninitializePlugin(MObject obj) { MStatus st; MFnPlugin plugin(obj); shaveCallbacks::mayaExiting(); // // Remove all callbacks. // shaveCallbacks::removeCallbacks(); // We don't want to delete our hotkeySet in case the user has made // changes to it. But we should make sure that it's not the current // set. // MString keySet; MGlobal::executeCommand("hotkeySet -q -current", keySet); if (keySet == "Shave_Hotkeys") { MGlobal::executeCommand("hotkeySet -e -current Maya_Default"); } #if MAYA_API_VERSION >= 201600 st = shaveGeometryOverride::deregisterComponentConverters(); if (!st) { st.perror("deregistering shaveGeometryOverride component converters"); } #endif st = MHWRender::MDrawRegistry::deregisterGeometryOverrideCreator( shaveHairShape::drawDbClassification, shaveHairShape::drawRegistrantId); if (!st) st.perror("deregister shaveGeometryOverride."); st = MHWRender::MDrawRegistry::deregisterGeometryOverrideCreator( shaveBrushManip::drawDbClassification, shaveBrushManip::drawRegistrantId); if (!st) st.perror("deregister shaveBrushOverride."); // Deregister the various elements in the reverse order to which they // were registered. (Reversing the order may not be essential but is // generally the best approach to avoid problems.) // if (MGlobal::mayaState() == MGlobal::kInteractive) { // Custom selection types. // st = MGlobal::executeCommand( MString("deleteSelectTypeItem(\"Surface\", \"") + shaveHairShape::kShapeSelectionMaskName + "\")" ); if (!st) { st.perror("deleteSelectTypeItem"); } if (!MSelectionMask::deregisterSelectionType(shaveHairShape::kShapeSelectionMaskName)) { std::cerr << "Error deregistering '" << shaveHairShape::kShapeSelectionMaskName << "' selection type." << std::endl; } } DEREGISTER_CTX_CMD(shaveCutCtxCmd); DEREGISTER_CTX_CMD(shaveBrushCtxCmd); DEREGISTER_CMD(shaveRepair) DEREGISTER_CMD(shavePurge) #if !defined(OSMac_CFM_) && (!defined(_DEBUG) || defined(LINUX)) DEREGISTER_CMD(shaveWriteRib) #endif DEREGISTER_CMD(shaveWriteHairCmd) DEREGISTER_CMD(shaveUtilCmd) DEREGISTER_CMD(shaveStyleCmd) DEREGISTER_CMD(shaveRenderCmd) DEREGISTER_CMD(ShavePreprocTex) DEREGISTER_CMD(shavePadCmd) DEREGISTER_CMD(shaveNodeCmd) DEREGISTER_CMD(shaveInfo) DEREGISTER_CMD(shaveIconCmd) DEREGISTER_CMD(isSharedCmd) DEREGISTER_MANIP(shaveBrushManip) DEREGISTER_NODE(shaveVolumeShader) DEREGISTER_NODE(shaveVertexShader) DEREGISTER_NODE(shaveBackgroundShader) DEREGISTER_NODE(shaveNode) DEREGISTER_NODE(shaveShadowNode) DEREGISTER_NODE(shaveGlobals) DEREGISTER_NODE(shaveHairShape) DEREGISTER_DATA(blindShaveData); #ifdef USE_VRAY // vlad|22Apr2010 - deregister stuff needed by V-Ray st = plugin.deregisterNode( shaveVrayNode::typeId ); if (!st) st.perror("deregister shaveVrayNode."); st = plugin.deregisterCommand( shaveVrayCmd::cmd ); if (!st) st.perror("deregister shaveVrayCmd."); #endif #ifdef USE_PROCEDURALS st = plugin.deregisterCommand( shaveProceduralsCmd::cmd ); if (!st) st.perror("deregister shaveProceduralsCmd."); #endif st = plugin.deregisterCommand( shavePack2TexCmd::cmd ); if (!st) st.perror("deregister shavePack2TexCmd."); st = plugin.deregisterCommand( shaveExportGame::cmd ); if (!st) st.perror("deregister shaveExportGame."); return st; }