// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== // // // Creation Date: 2005 // // Description: // Create Merged Disk Cache // // proc disableCaches( string $cachesToDisable[] ) { string $cache; for ( $cache in $cachesToDisable ) { setAttr ($cache+".enable") false; } } proc string[] getAssociatedGeometry( string $caches[] ) { string $cache; string $cmd = "cacheFileMerge -q -geometry"; for( $cache in $caches ) { $cmd += (" " + $cache); } return eval($cmd); } proc string processObjects( string $objsToCache[], string $geomType ) { int $i = 0; string $flags = ""; string $shapes[] = `ls -type controlPoint`; int $numObjs = size($objsToCache); for( $i =0; $i < $numObjs; $i++ ) { if( stringArrayContains($objsToCache[$i], $shapes) && ($geomType != "fluid")) { $flags += (" -points " + $objsToCache[$i]); } else { $flags += (" -cacheableNode " + $objsToCache[$i]); } } return $flags; } proc string[] processArgs( int $version, string $args[], string $objsToCache[], float $start, float $end ) // // $version == 1: // $args[0] = If start/end time should be specified. Otherwise, calculate using lengths of caches being merged. // $args[1] = start time // $args[2] = end time // $args[3] = cache file distribution, either "OneFile" or "OneFilePerFrame" // $args[4] = directory for cache files, if "", then use project data dir // $args[5] = name of cache file. An empty string can be used to specify that an auto-generated name is acceptable. // $args[6] = 0/1, whether the specified cache name is to be used as a prefix // $args[7] = force save even if it overwrites existing files // $args[8] = simulation rate, the rate at which the cloth simulation is forced to run // $args[9] = sample mulitplier, the rate at which samples are written, as a multiple of simulation rate. // $args[10] = 0/1 if caches should be deleted after merge // $args[11] = "geom", "ncloth", or "fluid", the type of objects we're caching. Only needed if cache file nodes have not been // selected in trax. // // $version == 2: // $args[12] = name of cache format // // Returns: // $ret[0] = resolved cache directory name // $ret[1] = string of flags ready to be appended to a call to a cacheFile command // { string $distrib = $args[3]; string $cacheDirectory = $args[4]; string $fileName = $args[5]; int $useAsPrefix = $args[6]; int $force = $args[7]; float $simulationRate = $args[8]; int $sampleMultiplier = $args[9]; string $format = "mcx"; // Maya's default internal format if( $version > 1 ) { $format = $args[12]; } // Check if directory has caches that might be overwritten // $cacheDirectory = getCacheDirectory( $cacheDirectory, "fileCache", $objsToCache, $fileName, $useAsPrefix, 0, "add", $force, 1 ); if( $cacheDirectory == "" ) { error( (uiRes("m_doMergeCache.kInvalidDir"))); return {"", ""}; } else if ($cacheDirectory == "rename") { // must use eval deferred to ensure the hideOptionBox call from // doCreate* does not close our newly posted option box. // if (size($args) > 10) { if ($args[11] == "geom") { evalDeferred("performCreateGeometryCache 1 \"merge\""); } else if ($args[11] == "ncloth") { evalDeferred("performCreateNclothCache 1 \"merge\""); } else { evalDeferred("performCreateFluidCache 1 \"merge\""); } } error((uiRes("m_doMergeCache.kNameAlreadyInUse"))); return {"", ""}; } string $cmd; if( $fileName != "" ) { $cmd += ("-fileName \"" + $fileName + "\""); } if ( $cacheDirectory != "" ) { $cmd += (" -directory \"" + $cacheDirectory + "\""); } if( $useAsPrefix ) { $cmd += (" -prefix"); } $cmd += (" -format \"" + $distrib + "\""); $cmd += (" -startTime " + $start); $cmd += (" -endTime " + $end); $cmd += (" -simulationRate " + $simulationRate); $cmd += (" -sampleMultiplier " + $sampleMultiplier); $cmd += (" -singleCache"); $cmd += (" -cacheFormat " + $format ); $cmd += processObjects( $objsToCache, $args[11] ); string $ret[] = { $cmd, $cacheDirectory }; return $ret; } proc string getFileDirFlag( string $cacheFile, string $cacheDirectory ) { string $fileDirFlag = ("-fileName \"" + $cacheFile+"\"" ); if ($cacheDirectory != "") { $fileDirFlag += (" -directory \""+$cacheDirectory+"\" "); } return $fileDirFlag; } proc string[] createAndAttachCache( string $cmdFlags, string $cacheDirectory, string $objsToCache[], string $format, string $geomType ) { global string $gCacheGroupSeparator; // Create new, merged cache... string $cmd = "cacheFile -refresh "; $cmd += $cmdFlags; string $newCache[] = eval($cmd); string $cacheFileNodes[]; if( size($newCache) != 1 ) { error( (uiRes("m_doMergeCache.kInvalidMerge"))); } string $fileDirFlag = getFileDirFlag( $newCache[0], $cacheDirectory ); string $cacheFile = getCacheFilePath( $cacheDirectory, $newCache[0] ); // Attach cache to all the objects... string $cacheGroups[] = `getObjectsByCacheGroup($objsToCache)`; int $currGroup = 0; int $nextGroup = getNextCacheGroup($cacheGroups,$currGroup); string $currObjs[]; while ($nextGroup > $currGroup) { clear($currObjs); for ($ii = $currGroup; $ii < $nextGroup; $ii++) { if ($cacheGroups[$ii] != $gCacheGroupSeparator) { $currObjs[size($currObjs)] = $cacheGroups[$ii]; } } if (size($currObjs) > 0) { string $cacheBlend[] = getCacheBlend( $currObjs, "add" ); if (size($cacheBlend) > 0) { string $createCacheCmd = ("cacheFile -createCacheNode " ); $createCacheCmd += $fileDirFlag; $createCacheCmd += (" -cacheFormat " + $format ); // Fluids caches attach multiple channels to a single shape. Other // caches attach a single channel to multiple shapes. if ($geomType == "fluid") { string $queryCmd = "cacheFile -q -cacheableAttrs -cacheableNode " + $currObjs[0]; string $channels[] = `eval $queryCmd`; string $channelNames[]; int $ct = 0; for ($chn in $channels) { $channelNames[$ct++] = ($currObjs[0] + "_" + $chn); $createCacheCmd += (" -cnm " + ($currObjs[0] + "_" + $chn)); } string $cacheFileNode = `eval $createCacheCmd`; doFluidCacheConnect($cacheBlend[0], $cacheFileNode, $channelNames); } else { for ($obj in $currObjs) { $createCacheCmd += (" -cnm "+$obj); } string $cacheFileNode = `evalEcho $createCacheCmd`; $cacheFileNodes[size($cacheFileNodes)] = $cacheFileNode; doCacheConnect( $cacheBlend[0], $cacheFileNode, $currObjs, $currObjs ); } $createCacheCmd += (" -cacheFormat " + $format ); } else { error( (uiRes("m_doMergeCache.kBadBlend")) ); } $currGroup = $nextGroup; $nextGroup = getNextCacheGroup($cacheGroups,$currGroup); } } return $cacheFileNodes; } proc appendGaps( int $version, string $args[], string $newCache, string $objsToCache[], float $startEndTimes[], string $geomType ) { string $flags = "cacheFile -refresh -replaceCachedFrame"; if( $version >= 1 ) { $flags += " -simulationRate "; $flags += $args[8]; $flags += " -sampleMultiplier "; $flags += $args[9]; } string $format = "mcx"; // Maya's default internal format if( $version >= 2 ) { $format = $args[12]; } // make sure we append to the newly created merged cache $flags += " -cacheFileNode "; $flags += $newCache; // format info $flags += " -cacheFormat "; $flags += $format; string $objStr = processObjects( $objsToCache, $geomType ); int $i; int $numTimes = size($startEndTimes); for( $i = 3; $i < $numTimes; $i+=2 ) { string $cmd = $flags; $cmd += " -startTime "; $cmd += $startEndTimes[$i]; $cmd += " -endTime "; if( $i == ($numTimes-1) ) { $cmd += $startEndTimes[1]; } else { $cmd += $startEndTimes[$i+1]; } $cmd += $objStr; eval($cmd); } } global proc string[] doMergeCache( int $version, string $args[] ) // // Description: // Merge selected caches. Return name of new, merged cache. // // $version == 1: // $args[0] = 0/1 whether start/end time should be specified. Otherwise, use times of caches being merged. // $args[1] = start time // $args[2] = end time // $args[3] = cache file distribution, either "OneFile" or "OneFilePerFrame" // $args[4] = directory for cache files, if "", then use project data dir // $args[5] = name of cache file. An empty string can be used to specify that an auto-generated name is acceptable. // $args[6] = 0/1, whether the specified cache name is to be used as a prefix // $args[7] = force save even if it overwrites existing files // $args[8] = simulation rate, the rate at which the cloth simulation is forced to run // $args[9] = sample mulitplier, the rate at which samples are written, as a multiple of simulation rate. // $args[10] = "merge" or "mergeDelete", whether existing caches should be deleted from disk // $args[11] = "geom", "ncloth". If no caches are selected, use all caches on selected geometry/cloth objects // // $version == 2: // $args[12] = name of cache format // { if( ($version > 2) || ( size($args) > 13 )) { error( (uiRes("m_doMergeCache.kBadArgsError"))); return {}; } waitCursor -state on; int $useStartEnd = 0; float $startTime = 0.0; float $endTime = 0.0; int $deleteCaches = 0; string $geomType = "geom"; string $format = "mcx"; // Maya's default internal format $useStartEnd = $args[0]; $startTime = $args[1]; $endTime = $args[2]; $deleteCaches = ($args[10] == "mergeDelete"); $geomType = $args[11]; if( $version > 1 ) { $format = $args[12]; } string $objsToCache[]; string $cachesToMerge[] = `ls -sl -type cacheFile`; if( size($cachesToMerge) > 0 ) { $objsToCache = getAssociatedGeometry($cachesToMerge); } else { // No caches selected, so look at caches // on selected geometry if( $geomType == "geom" ) $objsToCache = getGeometriesToCache(); else if( $geomType == "ncloth" ) $objsToCache = getNclothObjectsToCache(0); else { $objsToCache = getFluidObjectsToCache(0); } string $obj; for( $obj in $objsToCache ) { $cachesToMerge = stringArrayCatenate( $cachesToMerge, findExistingCaches($obj) ); } clear($objsToCache); $objsToCache = getAssociatedGeometry($cachesToMerge); } // Validate cache selection and get start/end times // for any gaps. string $cache; string $mergeQueryCmd = "cacheFileMerge"; if( $version >= 1 && $args[0] == 1 ) { $mergeQueryCmd += (" -startTime " + $args[1]); $mergeQueryCmd += (" -endTime " + $args[2]); } for( $cache in $cachesToMerge ) { $mergeQueryCmd += (" " + $cache + " "); } float $startEndTimes[] = eval($mergeQueryCmd); int $numStartEnd = size($startEndTimes); if( $numStartEnd == 0 || $numStartEnd % 2 != 0 ) { error( (uiRes("m_doMergeCache.kBadTimesError")) ); waitCursor -state off; return {}; } float $start = $startEndTimes[0]; float $end = $startEndTimes[1]; // We have gaps between our caches, so only create a new cache up to the first gap. // All subsequent contiguous chunks will be appended to the merged cache later on. if( $numStartEnd > 2 ) { $end = $startEndTimes[2]; } string $ret[] = processArgs( $version, $args, $objsToCache, $start, $end ); string $newCaches[] = createAndAttachCache( $ret[0], $ret[1], $objsToCache, $format, $geomType ); for ($newCache in $newCaches) { appendGaps( $version, $args, $newCache, $objsToCache, $startEndTimes, $geomType ); } if (size($newCaches) > 0) { disableCaches( $cachesToMerge ); if( $deleteCaches ) { string $cacheList = stringArrayToString( $cachesToMerge, ","); string $delargs[] = { "delete", $cacheList }; deleteCacheFile(2, $delargs); } } waitCursor -state off; return $newCaches; }