////////////
//
//  Script: senReuseTriangles 0.1.4
//  Updated: 17 May 2008
//  Compatibility: Maya 8 and higher
//  Probably works with earlier versions, too.
//
//
//  Written by Sven-Erik Neve
//  Website and contact info: www.seneve.de
//  Bugs, comments, questions or suggestions? Get in touch!
//
//
//  Usage:
//  Use the senReuseTriangles command to start the script.
//  Select at least one for example polygon object, choose
//  whether to enable or to disable reuseTriangles and
//  confirm your choice.
//
//
//  Installation:
//  Copy this source code within a MEL file to one of your
//  scripts folders, for example on Windows XP 32-bit to the
//  folder \My Documents\maya\<version>\scripts. Start Maya
//  or (if it is running) use the rehash command to make Maya
//  aware of the newly copied script. Execute the script with
//  the senReuseTriangles command. In the script's ZIP archive
//  you'll also find an XPM icon that you can copy for example
//  to \My Documents\maya\<version>\prefs\icons.
//
//
//  Purpose:
//  By default Maya reevaluates triangles on the fly which
//  may cause textures to flicker when you animate an object.
//  The reuseTriangles attribute controls this. All mesh nodes
//  have it. This script allows you to enable reuseTriangles
//  so that Maya literally reuses the triangle positions from
//  your object's bind pose instead of recalculating them
//  on the fly. This in turn stops textures from flickering.
//
////////////

// Set version and date of last modification
proc string[] versionInfo() {
	string $version = "0.1.4";
	string $modDate = "17 May 2008";
	string $scriptInfo[] = {$version, $modDate};
	return $scriptInfo;
}

// Run this when the window is about to be closed, clean up
global proc senReuseTrianglesCloseWindow(string $window) {
	deleteUI $window;
	// If user wants to reset settings, do it
	if (`optionVar -ex senReuseTrianglesReset`) {
		if (`windowPref -ex $window`) windowPref -r $window;
		optionVar -rm senReuseTrianglesReset;
		if (`optionVar -ex senReuseTrianglesCurrentValue`) {
			optionVar -rm senReuseTrianglesCurrentValue;
		}
		if (`optionVar -ex senReuseTrianglesSavedValue`) {
			optionVar -rm senReuseTrianglesSavedValue;
		}
	}
}

// Count selected objects in total and mesh nodes in selection
proc int[] countObjs() {
	string $meshes[] = sort(`ls -sl -dag -lf -typ mesh`);
	int $counter[] = {(size(`ls -sl`)), (size($meshes))};
	return $counter;
}

// On window creation, determine which radio button shall be selected
proc int getSavedValue() {
	int $rtriState = 1;
	if (`optionVar -ex senReuseTrianglesSavedValue`) {
		$rtriState = `optionVar -q senReuseTrianglesSavedValue`;
	}
	optionVar -iv senReuseTrianglesCurrentValue $rtriState;
	return $rtriState;
}

// On selection change, determine which radio button is _now_ selected
global proc int senReuseTrianglesGetCurrentValue() {
	int $rtriState = 1;
	if (`optionVar -ex senReuseTrianglesCurrentValue`) {
		$rtriState = `optionVar -q senReuseTrianglesCurrentValue`;
	}
	return $rtriState;
}

// When another radio button is selected save which one it is
global proc senReuseTrianglesSetRadioBtnState(string $rtriRadioBtns) {
	int $rtriState = (2 - `radioButtonGrp -q -sl $rtriRadioBtns`);
	optionVar -iv senReuseTrianglesCurrentValue $rtriState;
}

// Create info texts to inform user of script status
proc string[] createTexts(int $counter[]) {
	string $report;
	string $instruct;
	float $statusColor[];
	string $texts[];

	if (!$counter[0]) {
		$report = "Nothing selected.\n";
		$instruct = "Select at least one for example polygon object.";
		$statusColor = {0.9, 0.15, 0.0};
	}
 	else if ($counter[0] && !$counter[1]) {
 		$report = "No mesh nodes in selection.\n";
 		$instruct = "Select at least one for example polygon object.";
		$statusColor = {1.0, 0.7, 0.1};
 	}
 	else {
 		$report = "You're good to go.\n";
 		$instruct = "Enable reuseTriangles to make sure " +
 			"textures don't flicker.";
		$statusColor = {0.27, 0.8, 0.0};
	}
 	$texts = {$report, $instruct, $statusColor[0], $statusColor[1], $statusColor[2]};
 	return $texts;
}

