BlendOpsNode.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. //https://www.shadertoy.com/view/XdS3RW
  4. //http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html
  5. //http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm
  6. using UnityEngine;
  7. using UnityEditor;
  8. using System;
  9. namespace AmplifyShaderEditor
  10. {
  11. public enum BlendOps
  12. {
  13. ColorBurn,
  14. ColorDodge,
  15. Darken,
  16. Divide,
  17. Difference,
  18. Exclusion,
  19. SoftLight,
  20. HardLight,
  21. HardMix,
  22. Lighten,
  23. LinearBurn,
  24. LinearDodge,
  25. LinearLight,
  26. Multiply,
  27. Overlay,
  28. PinLight,
  29. Subtract,
  30. Screen,
  31. VividLight
  32. }
  33. [Serializable]
  34. [NodeAttributes( "Blend Operations", "Image Effects", "Common layer blending modes" )]
  35. public class BlendOpsNode : ParentNode
  36. {
  37. //private const string ASEHardLightCall = "ASEHardLight({0},{1})";
  38. //private const string ASEHardLightFunc =
  39. //"inline float ASEHardLight( float srcLocalVar, float dstLocalVar ){" +
  40. //" return ( ( srcLocalVar > 0.5 ) ? ( 1.0 - ( 1.0 - 2.0 * ( srcLocalVar - 0.5 ) ) * ( 1.0 - dstLocalVar ) ) : ( 2.0 * srcLocalVar * dstLocalVar ) ); }";
  41. //private const string ASELinearLightCall = "ASELinearLight({0},{1})";
  42. //private const string ASELinearLightFunc =
  43. //"inline float ASELinearLight( float srcLocalVar, float dstLocalVar ){" +
  44. //" return ( ( srcLocalVar > 0.5 ) ? ( dstLocalVar + 2.0 * srcLocalVar - 1.0 ) : ( dstLocalVar + 2.0 * ( srcLocalVar - 0.5 ) ) ); }";
  45. //private const string ASEOverlayCall = "ASEOverlay({0},{1})";
  46. //private const string ASEOverlayFunc =
  47. //"inline float ASEOverlay( float srcLocalVar, float dstLocalVar ){" +
  48. //" return ( ( dstLocalVar > 0.5 ) ? ( 1.0 - ( 1.0 - 2.0 * ( dstLocalVar - 0.5 ) ) * ( 1.0 - srcLocalVar ) ) : ( 2.0 * dstLocalVar * srcLocalVar ) ); }";
  49. ////" return (dstLocalVar < 0.5) ? 2.0 * srcLocalVar * dstLocalVar : 1.0 - 2.0 * (1.0 - srcLocalVar) * (1.0 - dstLocalVar); }";
  50. //private const string ASEPinLightCall = "ASEPinLight({0},{1})";
  51. //private const string ASEPinLightFunc =
  52. //"inline float ASEPinLight( float srcLocalVar, float dstLocalVar ){" +
  53. //" return ( ( srcLocalVar > 0.5 ) ? max( dstLocalVar , 2.0 * ( srcLocalVar - 0.5 ) ) : min( dstLocalVar , 2.0 * srcLocalVar ) ); }";
  54. //private const string ASEVividLightCall = "ASEVividLight({0},{1})";
  55. //private const string ASEVividLightFunc = "inline float ASEVividLight( float srcLocalVar, float dstLocalVar ){" +
  56. //" return ( ( srcLocalVar > 0.5 ) ? ( dstLocalVar / ( ( 1.0 - srcLocalVar ) * 2.0 ) ) : ( 1.0 - ( ( ( 1.0 - dstLocalVar ) * 0.5 ) / srcLocalVar ) ) ); }";
  57. private const string ASEDarkerColorCall = "ASEDarkerColor{}({0},{1})";
  58. private const string ASEDarkerColorFunc = "inline float ASEDarkerColor{0}( float srcLocalVar, float dstLocalVar ){" +
  59. " return ({1} < {2}) ? s : d; }";
  60. private const string ASELighterColorCall = "ASELighterColor{}({0},{1})";
  61. private const string ASELighterColorFunc = "inline float ASELighterColor{0}( float srcLocalVar, float dstLocalVar ){" +
  62. " return ({1} > {2}) ? s : d; }";
  63. private const string BlendOpsModeStr = "Blend Op";
  64. private const string SaturateResultStr = "Saturate";
  65. [SerializeField]
  66. private BlendOps m_currentBlendOp = BlendOps.ColorBurn;
  67. [SerializeField]
  68. private WirePortDataType m_mainDataType = WirePortDataType.COLOR;
  69. [SerializeField]
  70. private bool m_saturate = true;
  71. private UpperLeftWidgetHelper m_upperLeftWidget = new UpperLeftWidgetHelper();
  72. protected override void CommonInit( int uniqueId )
  73. {
  74. base.CommonInit( uniqueId );
  75. AddInputPort( WirePortDataType.COLOR, false, "Source" );
  76. AddInputPort( WirePortDataType.COLOR, false, "Destiny" );
  77. AddInputPort( WirePortDataType.FLOAT, false,"Alpha" );
  78. m_inputPorts[ 2 ].FloatInternalData = 1;
  79. AddOutputPort( WirePortDataType.COLOR, Constants.EmptyPortValue );
  80. m_inputPorts[ 0 ].AddPortForbiddenTypes( WirePortDataType.FLOAT3x3,
  81. WirePortDataType.FLOAT4x4,
  82. WirePortDataType.SAMPLER1D,
  83. WirePortDataType.SAMPLER2D,
  84. WirePortDataType.SAMPLER3D,
  85. WirePortDataType.SAMPLERCUBE,
  86. WirePortDataType.SAMPLER2DARRAY );
  87. m_inputPorts[ 1 ].AddPortForbiddenTypes( WirePortDataType.FLOAT3x3,
  88. WirePortDataType.FLOAT4x4,
  89. WirePortDataType.SAMPLER1D,
  90. WirePortDataType.SAMPLER2D,
  91. WirePortDataType.SAMPLER3D,
  92. WirePortDataType.SAMPLERCUBE,
  93. WirePortDataType.SAMPLER2DARRAY );
  94. m_textLabelWidth = 75;
  95. m_autoWrapProperties = true;
  96. m_hasLeftDropdown = true;
  97. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, m_currentBlendOp ) );
  98. m_useInternalPortData = true;
  99. m_previewShaderGUID = "6d6b3518705b3ba49acdc6e18e480257";
  100. }
  101. public override void SetPreviewInputs()
  102. {
  103. base.SetPreviewInputs();
  104. m_previewMaterialPassId = (int)m_currentBlendOp;
  105. PreviewMaterial.SetInt( "_Sat", m_saturate ? 1 : 0 );
  106. int lerpMode = ( m_inputPorts[ 2 ].IsConnected || m_inputPorts[ 2 ].FloatInternalData < 1 ) ? 1 : 0;
  107. PreviewMaterial.SetInt( "_Lerp", lerpMode );
  108. }
  109. public override void AfterCommonInit()
  110. {
  111. base.AfterCommonInit();
  112. if( PaddingTitleLeft == 0 )
  113. {
  114. PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  115. if( PaddingTitleRight == 0 )
  116. PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  117. }
  118. }
  119. public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true )
  120. {
  121. base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode );
  122. UpdateConnection( portId );
  123. }
  124. public override void OnConnectedOutputNodeChanges( int inputPortId, int otherNodeId, int otherPortId, string name, WirePortDataType type )
  125. {
  126. base.OnConnectedOutputNodeChanges( inputPortId, otherNodeId, otherPortId, name, type );
  127. UpdateConnection( inputPortId );
  128. }
  129. public override void OnInputPortDisconnected( int portId )
  130. {
  131. base.OnInputPortDisconnected( portId );
  132. UpdateDisconnection( portId );
  133. }
  134. void UpdateConnection( int portId )
  135. {
  136. if( portId == 2 )
  137. return;
  138. m_inputPorts[ portId ].MatchPortToConnection();
  139. int otherPortId = ( portId + 1 ) % 2;
  140. if( m_inputPorts[ otherPortId ].IsConnected )
  141. {
  142. m_mainDataType = UIUtils.GetPriority( m_inputPorts[ 0 ].DataType ) > UIUtils.GetPriority( m_inputPorts[ 1 ].DataType ) ? m_inputPorts[ 0 ].DataType : m_inputPorts[ 1 ].DataType;
  143. }
  144. else
  145. {
  146. m_mainDataType = m_inputPorts[ portId ].DataType;
  147. m_inputPorts[ otherPortId ].ChangeType( m_mainDataType, false );
  148. }
  149. m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
  150. }
  151. void UpdateDisconnection( int portId )
  152. {
  153. if( portId == 2 )
  154. return;
  155. int otherPortId = ( portId + 1 ) % 2;
  156. if( m_inputPorts[ otherPortId ].IsConnected )
  157. {
  158. m_mainDataType = m_inputPorts[ otherPortId ].DataType;
  159. m_inputPorts[ portId ].ChangeType( m_mainDataType, false );
  160. m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
  161. }
  162. }
  163. public override void DrawProperties()
  164. {
  165. base.DrawProperties();
  166. EditorGUI.BeginChangeCheck();
  167. m_currentBlendOp = (BlendOps)EditorGUILayoutEnumPopup( BlendOpsModeStr, m_currentBlendOp );
  168. if( EditorGUI.EndChangeCheck() )
  169. {
  170. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, m_currentBlendOp ) );
  171. }
  172. m_saturate = EditorGUILayoutToggle( SaturateResultStr, m_saturate );
  173. }
  174. public override void Draw( DrawInfo drawInfo )
  175. {
  176. base.Draw( drawInfo );
  177. m_upperLeftWidget.DrawWidget<BlendOps>( ref m_currentBlendOp, this, OnWidgetUpdate );
  178. }
  179. private readonly Action<ParentNode> OnWidgetUpdate = ( x ) =>
  180. {
  181. x.SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, ( x as BlendOpsNode ).m_currentBlendOp ) );
  182. };
  183. private string CreateMultiChannel( ref MasterNodeDataCollector dataCollector, string function, string srcLocalVar, string dstLocalVar, string varName )
  184. {
  185. switch( m_outputPorts[ 0 ].DataType )
  186. {
  187. default:
  188. {
  189. return string.Format( function, srcLocalVar, dstLocalVar );
  190. }
  191. case WirePortDataType.FLOAT2:
  192. {
  193. string xChannelName = varName + OutputId + "X";
  194. string xChannelValue = string.Format( function, srcLocalVar + ".x", dstLocalVar + ".x" );
  195. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, xChannelName, xChannelValue );
  196. string yChannelName = varName + OutputId + "Y";
  197. string yChannelValue = string.Format( function, srcLocalVar + ".y", dstLocalVar + ".y" );
  198. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, yChannelName, yChannelValue );
  199. return string.Format( "float2({0},{1})", xChannelName, yChannelName );
  200. }
  201. case WirePortDataType.FLOAT3:
  202. {
  203. string xChannelName = varName + OutputId + "X";
  204. string xChannelValue = string.Format( function, srcLocalVar + ".x", dstLocalVar + ".x" );
  205. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, xChannelName, xChannelValue );
  206. string yChannelName = varName + OutputId + "Y";
  207. string yChannelValue = string.Format( function, srcLocalVar + ".y", dstLocalVar + ".y" );
  208. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, yChannelName, yChannelValue );
  209. string zChannelName = varName + OutputId + "Z";
  210. string zChannelValue = string.Format( function, srcLocalVar + ".z", dstLocalVar + ".z" );
  211. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, zChannelName, zChannelValue );
  212. return string.Format( "float3({0},{1},{2})", xChannelName, yChannelName, zChannelName );
  213. }
  214. case WirePortDataType.FLOAT4:
  215. case WirePortDataType.COLOR:
  216. {
  217. string xChannelName = varName + OutputId + "X";
  218. string xChannelValue = string.Format( function, srcLocalVar + ".x", dstLocalVar + ".x" );
  219. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, xChannelName, xChannelValue );
  220. string yChannelName = varName + OutputId + "Y";
  221. string yChannelValue = string.Format( function, srcLocalVar + ".y", dstLocalVar + ".y" );
  222. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, yChannelName, yChannelValue );
  223. string zChannelName = varName + OutputId + "Z";
  224. string zChannelValue = string.Format( function, srcLocalVar + ".z", dstLocalVar + ".z" );
  225. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, zChannelName, zChannelValue );
  226. string wChannelName = varName + OutputId + "W";
  227. string wChannelValue = string.Format( function, srcLocalVar + ".w", dstLocalVar + ".w" );
  228. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, WirePortDataType.FLOAT, wChannelName, wChannelValue );
  229. return string.Format( "float4({0},{1},{2},{3})", xChannelName, yChannelName, zChannelName, wChannelName );
  230. }
  231. }
  232. }
  233. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  234. {
  235. if( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  236. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  237. string src = m_inputPorts[ 0 ].GenerateShaderForOutput( ref dataCollector, m_mainDataType, false, true );
  238. string dst = m_inputPorts[ 1 ].GenerateShaderForOutput( ref dataCollector, m_mainDataType, false, true );
  239. string srcLocalVar = "blendOpSrc" + OutputId;
  240. string dstLocalVar = "blendOpDest" + OutputId;
  241. dataCollector.AddLocalVariable( UniqueId, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_mainDataType ) + " " + srcLocalVar, src + ";" );
  242. dataCollector.AddLocalVariable( UniqueId, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_mainDataType ) + " " + dstLocalVar, dst + ";" );
  243. int currIndent = UIUtils.ShaderIndentLevel;
  244. if( dataCollector.MasterNodeCategory == AvailableShaderTypes.Template )
  245. {
  246. UIUtils.ShaderIndentLevel = 0;
  247. }
  248. else
  249. {
  250. UIUtils.ShaderIndentLevel = 1;
  251. UIUtils.ShaderIndentLevel++;
  252. }
  253. string result = string.Empty;
  254. switch( m_currentBlendOp )
  255. {
  256. case BlendOps.ColorBurn:
  257. {
  258. result = string.Format( "( 1.0 - ( ( 1.0 - {0}) / max( {1}, 0.00001) ) )", dstLocalVar, srcLocalVar);
  259. }
  260. break;
  261. case BlendOps.ColorDodge:
  262. {
  263. result = string.Format( "( {0}/ max( 1.0 - {1}, 0.00001 ) )", dstLocalVar, srcLocalVar );
  264. }
  265. break;
  266. case BlendOps.Darken:
  267. {
  268. result = "min( " + srcLocalVar + " , " + dstLocalVar + " )";
  269. }
  270. break;
  271. case BlendOps.Divide:
  272. {
  273. result = string.Format( "( {0} / max({1},0.00001) )", dstLocalVar, srcLocalVar );
  274. }
  275. break;
  276. case BlendOps.Difference:
  277. {
  278. result = "abs( " + srcLocalVar + " - " + dstLocalVar + " )";
  279. }
  280. break;
  281. case BlendOps.Exclusion:
  282. {
  283. result = "( 0.5 - 2.0 * ( " + srcLocalVar + " - 0.5 ) * ( " + dstLocalVar + " - 0.5 ) )";
  284. }
  285. break;
  286. case BlendOps.SoftLight:
  287. {
  288. result = string.Format( "2.0f*{0}*{1} + {0}*{0}*(1.0f - 2.0f*{1})", dstLocalVar, srcLocalVar );
  289. }
  290. break;
  291. case BlendOps.HardLight:
  292. {
  293. result = " (( " + srcLocalVar + " > 0.5 ) ? ( 1.0 - ( 1.0 - 2.0 * ( " + srcLocalVar + " - 0.5 ) ) * ( 1.0 - " + dstLocalVar + " ) ) : ( 2.0 * " + srcLocalVar + " * " + dstLocalVar + " ) )";
  294. //dataCollector.AddFunction( ASEHardLightCall, UIUtils.ShaderIndentTabs + ASEHardLightFunc );
  295. //result = CreateMultiChannel( ref dataCollector, ASEHardLightCall, srcLocalVar, dstLocalVar, "hardLightBlend" );
  296. }
  297. break;
  298. case BlendOps.HardMix:
  299. {
  300. result = " round( 0.5 * ( " + srcLocalVar + " + " + dstLocalVar + " ) )";
  301. }
  302. break;
  303. case BlendOps.Lighten:
  304. {
  305. result = " max( " + srcLocalVar + ", " + dstLocalVar + " )";
  306. }
  307. break;
  308. case BlendOps.LinearBurn:
  309. {
  310. result = "( " + srcLocalVar + " + " + dstLocalVar + " - 1.0 )";
  311. }
  312. break;
  313. case BlendOps.LinearDodge:
  314. {
  315. result = "( " + srcLocalVar + " + " + dstLocalVar + " )";
  316. }
  317. break;
  318. case BlendOps.LinearLight:
  319. {
  320. result = "(( " + srcLocalVar + " > 0.5 )? ( " + dstLocalVar + " + 2.0 * " + srcLocalVar + " - 1.0 ) : ( " + dstLocalVar + " + 2.0 * ( " + srcLocalVar + " - 0.5 ) ) )";
  321. //dataCollector.AddFunction( ASELinearLightCall, UIUtils.ShaderIndentTabs + ASELinearLightFunc );
  322. //result = CreateMultiChannel( ref dataCollector, ASELinearLightCall, srcLocalVar, dstLocalVar, "linearLightBlend" );
  323. }
  324. break;
  325. case BlendOps.Multiply:
  326. {
  327. result = "( " + srcLocalVar + " * " + dstLocalVar + " )";
  328. }
  329. break;
  330. case BlendOps.Overlay:
  331. {
  332. //result = "(( " + dstLocalVar + " > 0.5 ) ? ( 1.0 - ( 1.0 - 2.0 * ( " + dstLocalVar + " - 0.5 ) ) * ( 1.0 - " + srcLocalVar + " ) ) : ( 2.0 * " + dstLocalVar + " * " + srcLocalVar + " ) )";
  333. result = "(( " + dstLocalVar + " > 0.5 ) ? ( 1.0 - 2.0 * ( 1.0 - " + dstLocalVar + " ) * ( 1.0 - " + srcLocalVar + " ) ) : ( 2.0 * " + dstLocalVar + " * " + srcLocalVar + " ) )";
  334. //dataCollector.AddFunction( ASEOverlayCall, UIUtils.ShaderIndentTabs + ASEOverlayFunc );
  335. //result = CreateMultiChannel( ref dataCollector, ASEOverlayCall, srcLocalVar, dstLocalVar, "overlayBlend" );
  336. }
  337. break;
  338. case BlendOps.PinLight:
  339. {
  340. result = "(( " + srcLocalVar + " > 0.5 ) ? max( " + dstLocalVar + ", 2.0 * ( " + srcLocalVar + " - 0.5 ) ) : min( " + dstLocalVar + ", 2.0 * " + srcLocalVar + " ) )";
  341. //dataCollector.AddFunction( ASEPinLightCall, UIUtils.ShaderIndentTabs + ASEPinLightFunc );
  342. //result = CreateMultiChannel( ref dataCollector, ASEPinLightCall, srcLocalVar, dstLocalVar, "pinLightBlend" );
  343. }
  344. break;
  345. case BlendOps.Subtract:
  346. {
  347. result = "( " + dstLocalVar + " - " + srcLocalVar + " )";
  348. }
  349. break;
  350. case BlendOps.Screen:
  351. {
  352. result = "( 1.0 - ( 1.0 - " + srcLocalVar + " ) * ( 1.0 - " + dstLocalVar + " ) )";
  353. }
  354. break;
  355. case BlendOps.VividLight:
  356. {
  357. result = string.Format( "(( {0} > 0.5 ) ? ( {1} / max( ( 1.0 - {0} ) * 2.0 ,0.00001) ) : ( 1.0 - ( ( ( 1.0 - {1} ) * 0.5 ) / max( {0},0.00001) ) ) )", srcLocalVar, dstLocalVar);
  358. //dataCollector.AddFunction( ASEVividLightCall, UIUtils.ShaderIndentTabs + ASEVividLightFunc );
  359. //result = CreateMultiChannel( ref dataCollector, ASEVividLightCall, srcLocalVar, dstLocalVar, "vividLightBlend" );
  360. }
  361. break;
  362. }
  363. UIUtils.ShaderIndentLevel = currIndent;
  364. if( m_inputPorts[ 2 ].IsConnected || m_inputPorts[ 2 ].FloatInternalData < 1.0 )
  365. {
  366. string opacity = m_inputPorts[ 2 ].GeneratePortInstructions( ref dataCollector );
  367. string lerpVar = "lerpBlendMode" + OutputId;
  368. string lerpResult = string.Format( "lerp({0},{1},{2})", dstLocalVar, result, opacity );
  369. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, m_outputPorts[ 0 ].DataType, lerpVar, lerpResult );
  370. result = lerpVar;
  371. }
  372. if( m_saturate )
  373. result = "( saturate( " + result + " ))";
  374. return CreateOutputLocalVariable( 0, result, ref dataCollector );
  375. }
  376. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  377. {
  378. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  379. IOUtils.AddFieldValueToString( ref nodeInfo, m_currentBlendOp );
  380. IOUtils.AddFieldValueToString( ref nodeInfo, m_saturate );
  381. }
  382. public override void ReadFromString( ref string[] nodeParams )
  383. {
  384. base.ReadFromString( ref nodeParams );
  385. m_currentBlendOp = (BlendOps)Enum.Parse( typeof( BlendOps ), GetCurrentParam( ref nodeParams ) );
  386. m_saturate = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  387. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, m_currentBlendOp ) );
  388. }
  389. public override void Destroy()
  390. {
  391. base.Destroy();
  392. m_upperLeftWidget = null;
  393. }
  394. }
  395. }