You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

523 lines
22 KiB

  1. using UnityEngine;
  2. using System.Linq;
  3. using System.Collections;
  4. namespace TMPro
  5. {
  6. public static class ShaderUtilities
  7. {
  8. // Shader Property IDs
  9. public static int ID_MainTex;
  10. public static int ID_FaceTex;
  11. public static int ID_FaceColor;
  12. public static int ID_FaceDilate;
  13. public static int ID_Shininess;
  14. public static int ID_UnderlayColor;
  15. public static int ID_UnderlayOffsetX;
  16. public static int ID_UnderlayOffsetY;
  17. public static int ID_UnderlayDilate;
  18. public static int ID_UnderlaySoftness;
  19. public static int ID_WeightNormal;
  20. public static int ID_WeightBold;
  21. public static int ID_OutlineTex;
  22. public static int ID_OutlineWidth;
  23. public static int ID_OutlineSoftness;
  24. public static int ID_OutlineColor;
  25. public static int ID_Padding;
  26. public static int ID_GradientScale;
  27. public static int ID_ScaleX;
  28. public static int ID_ScaleY;
  29. public static int ID_PerspectiveFilter;
  30. public static int ID_TextureWidth;
  31. public static int ID_TextureHeight;
  32. public static int ID_BevelAmount;
  33. public static int ID_GlowColor;
  34. public static int ID_GlowOffset;
  35. public static int ID_GlowPower;
  36. public static int ID_GlowOuter;
  37. public static int ID_LightAngle;
  38. public static int ID_EnvMap;
  39. public static int ID_EnvMatrix;
  40. public static int ID_EnvMatrixRotation;
  41. //public static int ID_MaskID;
  42. public static int ID_MaskCoord;
  43. public static int ID_ClipRect;
  44. public static int ID_MaskSoftnessX;
  45. public static int ID_MaskSoftnessY;
  46. public static int ID_VertexOffsetX;
  47. public static int ID_VertexOffsetY;
  48. public static int ID_UseClipRect;
  49. public static int ID_StencilID;
  50. public static int ID_StencilOp;
  51. public static int ID_StencilComp;
  52. public static int ID_StencilReadMask;
  53. public static int ID_StencilWriteMask;
  54. public static int ID_ShaderFlags;
  55. public static int ID_ScaleRatio_A;
  56. public static int ID_ScaleRatio_B;
  57. public static int ID_ScaleRatio_C;
  58. public static string Keyword_Bevel = "BEVEL_ON";
  59. public static string Keyword_Glow = "GLOW_ON";
  60. public static string Keyword_Underlay = "UNDERLAY_ON";
  61. public static string Keyword_Ratios = "RATIOS_OFF";
  62. //public static string Keyword_MASK_OFF = "MASK_OFF";
  63. public static string Keyword_MASK_SOFT = "MASK_SOFT";
  64. public static string Keyword_MASK_HARD = "MASK_HARD";
  65. public static string Keyword_MASK_TEX = "MASK_TEX";
  66. public static string Keyword_Outline = "OUTLINE_ON";
  67. public static string ShaderTag_ZTestMode = "unity_GUIZTestMode";
  68. public static string ShaderTag_CullMode = "_CullMode";
  69. private static float m_clamp = 1.0f;
  70. public static bool isInitialized = false;
  71. /// <summary>
  72. ///
  73. /// </summary>
  74. static ShaderUtilities()
  75. {
  76. GetShaderPropertyIDs();
  77. }
  78. /// <summary>
  79. ///
  80. /// </summary>
  81. public static void GetShaderPropertyIDs()
  82. {
  83. if (isInitialized == false)
  84. {
  85. //Debug.Log("Getting Shader property IDs");
  86. isInitialized = true;
  87. ID_MainTex = Shader.PropertyToID("_MainTex");
  88. ID_FaceTex = Shader.PropertyToID("_FaceTex");
  89. ID_FaceColor = Shader.PropertyToID("_FaceColor");
  90. ID_FaceDilate = Shader.PropertyToID("_FaceDilate");
  91. ID_Shininess = Shader.PropertyToID("_FaceShininess");
  92. ID_UnderlayColor = Shader.PropertyToID("_UnderlayColor");
  93. ID_UnderlayOffsetX = Shader.PropertyToID("_UnderlayOffsetX");
  94. ID_UnderlayOffsetY = Shader.PropertyToID("_UnderlayOffsetY");
  95. ID_UnderlayDilate = Shader.PropertyToID("_UnderlayDilate");
  96. ID_UnderlaySoftness = Shader.PropertyToID("_UnderlaySoftness");
  97. ID_WeightNormal = Shader.PropertyToID("_WeightNormal");
  98. ID_WeightBold = Shader.PropertyToID("_WeightBold");
  99. ID_OutlineTex = Shader.PropertyToID("_OutlineTex");
  100. ID_OutlineWidth = Shader.PropertyToID("_OutlineWidth");
  101. ID_OutlineSoftness = Shader.PropertyToID("_OutlineSoftness");
  102. ID_OutlineColor = Shader.PropertyToID("_OutlineColor");
  103. ID_Padding = Shader.PropertyToID("_Padding");
  104. ID_GradientScale = Shader.PropertyToID("_GradientScale");
  105. ID_ScaleX = Shader.PropertyToID("_ScaleX");
  106. ID_ScaleY = Shader.PropertyToID("_ScaleY");
  107. ID_PerspectiveFilter = Shader.PropertyToID("_PerspectiveFilter");
  108. ID_TextureWidth = Shader.PropertyToID("_TextureWidth");
  109. ID_TextureHeight = Shader.PropertyToID("_TextureHeight");
  110. ID_BevelAmount = Shader.PropertyToID("_Bevel");
  111. ID_LightAngle = Shader.PropertyToID("_LightAngle");
  112. ID_EnvMap = Shader.PropertyToID("_Cube");
  113. ID_EnvMatrix = Shader.PropertyToID("_EnvMatrix");
  114. ID_EnvMatrixRotation = Shader.PropertyToID("_EnvMatrixRotation");
  115. ID_GlowColor = Shader.PropertyToID("_GlowColor");
  116. ID_GlowOffset = Shader.PropertyToID("_GlowOffset");
  117. ID_GlowPower = Shader.PropertyToID("_GlowPower");
  118. ID_GlowOuter = Shader.PropertyToID("_GlowOuter");
  119. //ID_MaskID = Shader.PropertyToID("_MaskID");
  120. ID_MaskCoord = Shader.PropertyToID("_MaskCoord");
  121. ID_ClipRect = Shader.PropertyToID("_ClipRect");
  122. ID_UseClipRect = Shader.PropertyToID("_UseClipRect");
  123. ID_MaskSoftnessX = Shader.PropertyToID("_MaskSoftnessX");
  124. ID_MaskSoftnessY = Shader.PropertyToID("_MaskSoftnessY");
  125. ID_VertexOffsetX = Shader.PropertyToID("_VertexOffsetX");
  126. ID_VertexOffsetY = Shader.PropertyToID("_VertexOffsetY");
  127. ID_StencilID = Shader.PropertyToID("_Stencil");
  128. ID_StencilOp = Shader.PropertyToID("_StencilOp");
  129. ID_StencilComp = Shader.PropertyToID("_StencilComp");
  130. ID_StencilReadMask = Shader.PropertyToID("_StencilReadMask");
  131. ID_StencilWriteMask = Shader.PropertyToID("_StencilWriteMask");
  132. ID_ShaderFlags = Shader.PropertyToID("_ShaderFlags");
  133. ID_ScaleRatio_A = Shader.PropertyToID("_ScaleRatioA");
  134. ID_ScaleRatio_B = Shader.PropertyToID("_ScaleRatioB");
  135. ID_ScaleRatio_C = Shader.PropertyToID("_ScaleRatioC");
  136. }
  137. }
  138. // Scale Ratios to ensure property ranges are optimum in Material Editor
  139. public static void UpdateShaderRatios(Material mat)
  140. {
  141. //Debug.Log("UpdateShaderRatios() called.");
  142. float ratio_A = 1;
  143. float ratio_B = 1;
  144. float ratio_C = 1;
  145. bool isRatioEnabled = !mat.shaderKeywords.Contains(Keyword_Ratios);
  146. // Compute Ratio A
  147. float scale = mat.GetFloat(ID_GradientScale);
  148. float faceDilate = mat.GetFloat(ID_FaceDilate);
  149. float outlineThickness = mat.GetFloat(ID_OutlineWidth);
  150. float outlineSoftness = mat.GetFloat(ID_OutlineSoftness);
  151. float weight = Mathf.Max(mat.GetFloat(ID_WeightNormal), mat.GetFloat(ID_WeightBold)) / 4.0f;
  152. float t = Mathf.Max(1, weight + faceDilate + outlineThickness + outlineSoftness);
  153. ratio_A = isRatioEnabled ? (scale - m_clamp) / (scale * t) : 1;
  154. //float ratio_A_old = mat.GetFloat(ID_ScaleRatio_A);
  155. // Only set the ratio if it has changed.
  156. //if (ratio_A != ratio_A_old)
  157. mat.SetFloat(ID_ScaleRatio_A, ratio_A);
  158. // Compute Ratio B
  159. if (mat.HasProperty(ID_GlowOffset))
  160. {
  161. float glowOffset = mat.GetFloat(ID_GlowOffset);
  162. float glowOuter = mat.GetFloat(ID_GlowOuter);
  163. float range = (weight + faceDilate) * (scale - m_clamp);
  164. t = Mathf.Max(1, glowOffset + glowOuter);
  165. ratio_B = isRatioEnabled ? Mathf.Max(0, scale - m_clamp - range) / (scale * t) : 1;
  166. //float ratio_B_old = mat.GetFloat(ID_ScaleRatio_B);
  167. // Only set the ratio if it has changed.
  168. //if (ratio_B != ratio_B_old)
  169. mat.SetFloat(ID_ScaleRatio_B, ratio_B);
  170. }
  171. // Compute Ratio C
  172. if (mat.HasProperty(ID_UnderlayOffsetX))
  173. {
  174. float underlayOffsetX = mat.GetFloat(ID_UnderlayOffsetX);
  175. float underlayOffsetY = mat.GetFloat(ID_UnderlayOffsetY);
  176. float underlayDilate = mat.GetFloat(ID_UnderlayDilate);
  177. float underlaySoftness = mat.GetFloat(ID_UnderlaySoftness);
  178. float range = (weight + faceDilate) * (scale - m_clamp);
  179. t = Mathf.Max(1, Mathf.Max(Mathf.Abs(underlayOffsetX), Mathf.Abs(underlayOffsetY)) + underlayDilate + underlaySoftness);
  180. ratio_C = isRatioEnabled ? Mathf.Max(0, scale - m_clamp - range) / (scale * t) : 1;
  181. //float ratio_C_old = mat.GetFloat(ID_ScaleRatio_C);
  182. // Only set the ratio if it has changed.
  183. //if (ratio_C != ratio_C_old)
  184. mat.SetFloat(ID_ScaleRatio_C, ratio_C);
  185. }
  186. }
  187. // Function to calculate padding required for Outline Width & Dilation for proper text alignment
  188. public static Vector4 GetFontExtent(Material material)
  189. {
  190. // Revised implementation where style no longer affects alignment
  191. return Vector4.zero;
  192. /*
  193. if (material == null || !material.HasProperty(ShaderUtilities.ID_GradientScale))
  194. return Vector4.zero; // We are using an non SDF Shader.
  195. float scaleRatioA = material.GetFloat(ID_ScaleRatio_A);
  196. float faceDilate = material.GetFloat(ID_FaceDilate) * scaleRatioA;
  197. float outlineThickness = material.GetFloat(ID_OutlineWidth) * scaleRatioA;
  198. float extent = Mathf.Min(1, faceDilate + outlineThickness);
  199. extent *= material.GetFloat(ID_GradientScale);
  200. return new Vector4(extent, extent, extent, extent);
  201. */
  202. }
  203. // Function to check if Masking is enabled
  204. public static bool IsMaskingEnabled(Material material)
  205. {
  206. if (material == null || !material.HasProperty(ShaderUtilities.ID_ClipRect))
  207. return false;
  208. if (material.shaderKeywords.Contains(ShaderUtilities.Keyword_MASK_SOFT) || material.shaderKeywords.Contains(ShaderUtilities.Keyword_MASK_HARD) || material.shaderKeywords.Contains(ShaderUtilities.Keyword_MASK_TEX))
  209. return true;
  210. return false;
  211. }
  212. // Function to determine how much extra padding is required as a result of material properties like dilate, outline thickness, softness, glow, etc...
  213. public static float GetPadding(Material material, bool enableExtraPadding, bool isBold)
  214. {
  215. //Debug.Log("GetPadding() called.");
  216. if (isInitialized == false)
  217. GetShaderPropertyIDs();
  218. // Return if Material is null
  219. if (material == null) return 0;
  220. int extraPadding = enableExtraPadding ? 4 : 0;
  221. // Check if we are using a non Distance Field Shader
  222. if (material.HasProperty(ID_GradientScale) == false)
  223. {
  224. if (material.HasProperty(ID_Padding))
  225. extraPadding += (int)material.GetFloat(ID_Padding);
  226. return extraPadding;
  227. }
  228. Vector4 padding = Vector4.zero;
  229. Vector4 maxPadding = Vector4.zero;
  230. //float weight = 0;
  231. float faceDilate = 0;
  232. float faceSoftness = 0;
  233. float outlineThickness = 0;
  234. float scaleRatio_A = 0;
  235. float scaleRatio_B = 0;
  236. float scaleRatio_C = 0;
  237. float glowOffset = 0;
  238. float glowOuter = 0;
  239. float uniformPadding = 0;
  240. // Iterate through each of the assigned materials to find the max values to set the padding.
  241. // Update Shader Ratios prior to computing padding
  242. UpdateShaderRatios(material);
  243. string[] shaderKeywords = material.shaderKeywords;
  244. if (material.HasProperty(ID_ScaleRatio_A))
  245. scaleRatio_A = material.GetFloat(ID_ScaleRatio_A);
  246. //weight = 0; // Mathf.Max(material.GetFloat(ID_WeightNormal), material.GetFloat(ID_WeightBold)) / 2.0f * scaleRatio_A;
  247. if (material.HasProperty(ID_FaceDilate))
  248. faceDilate = material.GetFloat(ID_FaceDilate) * scaleRatio_A;
  249. if (material.HasProperty(ID_OutlineSoftness))
  250. faceSoftness = material.GetFloat(ID_OutlineSoftness) * scaleRatio_A;
  251. if (material.HasProperty(ID_OutlineWidth))
  252. outlineThickness = material.GetFloat(ID_OutlineWidth) * scaleRatio_A;
  253. uniformPadding = outlineThickness + faceSoftness + faceDilate;
  254. // Glow padding contribution
  255. if (material.HasProperty(ID_GlowOffset) && shaderKeywords.Contains(Keyword_Glow)) // Generates GC
  256. {
  257. if (material.HasProperty(ID_ScaleRatio_B))
  258. scaleRatio_B = material.GetFloat(ID_ScaleRatio_B);
  259. glowOffset = material.GetFloat(ID_GlowOffset) * scaleRatio_B;
  260. glowOuter = material.GetFloat(ID_GlowOuter) * scaleRatio_B;
  261. }
  262. uniformPadding = Mathf.Max(uniformPadding, faceDilate + glowOffset + glowOuter);
  263. // Underlay padding contribution
  264. if (material.HasProperty(ID_UnderlaySoftness) && shaderKeywords.Contains(Keyword_Underlay)) // Generates GC
  265. {
  266. if (material.HasProperty(ID_ScaleRatio_C))
  267. scaleRatio_C = material.GetFloat(ID_ScaleRatio_C);
  268. float offsetX = material.GetFloat(ID_UnderlayOffsetX) * scaleRatio_C;
  269. float offsetY = material.GetFloat(ID_UnderlayOffsetY) * scaleRatio_C;
  270. float dilate = material.GetFloat(ID_UnderlayDilate) * scaleRatio_C;
  271. float softness = material.GetFloat(ID_UnderlaySoftness) * scaleRatio_C;
  272. padding.x = Mathf.Max(padding.x, faceDilate + dilate + softness - offsetX);
  273. padding.y = Mathf.Max(padding.y, faceDilate + dilate + softness - offsetY);
  274. padding.z = Mathf.Max(padding.z, faceDilate + dilate + softness + offsetX);
  275. padding.w = Mathf.Max(padding.w, faceDilate + dilate + softness + offsetY);
  276. }
  277. padding.x = Mathf.Max(padding.x, uniformPadding);
  278. padding.y = Mathf.Max(padding.y, uniformPadding);
  279. padding.z = Mathf.Max(padding.z, uniformPadding);
  280. padding.w = Mathf.Max(padding.w, uniformPadding);
  281. padding.x += extraPadding;
  282. padding.y += extraPadding;
  283. padding.z += extraPadding;
  284. padding.w += extraPadding;
  285. padding.x = Mathf.Min(padding.x, 1);
  286. padding.y = Mathf.Min(padding.y, 1);
  287. padding.z = Mathf.Min(padding.z, 1);
  288. padding.w = Mathf.Min(padding.w, 1);
  289. maxPadding.x = maxPadding.x < padding.x ? padding.x : maxPadding.x;
  290. maxPadding.y = maxPadding.y < padding.y ? padding.y : maxPadding.y;
  291. maxPadding.z = maxPadding.z < padding.z ? padding.z : maxPadding.z;
  292. maxPadding.w = maxPadding.w < padding.w ? padding.w : maxPadding.w;
  293. float gradientScale = material.GetFloat(ID_GradientScale);
  294. padding *= gradientScale;
  295. // Set UniformPadding to the maximum value of any of its components.
  296. uniformPadding = Mathf.Max(padding.x, padding.y);
  297. uniformPadding = Mathf.Max(padding.z, uniformPadding);
  298. uniformPadding = Mathf.Max(padding.w, uniformPadding);
  299. return uniformPadding + 0.5f;
  300. }
  301. // Function to determine how much extra padding is required as a result of material properties like dilate, outline thickness, softness, glow, etc...
  302. public static float GetPadding(Material[] materials, bool enableExtraPadding, bool isBold)
  303. {
  304. //Debug.Log("GetPadding() called.");
  305. if (isInitialized == false)
  306. GetShaderPropertyIDs();
  307. // Return if Material is null
  308. if (materials == null) return 0;
  309. int extraPadding = enableExtraPadding ? 4 : 0;
  310. // Check if we are using a Bitmap Shader
  311. if (materials[0].HasProperty(ID_Padding))
  312. return extraPadding + materials[0].GetFloat(ID_Padding);
  313. Vector4 padding = Vector4.zero;
  314. Vector4 maxPadding = Vector4.zero;
  315. float faceDilate = 0;
  316. float faceSoftness = 0;
  317. float outlineThickness = 0;
  318. float scaleRatio_A = 0;
  319. float scaleRatio_B = 0;
  320. float scaleRatio_C = 0;
  321. float glowOffset = 0;
  322. float glowOuter = 0;
  323. float uniformPadding = 0;
  324. // Iterate through each of the assigned materials to find the max values to set the padding.
  325. for (int i = 0; i < materials.Length; i++)
  326. {
  327. // Update Shader Ratios prior to computing padding
  328. ShaderUtilities.UpdateShaderRatios(materials[i]);
  329. string[] shaderKeywords = materials[i].shaderKeywords;
  330. if (materials[i].HasProperty(ShaderUtilities.ID_ScaleRatio_A))
  331. scaleRatio_A = materials[i].GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  332. if (materials[i].HasProperty(ShaderUtilities.ID_FaceDilate))
  333. faceDilate = materials[i].GetFloat(ShaderUtilities.ID_FaceDilate) * scaleRatio_A;
  334. if (materials[i].HasProperty(ShaderUtilities.ID_OutlineSoftness))
  335. faceSoftness = materials[i].GetFloat(ShaderUtilities.ID_OutlineSoftness) * scaleRatio_A;
  336. if (materials[i].HasProperty(ShaderUtilities.ID_OutlineWidth))
  337. outlineThickness = materials[i].GetFloat(ShaderUtilities.ID_OutlineWidth) * scaleRatio_A;
  338. uniformPadding = outlineThickness + faceSoftness + faceDilate;
  339. // Glow padding contribution
  340. if (materials[i].HasProperty(ShaderUtilities.ID_GlowOffset) && shaderKeywords.Contains(ShaderUtilities.Keyword_Glow))
  341. {
  342. if (materials[i].HasProperty(ShaderUtilities.ID_ScaleRatio_B))
  343. scaleRatio_B = materials[i].GetFloat(ShaderUtilities.ID_ScaleRatio_B);
  344. glowOffset = materials[i].GetFloat(ShaderUtilities.ID_GlowOffset) * scaleRatio_B;
  345. glowOuter = materials[i].GetFloat(ShaderUtilities.ID_GlowOuter) * scaleRatio_B;
  346. }
  347. uniformPadding = Mathf.Max(uniformPadding, faceDilate + glowOffset + glowOuter);
  348. // Underlay padding contribution
  349. if (materials[i].HasProperty(ShaderUtilities.ID_UnderlaySoftness) && shaderKeywords.Contains(ShaderUtilities.Keyword_Underlay))
  350. {
  351. if (materials[i].HasProperty(ShaderUtilities.ID_ScaleRatio_C))
  352. scaleRatio_C = materials[i].GetFloat(ShaderUtilities.ID_ScaleRatio_C);
  353. float offsetX = materials[i].GetFloat(ShaderUtilities.ID_UnderlayOffsetX) * scaleRatio_C;
  354. float offsetY = materials[i].GetFloat(ShaderUtilities.ID_UnderlayOffsetY) * scaleRatio_C;
  355. float dilate = materials[i].GetFloat(ShaderUtilities.ID_UnderlayDilate) * scaleRatio_C;
  356. float softness = materials[i].GetFloat(ShaderUtilities.ID_UnderlaySoftness) * scaleRatio_C;
  357. padding.x = Mathf.Max(padding.x, faceDilate + dilate + softness - offsetX);
  358. padding.y = Mathf.Max(padding.y, faceDilate + dilate + softness - offsetY);
  359. padding.z = Mathf.Max(padding.z, faceDilate + dilate + softness + offsetX);
  360. padding.w = Mathf.Max(padding.w, faceDilate + dilate + softness + offsetY);
  361. }
  362. padding.x = Mathf.Max(padding.x, uniformPadding);
  363. padding.y = Mathf.Max(padding.y, uniformPadding);
  364. padding.z = Mathf.Max(padding.z, uniformPadding);
  365. padding.w = Mathf.Max(padding.w, uniformPadding);
  366. padding.x += extraPadding;
  367. padding.y += extraPadding;
  368. padding.z += extraPadding;
  369. padding.w += extraPadding;
  370. padding.x = Mathf.Min(padding.x, 1);
  371. padding.y = Mathf.Min(padding.y, 1);
  372. padding.z = Mathf.Min(padding.z, 1);
  373. padding.w = Mathf.Min(padding.w, 1);
  374. maxPadding.x = maxPadding.x < padding.x ? padding.x : maxPadding.x;
  375. maxPadding.y = maxPadding.y < padding.y ? padding.y : maxPadding.y;
  376. maxPadding.z = maxPadding.z < padding.z ? padding.z : maxPadding.z;
  377. maxPadding.w = maxPadding.w < padding.w ? padding.w : maxPadding.w;
  378. }
  379. float gradientScale = materials[0].GetFloat(ShaderUtilities.ID_GradientScale);
  380. padding *= gradientScale;
  381. // Set UniformPadding to the maximum value of any of its components.
  382. uniformPadding = Mathf.Max(padding.x, padding.y);
  383. uniformPadding = Mathf.Max(padding.z, uniformPadding);
  384. uniformPadding = Mathf.Max(padding.w, uniformPadding);
  385. return uniformPadding + 0.25f;
  386. }
  387. }
  388. }