// Save settings
global proc senReuseTrianglesSaveSettings(string $rtriRadioBtns) {
	int $rtriState = (2 - `radioButtonGrp -q -sl $rtriRadioBtns`);
	optionVar -iv senReuseTrianglesCurrentValue $rtriState;
	optionVar -iv senReuseTrianglesSavedValue $rtriState;
}

// Reset settings; actual reset occurs when window closes
global proc senReuseTrianglesResetSettings(string $rtriRadioBtns) {
	optionVar -iv senReuseTrianglesSavedValue 1;
	radioButtonGrp -e -sl 1 $rtriRadioBtns;
	optionVar -iv senReuseTrianglesReset 1;
}

// Get length of Help window just before the user changes something
global proc int senReuseTrianglesGetHelpMenuLen(string $helpMenu) {
	int $helpMenuLen = `window -q -h $helpMenu`;
	return $helpMenuLen;
}

// Change length of Help window when user opens and closes frameLayouts
global proc senReuseTrianglesHelpMenuChangeLen(int $frame, int $incLen, int $helpMenuLen, string $helpMenu) {
	if ($incLen) {
		if ($frame) window -e -h ($helpMenuLen + 110) $helpMenu;
		else window -e -h ($helpMenuLen + 200) $helpMenu;
	}
	else {
		if ($frame) window -e -h ($helpMenuLen - 110) $helpMenu;
		else window -e -h ($helpMenuLen - 200) $helpMenu;
	}
}

// Create Help menu
global proc senReuseTrianglesHelpMenu(string $script) {
	int $helpMenuLen = 350;
	string $helpMenu = ($script + "HelpWindow");
	string $versionInfo[] = versionInfo();

	// If Help window already exists delete it
	if (`window -ex $helpMenu`) deleteUI $helpMenu;
	if (`windowPref -ex $helpMenu`) windowPref -r $helpMenu;
	window -t ($script + " Help") -mb true -wh 400 $helpMenuLen $helpMenu;

	showWindow $helpMenu;

	// Create formLayout to accommodate four frames
	string $helpMenuFrame = `formLayout "helpMenuFrame"`;

		// "About" frame
		string $helpAbout = `frameLayout
			-l ("About " + $script + "\n") -bs "etchedIn"
			-la center -li 5 -mw 10 -mh 10 "helpAboutHeadlineFrame"`;
			string $helpAboutText = `text -l ("Version: " + $versionInfo[0] + "\n" +
				"Updated: " + $versionInfo[1] + "\n" +
				"Compatibility: Maya 8 and higher\n" +
				"Probably works with earlier versions, too.\n\n" +
				"Written by Sven-Erik Neve\n" +
				"Website and contact info: www.seneve.de\n" +
				"Bugs, comments, questions or suggestions? Get in touch!") "helpAboutText"`;
		setParent ..;

		// "Usage (summary)" frame
		string $helpUsageShort = `frameLayout
			-l ("Usage (summary)") -bs "etchedIn"
			-la center -li 5 -mw 10 -mh 10 "helpUsageShortFrame"`;
			string $helpUsageShortText = `text -l ("Select at least one for example polygon object, choose whether\n" +
				"to enable or to disable reuseTriangles and confirm your choice.") "helpUsageShortText"`;
		setParent ..;

		// "Usage (in-depth)" frame
		string $helpUsageLong = `frameLayout
			-l ("Usage (in-depth)") -bs "etchedIn" -cll true -cl true
			-pec ("senReuseTrianglesHelpMenuChangeLen(0, 1, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-pcc ("senReuseTrianglesHelpMenuChangeLen(0, 0, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-la center -li 5 -mw 10 -mh 10 "helpUsageLongFrame"`;
			string $helpUsageLongText = `text -l ("Select an object that contains a mesh node, for example select a\n" +
				"polygon object. The script's Status will inform you at all times whether\n" +
				"your selection contains a mesh node or not. Once you have something\n" +
				"selected that contains at least one mesh node the script is ready to go.\n\n" +
				"Select whether you want to enable or disable reuseTriangles for the mesh\n" +
				"nodes in your selection. The default setting is Enable. Confirm your choice\n" +
				"with either the Set button (runs the script and closes the window) or with\n" +
				"the Apply button (runs the script, leaves the windw open).\n\n" +
				"The main window also has a menu to save and reset the settings.\n" +
				"Save Settings saves the settings even if you don't run the script.\n" +
				"Reset Settings resets the settings and - contrary to regular Maya\n" +
				"windows - also resets the window position.") "helpUsageLongText"`;
		setParent ..;

		// "Purpose" frame
		string $helpPurpose = `frameLayout
			-l ("Purpose") -bs "etchedIn" -cll true -cl true
			-pec ("senReuseTrianglesHelpMenuChangeLen(1, 1, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-pcc ("senReuseTrianglesHelpMenuChangeLen(1, 0, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-la center -li 5 -mw 10 -mh 10 "helpPurposeFrame"`;
			string $helpPurposeText = `text -l ("By default Maya reevaluates triangles on the fly which may cause\n" +
				"textures to flicker when you animate an object. The reuseTriangles\n" +
				"attribute controls this. All mesh nodes have it.\n\n" +
				"This script allows you to enable reuseTriangles so that Maya literally\n" +
				"reuses the triangle positions from your object's bind pose instead of\n" +
				"recalculating them on the fly. This in turn stops textures from flickering.") "helpPurposeText"`;
		setParent ..;

		// Create Close button and correctly align all elements
		string $closeButton = `button -l "Close" -h 25 -c ("deleteUI(\"" + $helpMenu + "\")") "helpMenuCloseButton"`;
		formLayout -e
			-af $helpAbout top 5
			-af $helpAbout left 5
			-af $helpAbout right 5

			-af $helpUsageShort left 5
			-af $helpUsageShort right 5
			-ac $helpUsageShort top 5 $helpAbout

			-af $helpUsageLong left 5
			-af $helpUsageLong right 5
			-ac $helpUsageLong top 5 $helpUsageShort

			-af $helpPurpose left 5
			-af $helpPurpose right 5
			-ac $helpPurpose top 5 $helpUsageLong

			-af $closeButton bottom 5
			-ap $closeButton left 0 33
			-ap $closeButton right 0 66
		$helpMenuFrame;
	setParent ..;
}

