// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include #include #include "shaveIO.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #define fileno _fileno #define fstat _fstat typedef struct _stat StatType; #include #else #include typedef struct stat StatType; #endif #include "shaveConstant.h" #include "shaveDebug.h" #include "shaveGlobals.h" #include "shaveHairShape.h" #include "shaveMaya.h" #include "shaveVrayRenderer.h" #include "shaveRender.h" #include "shaveRenderer.h" #include "shaveSDK.h" #include "shaveUtil.h" #include "shaveVraySharedFunctions.h" #if defined(OSMac_) #include "shaveMacCarbon.h" #endif #ifdef USE_VRAY static MString draFile; shaveVrayRenderer::shaveVrayRenderer() : mTimeState(shaveVrayRenderer::kAwaitingNothing) { //MGlobal::displayInfo(" new shaveVrayRenderer"); exportOK = false; } shaveVrayRenderer::~shaveVrayRenderer() {} void shaveVrayRenderer::renderStart() { #ifdef _DEBUG MGlobal::displayInfo("shaveVrayRenderer::renderStart"); #endif ENTER(); MGlobal::getActiveSelectionList( list ); char buf[200]; time_t t; time(&t); srand((unsigned int)t); int r1 = rand(); int r2 = rand(); sprintf(buf,"vrayHair_%i%i.dra",r1,r2); tempDra = buf; MString fileDir; MGlobal::executeCommand("eval(\"internalVar -userTmpDir\")",fileDir); //MString fileName = fileDir + "vrayHair.dra"; MString tempFile; MGlobal::executeCommand("eval(\"getAttr shaveGlobals.vrayDraFile\");",tempFile); if(tempFile == "" ) tempFile = tempDra; fileName = fileDir + tempFile; #if defined(OSMac_) && !defined(OSMac_MachO_) MString testFile = shaveMacCarbon::makeMacFilename(fileDir + MString("vray_Shave.tmp")); #else MString testFile = fileDir + MString("vray_Shave.tmp"); #endif ioError = true; FILE* testFileH = fopen(testFile.asChar(),"w"); if(testFileH) { int nb = fprintf(testFileH,"hello"); if(nb == strlen("hello")) ioError = false; fclose(testFileH); } if(ioError) { MGlobal::displayError(MString("shaveVrayRenderer: can not write to dir ")+fileDir+MString(". Giving up.")); LEAVE(); return; } else MGlobal::displayInfo(MString("shaveVrayRenderer: ")+fileDir+MString(" is writable.")); // not neeeded any more //mIsAnimation = false; //mFirstFrame; //mIsFirstFrame= true; //MSelectionList renderGlobalsList; //renderGlobalsList.clear(); //renderGlobalsList.add("defaultRenderGlobals"); //if (renderGlobalsList.length() > 0) //{ // MObject rgNode; // renderGlobalsList.getDependNode(0, rgNode); // MFnDependencyNode depFn(rgNode); // int animOn = 0; // MPlug animOnPlug = depFn.findPlug("animation"); // if(!animOnPlug.isNull()) // { // animOnPlug.getValue(animOn); // MGlobal::displayInfo(MString("anim ") + animOn); // mIsAnimation = (animOn == 1); // if(mIsAnimation) // { // MTime startF; // MPlug startFPlug = depFn.findPlug("startFrame"); // if(!animOnPlug.isNull()) // { // startFPlug.getValue(startF); // mFirstFrame = startF; // MGlobal::displayInfo(MString("start frame ") + startF.value()); // } // } // } // else // MGlobal::displayError("shave: can find plug."); //} //else // MGlobal::displayError("shave: can not get defaultRenderGlobals."); //set up vraySettings.preKeyframeMel MStatus stat; MSelectionList vraySettingsList; vraySettingsList.add("vraySettings"); bool doCreate = false; if (vraySettingsList.length() > 0) { MObject vraySettingsNode; vraySettingsList.getDependNode(0, vraySettingsNode); MFnDependencyNode depFn(vraySettingsNode); MPlug preKeyframeMelPlug = depFn.findPlug("preKeyframeMel"); if(!preKeyframeMelPlug.isNull()) { MString kf("shaveRender -vrayKeyframe"); stat = preKeyframeMelPlug.setValue(kf); if(stat != MStatus::kSuccess) MGlobal::displayError("shave: can not set vraySettings.preKeyframeMel"); } else MGlobal::displayError("shave: can not find vraySettings.preKeyframeMel"); } else { //MGlobal::executeCommand("createNode -name vraySettings VRaySettingsNode"); // //it is better to use the procedure - vrayCreateVRaySettingsNode() //It will check whether the node has already been created and create it if not. //It will also register vraySettings as a global node for the V-Ray renderer. //This is important for render settings presets (although V-Ray will register the //node even if you created it manually, but still). vrayCreateVRaySettingsNode() //also creates the vraySettings node as shared which is important when referencing //the particular scene in another one. MGlobal::executeCommand("vrayCreateVRaySettingsNode"); doCreate = true; } if(doCreate) { vraySettingsList.add("vraySettings"); if (vraySettingsList.length() > 0) { MObject vraySettingsNode; vraySettingsList.getDependNode(0, vraySettingsNode); MFnDependencyNode depFn(vraySettingsNode); MPlug preKeyframeMelPlug = depFn.findPlug("preKeyframeMel"); if(!preKeyframeMelPlug.isNull()) { MString kf("shaveRender -vrayKeyframe"); stat = preKeyframeMelPlug.setValue(kf); if(stat != MStatus::kSuccess) MGlobal::displayError("shave: can not set vraySettings.preKeyframeMel"); } else MGlobal::displayError("shave: can not find vraySettings.preKeyframeMel"); } else MGlobal::displayError("shave: can not get vraySettings."); } //execute shave stuff shaveRenderer::renderStart(); ///create shaders MGlobal::executeCommand("shaveVrayShader -create -all"); //MGlobal::executeCommand("shaveVrayShader -addCallback"); ////forse to set stack ids MObjectArray shaveShapes; getRenderableShaveNodesByRenderMode(NULL, &shaveShapes); for(unsigned int i = 0; i < shaveShapes.length(); i++) { MFnDependencyNode nodeFn(shaveShapes[i]); shaveHairShape* hairShape = (shaveHairShape*)nodeFn.userNode(); hairShape->setStackIndex(i); } shaveShapes.clear(); LEAVE(); } void shaveVrayRenderer::vrayKeyframeCallback() { #ifdef _DEBUG MGlobal::displayInfo("shaveVrayRenderer::vrayKeyframeCallback"); #endif if(ioError) return; ENTER(); MStatus stat; bool isFirstSample = false; bool isLastSample = false; int numS = 0; int curS = 0; stat = MGlobal::executeCommand("eval(\"vrayRenderInfo -numKeyframes\")",numS); stat = MGlobal::executeCommand("eval(\"vrayRenderInfo -currentKeyframe\")",curS); MTime curTime = MAnimControl::currentTime(); MString dbgStr = MString("preKeyframeMel numKeyframes: ") + numS + MString(" currentKeyframe: ") + curS + MString(" currentTime: ") + curTime.value(); if(numS == 1) { isFirstSample = true; isLastSample = true; } else { shaveMaya::doMotionBlur = true; if(curS == 0) isFirstSample = true; if(curS == numS-1) isLastSample = true; } if(isFirstSample) { //not good place at all, prmitieves do not render //MGlobal::executeCommand("shaveVrayShader -delete -all"); //MGlobal::executeCommand("shaveVrayShader -create -all"); dbgStr += MString(" << firstSample"); // // Get the nodes to be rendered as geometry, and those to be rendered // not as geometry, into two separate lists. // mGeometryNodes.clear(); mNonGeometryNodes.clear(); getRenderableShaveNodesByRenderMode(&mGeometryNodes, &mNonGeometryNodes); // // Changes in animated attributes may have changed the list of // renderable shaveHairShapes. Let's update the flags telling us which // types of shaveHairShapes we have. // bool tempHaveHair; bool tempHaveInstances; shaveUtil::classifyShaveNodes(mGeometryNodes, tempHaveHair, tempHaveInstances); shaveUtil::classifyShaveNodes(mNonGeometryNodes, mHaveHair, mHaveInstances); mHaveHair = (mHaveHair || tempHaveHair); mHaveInstances = (mHaveInstances || tempHaveInstances); //do shutter // // // If motion blur is on, do shutter open and wait for shutter close. // If motion blur is off, do both shutter open and shutter close now. // if (shaveMaya::doMotionBlur) { doShutter(curTime, shaveConstant::kShutterOpen); mTimeState = kAwaitingShutterClose; } else { //doShutter(curTime, shaveConstant::kShutterBoth); //mTimeState = kAwaitingNothing; mTimeState = kAwaitingShutterBoth; } } if(isLastSample) { dbgStr += MString(" << lastSample"); switch (mTimeState) { case kAwaitingShutterClose: doShutter(curTime, shaveConstant::kShutterClose); mTimeState = kAwaitingNothing; break; case kAwaitingShutterBoth: doShutter(curTime, shaveConstant::kShutterBoth); mTimeState = kAwaitingNothing; break; default: break; } // joexxx // SHAVEclear_stack(); //gr, too late //MGlobal::executeCommand("shaveVrayShader -delete -all"); //MGlobal::executeCommand("shaveVrayShader -create -all"); } //joexxxxxx SHAVEclear_stack(); //MGlobal::displayInfo(dbgStr); LEAVE(); } void shaveVrayRenderer::frameStart(const shaveGlobals::Globals& g) { #ifdef _DEBUG MGlobal::displayInfo("shaveVrayRenderer::frameStart"); #endif if(ioError) return; //here it's confused at all only the last layer renders correctly //MGlobal::executeCommand("shaveVrayShader -delete -all"); //MGlobal::executeCommand("shaveVrayShader -create -all"); #if 0 //do nothing - vrayKeyframeCallback is used instead ENTER(); shaveRenderer::frameStart(g); // // If motion blur is on, do shutter open and wait for shutter close. // If motion blur is off, do both shutter open and shutter close now. // MTime curTime = MAnimControl::currentTime(); MGlobal::displayInfo(MString("blur ") + shaveMaya::doMotionBlur + " time " + curTime.value()); if (shaveMaya::doMotionBlur) { //if(mIsAnimation && mIsFirstFrame) //{ // curTime = mFirstFrame - 0.5;//+ 1.0; // MAnimControl::setCurrentTime(curTime); //} doShutter(curTime, shaveConstant::kShutterOpen); mTimeState = kAwaitingShutterClose; } else { //doShutter(curTime, shaveConstant::kShutterBoth); //mTimeState = kAwaitingNothing; mTimeState = kAwaitingShutterBoth; } mIsFirstFrame = false; LEAVE(); #endif } void shaveVrayRenderer::render( float frame, shaveConstant::ShutterState shutter, const MDagPath& camera ) { #ifdef _DEBUG MGlobal::displayInfo("shaveVrayRenderer::render"); #endif if(ioError) return; ENTER(); bool isShutterClose = (shutter == shaveConstant::kShutterClose) ||(shutter == shaveConstant::kShutterBoth); if(isShutterClose) { //MString fileDir; //MGlobal::executeCommand("eval(\"internalVar -userTmpDir\")",fileDir); ////MString fileName = fileDir + "vrayHair.dra"; //MString tempFile; //MGlobal::executeCommand("eval(\"getAttr shaveGlobals.vrayDraFile\");",tempFile); //MGlobal::displayInfo(MString("tempFile :") + tempFile); //if(tempFile == "" ) // tempFile = tempDra; //fileName = fileDir + tempFile; //MGlobal::displayInfo(MString("export :") + fileName); //MGlobal::displayInfo(MString("tempDra :") + tempDra); //SHAVEmult_vox_size(g.voxelScaling); #if defined(OSMac_) && !defined(OSMac_MachO_) hfsFileName = shaveMacCarbon::makeMacFilename(fileName); int res = SHAVEexport_archive((char*)hfsFileName.asChar(), voxelResolutionGlob); #else int res = SHAVEexport_archive((char*)fileName.asChar(), voxelResolutionGlob); #endif // SHAVEclear_stack(); //nope does not help //I hate such approaches, but ... MObjectArray vnodes; FindNodesByTypeId(shaveVrayNode::typeId,vnodes); const char *draFilename; #if defined(OSMac_) && !defined(OSMac_MachO_) MString hfsFileName = shaveMacCarbon::makeMacFilename(fileName); draFilename = hfsFileName.asChar(); #else draFilename = fileName.asChar(); #endif if(vnodes.length() > 0) { for(unsigned int i = 0; i < vnodes.length(); i++) { MFnDependencyNode dFn(vnodes[i]); shaveVrayNode* vnode = (shaveVrayNode*)dFn.userNode(); vnode->readDraToParam(draFilename); } } exportOK = (res != -1); } LEAVE(); } void shaveVrayRenderer::frameEnd(const shaveGlobals::Globals& g) { (void) g; #if 0 //do nothing - vrayKeyframeCallback is used instead ENTER(); shaveRenderer::frameEnd(g); LEAVE(); #endif } void shaveVrayRenderer::renderEnd() { //MGlobal::displayInfo("shaveVrayRenderer::renderEnd"); if(ioError) return; ENTER(); //re-set up vraySettings.preKeyframeMel MStatus stat; MSelectionList vraySettingsList; vraySettingsList.clear(); vraySettingsList.add("vraySettings"); if (vraySettingsList.length() > 0) { MObject vraySettingsNode; vraySettingsList.getDependNode(0, vraySettingsNode); MFnDependencyNode depFn(vraySettingsNode); MPlug preKeyframeMelPlug = depFn.findPlug("preKeyframeMel"); if(!preKeyframeMelPlug.isNull()) { MString kf(""); stat = preKeyframeMelPlug.setValue(kf); if(stat != MStatus::kSuccess) MGlobal::displayError("shave: can not reset vraySettings.preKeyframeMel"); } else MGlobal::displayError("shave: can not find vraySettings.preKeyframeMel"); } else MGlobal::displayError("shave: can not get vraySettings."); shaveRenderer::renderEnd(); MGlobal::executeCommand("shaveVrayShader -delete -all"); //MGlobal::executeCommand("shaveVrayShader -removeCallback"); //MString fileDir; //MGlobal::executeCommand("eval(\"internalVar -userTmpDir\")",fileDir); MString tempFile; MGlobal::executeCommand("eval(\"getAttr shaveGlobals.vrayDraFile\");",tempFile); if(fileName.length() > 0 && tempFile == "") { if(remove(fileName.asChar()) == -1) MGlobal::displayInfo(MString("shave: can not delete ")+fileName); } MGlobal::setActiveSelectionList( list, MGlobal::kReplaceList); LEAVE(); } void shaveVrayRenderer::timeChange(const MTime& newTime) { if(ioError) return; #if 0 //do nothing - vrayKeyframeCallback is used instead ENTER(); switch (mTimeState) { case kAwaitingShutterOpen: doShutter(newTime, shaveConstant::kShutterOpen); if (shaveRenderCancelled) mTimeState = kAwaitingNothing; else mTimeState = kAwaitingShutterClose; break; case kAwaitingShutterClose: doShutter(newTime, shaveConstant::kShutterClose); mTimeState = kAwaitingNothing; break; case kAwaitingShutterBoth: doShutter(newTime, shaveConstant::kShutterBoth); mTimeState = kAwaitingNothing; break; default: break; } LEAVE(); #endif } bool shaveVrayRenderer::isGeomNode(const shaveHairShape* nodePtr) const { return false; //if (nodePtr->isInstanced()) return false; //return (getRenderMode() == shaveConstant::kGeometryRender); } #endif //USE_VRAY