// Set the selected meshes' reuseTriangles attributes and print a report
global proc senReuseTrianglesRtriSwitcher(int $rtriState, int $closeWindow, string $window, string $rtriRadioBtns) {
	string $meshes[] = sort(`ls -sl -dag -lf -typ mesh`);
	string $list;
	string $listShort[];
	string $resultOff = "reuseTriangles is now disabled for";
	string $resultOn = "reuseTriangles is now enabled for";
	string $result;
	int $counter[] = {(size(`ls -sl`)), (size($meshes))};

	if ($rtriState) $result = $resultOn;
	else $result = $resultOff;

	for ($element in $meshes) setAttr ($element + ".rtri") $rtriState;

	if ($counter[1] >= 2) {
		appendStringArray($listShort, $meshes, ($counter[1] - 1));
		$list = (stringArrayToString($listShort, ", "));
		$list = ($list + " and " + $meshes[$counter[1] - 1] + ".\n");
		print ($result + " the " + $counter[1] + " mesh nodes " + $list);
	}
	else print ($result + " the mesh node " + $meshes[0] + ".\n");
	senReuseTrianglesSaveSettings($rtriRadioBtns);
	if ($closeWindow) senReuseTrianglesCloseWindow($window);
}

// Create layout with Status frame and radio button group
proc string layoutTopAndBottom(int $rtriState, int $counter[], string $window, string $layAll) {
	string $rtriText = "reuseTriangles:";
	string $texts[] = createTexts($counter);
	string $annStatus = ("Script status: " + (match ("[^\n]*", $texts[0])) + " " + $texts[1]);
	string $annSettings = $rtriText + " Enable " +
		"to stop textures from flickering.";

	// Create frame for Status and Settings
	string $topFrame = `columnLayout -adj true -rs 5 -co both 5 "topFrame"`;

		// Frame for status text and traffic light icon
		string $statusFrame = `frameLayout
			-l "Status" -bs "etchedIn"
			-la center -li 5 -mw 5 -mh 5 "statusFrame"`;
			string $statusForm = `formLayout -nd 100 "statusForm"`;
				string $statusIcon = `formLayout
					-w 15 -h 15
					-bgc (float($texts[2])) (float($texts[3])) (float($texts[4])) "statusIcon"`;
				setParent ..;
				string $textColumn = `columnLayout
					-adj true
					-cal center "textColumn"`;
					string $statusText = `text -ann $annStatus -l ($texts[0] + $texts[1]) "statusText"`;
				setParent ..;
				formLayout -e
					-af $statusIcon left 5
					-af $statusIcon top 5

					-af $textColumn left 30
					-af $textColumn right 0
				$statusForm;
			setParent ..;
		setParent ..;

		// Frame for radio button group
		string $settingsFrame = `frameLayout
			-l "Settings" -bs "etchedIn"
			-la center -li 5 -mw 5 -mh 5 "settingsFrame"`;
			string $radioColumn = `columnLayout
				-adj true
				-cal center "radioColumn"`;
				string $rtriRadioBtns = `radioButtonGrp
					-nrb 2 -vr -l $rtriText
					-la2 "Enable" "Disable"
					-ann $annSettings
					-sl (2 - $rtriState) "rtriRadioBtns"`;
			radioButtonGrp -e -cc ("senReuseTrianglesSetRadioBtnState(\"" + $rtriRadioBtns + "\")") $rtriRadioBtns;
			setParent ..;
		setParent ..;

	setParent ..;

	// Frame for the Set, Apply and Close buttons
	string $bottomFrame = `formLayout -nd 20 "bottomFrame"`;
		string $b1 = `button -l "Set" -h 25 -c ("senReuseTrianglesRtriSwitcher((senReuseTrianglesGetCurrentValue()), 1, \"" + $window + "\", \"" + $rtriRadioBtns + "\")") "setButton"`;
		string $b2 = `button -l "Apply" -h 25 -c ("senReuseTrianglesRtriSwitcher((senReuseTrianglesGetCurrentValue()), 0, \"" + $window + "\", \"" + $rtriRadioBtns + "\")") "applyButton"`;
		string $b3 = `button -l "Close" -h 25 -c ("senReuseTrianglesCloseWindow(\"" + $window + "\")") "closeButton"`;

		if (!$counter[1]) {
			button -e -en false $b1;
			button -e -en false $b2;
		}

		// Correctly align the buttons
		formLayout -e
			-af $b1 bottom 5
			-af $b1 left 5
			-ap $b1 right 5 7
			-an $b1 top

			-af $b2 bottom 5
			-ac $b2 left 5 $b1
			-ac $b2 right 5 $b3
			-an $b2 top

			-af $b3 bottom 5
			-af $b3 right 5
			-ap $b3 left 5 13
			-an $b3 top
		$bottomFrame;
	setParent;

	// Correctly align the two frames
	formLayout -e
		-af $topFrame right 0
		-af $topFrame left 0
		-af $bottomFrame bottom 0
		-af $bottomFrame right 0
		-af $bottomFrame left 0
	$layAll;
	return $rtriRadioBtns;
}

// Either create formLayout or just update its content
global proc string senReuseTrianglesCreateLayout(int $rtriState, string $window, string $layout) {
	windowPref -sa;
	if (`formLayout -ex $layout`) {
		deleteUI -lay $layout;
		$rtriState = senReuseTrianglesGetCurrentValue();
	}

	int $counter[] = countObjs();

	string $layAll = `formLayout -p $window $layout`;
	string $rtriRadioBtns = (layoutTopAndBottom($rtriState, $counter, $window, $layAll));
	setParent ..;
	return $rtriRadioBtns;
}

// Create main window and fill in content
proc createWindow() {
	string $script = "senReuseTriangles";
	string $window = ($script + "Window");
	string $layout = ($script + "Layout");

	if (`window -ex $window`) deleteUI $window;
	window -t $script -mb true -wh 400 250 $window;

	int $rtriState = getSavedValue();

	string $rtriRadioBtns = (senReuseTrianglesCreateLayout($rtriState, $window, $layout));

	// Create Edit and Help menus
	string $mainEditMenu = `menu -l "Edit" "editMenu"`;
		string $mainEdit1 = `menuItem -l "Save Settings" -c ("senReuseTrianglesSaveSettings(\"" + $rtriRadioBtns + "\")") "editMenuSave"`;
		string $mainEdit2 = `menuItem -l "Reset Settings" -c ("senReuseTrianglesResetSettings(\"" + $rtriRadioBtns + "\")") "editMenuReset"`;
	string $mainHelpMenu = `menu -l "Help" -hm true "helpMenu"`;
		string $mainHelp1 = `menuItem -l ("Help on " + $script) -c ("senReuseTrianglesHelpMenu(\"" + $script + "\")") "helpMenuHelp"`;

	showWindow $window;

	// Start a scriptJob to run as long as the window exists
	int $jobNum = `scriptJob -e "SelectionChanged" ("senReuseTrianglesCreateLayout(\"" + $rtriState + "\", \"" + $window + "\", \"" + $layout + "\")") -p $window`;
}

// Procedure to start the script
global proc senReuseTriangles() {
	createWindow();
}

senReuseTriangles MEL script. This script controls the reuseTriangles attribute and thus flickerung textures of animated objects. Firstly, it checks if the current selection contains at least one mesh node. Since only mesh nodes have the reuseTriangles (rtri) attribute anyway the script can only be run if there's at least one of them in the selection. If that's the case the script changes rtri to either 0 or 1 – depending on what the user has chosen. Lastly, it reports which mesh nodes were affected by the change.

Download this script (6.79 KiByte)
Maya 8 or higher, probably works with earlier versions, too.