DisplayIMGUI.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_IOS || UNITY_TVOS || UNITY_ANDROID || (UNITY_WEBGL && UNITY_2017_2_OR_NEWER)
  2. #define UNITY_PLATFORM_SUPPORTS_LINEAR
  3. #endif
  4. #if (UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN))
  5. #define UNITY_PLATFORM_SUPPORTS_VIDEOASPECTRATIO
  6. #endif
  7. using UnityEngine;
  8. using UnityEngine.Serialization;
  9. //-----------------------------------------------------------------------------
  10. // Copyright 2015-2022 RenderHeads Ltd. All rights reserved.
  11. //-----------------------------------------------------------------------------
  12. namespace RenderHeads.Media.AVProVideo
  13. {
  14. /// <summary>
  15. /// Displays the video from MediaPlayer component using IMGUI
  16. /// </summary>
  17. [AddComponentMenu("AVPro Video/Display IMGUI", 200)]
  18. [HelpURL("https://www.renderheads.com/products/avpro-video/")]
  19. [ExecuteInEditMode]
  20. public class DisplayIMGUI : MonoBehaviour
  21. {
  22. [SerializeField] MediaPlayer _mediaPlayer = null;
  23. public MediaPlayer Player
  24. {
  25. get { return _mediaPlayer; }
  26. set { _mediaPlayer = value; Update(); }
  27. }
  28. [SerializeField] ScaleMode _scaleMode = ScaleMode.ScaleToFit;
  29. public ScaleMode ScaleMode { get { return _scaleMode; } set { _scaleMode = value; } }
  30. [SerializeField] Color _color = UnityEngine.Color.white;
  31. public Color Color { get { return _color; } set { _color = value; } }
  32. [FormerlySerializedAs("_alphaBlend")]
  33. [SerializeField] bool _allowTransparency = false;
  34. public bool AllowTransparency { get { return _allowTransparency; } set { _allowTransparency = value; } }
  35. [SerializeField] bool _useDepth = false;
  36. public bool UseDepth { get { return _useDepth; } set { _useDepth = value; } }
  37. [SerializeField] int _depth = 0;
  38. public int Depth { get { return _depth; } set { _depth = value; } }
  39. [Header("Area")]
  40. [FormerlySerializedAs("_fullScreen")]
  41. [SerializeField] bool _isAreaFullScreen = true;
  42. public bool IsAreaFullScreen { get { return _isAreaFullScreen; } set { _isAreaFullScreen = value; } }
  43. [FormerlySerializedAs("_x")]
  44. [Range(0f, 1f)]
  45. [SerializeField] float _areaX = 0f;
  46. public float AreaX { get { return _areaX; } set { _areaX = value; } }
  47. [FormerlySerializedAs("_y")]
  48. [Range(0f, 1f)]
  49. [SerializeField] float _areaY = 0f;
  50. public float AreaY { get { return _areaY; } set { _areaY = value; } }
  51. [FormerlySerializedAs("_width")]
  52. [Range(0f, 1f)]
  53. [SerializeField] float _areaWidth = 1f;
  54. public float AreaWidth { get { return _areaWidth; } set { _areaWidth = value; } }
  55. [FormerlySerializedAs("_height")]
  56. [Range(0f, 1f)]
  57. [SerializeField] float _areaHeight = 1f;
  58. public float AreaHeight { get { return _areaHeight; } set { _areaHeight = value; } }
  59. [FormerlySerializedAs("_displayInEditor")]
  60. [SerializeField] bool _showAreaInEditor = false;
  61. public bool ShowAreaInEditor { get { return _showAreaInEditor; } set { _showAreaInEditor = value; } }
  62. private static Shader _shaderAlphaPacking;
  63. private Material _material;
  64. void Start()
  65. {
  66. // Disabling useGUILayout lets you skip the GUI layout phase which helps performance, but this also breaks the GUI.depth usage.
  67. if (!_useDepth)
  68. {
  69. this.useGUILayout = false;
  70. }
  71. if (!_shaderAlphaPacking)
  72. {
  73. _shaderAlphaPacking = Shader.Find("AVProVideo/Internal/IMGUI/Texture Transparent");
  74. if (!_shaderAlphaPacking)
  75. {
  76. Debug.LogWarning("[AVProVideo] Missing shader 'AVProVideo/Internal/IMGUI/Texture Transparent'");
  77. }
  78. }
  79. }
  80. public void Update()
  81. {
  82. if (_mediaPlayer != null)
  83. {
  84. SetupMaterial();
  85. }
  86. }
  87. void OnDestroy()
  88. {
  89. // Destroy existing material
  90. if (_material != null)
  91. {
  92. #if UNITY_EDITOR
  93. Material.DestroyImmediate(_material);
  94. #else
  95. Material.Destroy(_material);
  96. #endif
  97. _material = null;
  98. }
  99. }
  100. private Shader GetRequiredShader()
  101. {
  102. Shader result = null;
  103. if (result == null && _mediaPlayer.TextureProducer != null)
  104. {
  105. switch (_mediaPlayer.TextureProducer.GetTextureAlphaPacking())
  106. {
  107. case AlphaPacking.None:
  108. break;
  109. case AlphaPacking.LeftRight:
  110. case AlphaPacking.TopBottom:
  111. result = _shaderAlphaPacking;
  112. break;
  113. }
  114. }
  115. #if UNITY_PLATFORM_SUPPORTS_LINEAR
  116. if (result == null && _mediaPlayer.Info != null)
  117. {
  118. // If the player does support generating sRGB textures then we need to use a shader to convert them for display via IMGUI
  119. if (QualitySettings.activeColorSpace == ColorSpace.Linear && !_mediaPlayer.Info.PlayerSupportsLinearColorSpace())
  120. {
  121. result = _shaderAlphaPacking;
  122. }
  123. }
  124. #endif
  125. if (result == null && _mediaPlayer.TextureProducer != null)
  126. {
  127. if (_mediaPlayer.TextureProducer.GetTextureCount() == 2)
  128. {
  129. result = _shaderAlphaPacking;
  130. }
  131. }
  132. return result;
  133. }
  134. private void SetupMaterial()
  135. {
  136. // Get required shader
  137. Shader currentShader = null;
  138. if (_material != null)
  139. {
  140. currentShader = _material.shader;
  141. }
  142. Shader nextShader = GetRequiredShader();
  143. // If the shader requirement has changed
  144. if (currentShader != nextShader)
  145. {
  146. // Destroy existing material
  147. if (_material != null)
  148. {
  149. #if UNITY_EDITOR
  150. Material.DestroyImmediate(_material);
  151. #else
  152. Material.Destroy(_material);
  153. #endif
  154. _material = null;
  155. }
  156. // Create new material
  157. if (nextShader != null)
  158. {
  159. _material = new Material(nextShader);
  160. }
  161. }
  162. }
  163. #if UNITY_EDITOR
  164. private void DrawArea()
  165. {
  166. Rect rect = GetAreaRect();
  167. Rect uv = rect;
  168. uv.x /= Screen.width;
  169. uv.width /= Screen.width;
  170. uv.y /= Screen.height;
  171. uv.height /= Screen.height;
  172. uv.width *= 16f;
  173. uv.height *= 16f;
  174. uv.x += 0.5f;
  175. uv.y += 0.5f;
  176. Texture2D icon = Resources.Load<Texture2D>("AVProVideoIcon");
  177. GUI.depth = _depth;
  178. GUI.color = _color;
  179. GUI.DrawTextureWithTexCoords(rect, icon, uv);
  180. }
  181. #endif
  182. void OnGUI()
  183. {
  184. #if UNITY_EDITOR
  185. if (_showAreaInEditor && !Application.isPlaying)
  186. {
  187. DrawArea();
  188. return;
  189. }
  190. #endif
  191. if (_mediaPlayer == null)
  192. {
  193. return;
  194. }
  195. Texture texture = null;
  196. if (_showAreaInEditor)
  197. {
  198. #if UNITY_EDITOR
  199. texture = Texture2D.whiteTexture;
  200. #endif
  201. }
  202. texture = VideoRender.GetTexture(_mediaPlayer, 0);
  203. if (_mediaPlayer.Info != null && !_mediaPlayer.Info.HasVideo())
  204. {
  205. texture = null;
  206. }
  207. if (texture != null)
  208. {
  209. bool isTextureVisible = (_color.a > 0f || !_allowTransparency);
  210. if (isTextureVisible)
  211. {
  212. GUI.depth = _depth;
  213. GUI.color = _color;
  214. Rect rect = GetAreaRect();
  215. // TODO: change this to a material-only path so we only have a single drawing path
  216. if (_material != null)
  217. {
  218. // TODO: Only setup material when needed
  219. VideoRender.SetupMaterialForMedia(_material, _mediaPlayer);
  220. // NOTE: It seems that Graphics.DrawTexture() behaves differently than GUI.DrawTexture() when it comes to sRGB writing
  221. // on newer versions of Unity (at least 2018.2.19 and above), so now we have to force the conversion to sRGB on writing
  222. bool restoreSRGBWrite = false;
  223. #if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
  224. if (QualitySettings.activeColorSpace == ColorSpace.Linear && !GL.sRGBWrite)
  225. {
  226. restoreSRGBWrite = true;
  227. }
  228. #endif
  229. if (restoreSRGBWrite)
  230. {
  231. GL.sRGBWrite = true;
  232. }
  233. VideoRender.DrawTexture(rect, texture, _scaleMode, _mediaPlayer.TextureProducer.GetTextureAlphaPacking(), _mediaPlayer.TextureProducer.GetTexturePixelAspectRatio(), _material);
  234. if (restoreSRGBWrite)
  235. {
  236. GL.sRGBWrite = false;
  237. }
  238. }
  239. else
  240. {
  241. bool requiresVerticalFlip = false;
  242. if (_mediaPlayer.TextureProducer != null)
  243. {
  244. requiresVerticalFlip = _mediaPlayer.TextureProducer.RequiresVerticalFlip();
  245. }
  246. if (requiresVerticalFlip)
  247. {
  248. GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), new Vector2(0f, rect.y + (rect.height / 2f)));
  249. }
  250. #if UNITY_PLATFORM_SUPPORTS_VIDEOASPECTRATIO
  251. float par = _mediaPlayer.TextureProducer.GetTexturePixelAspectRatio();
  252. if (par > 0f)
  253. {
  254. if (par > 1f)
  255. {
  256. GUIUtility.ScaleAroundPivot(new Vector2(par, 1f), new Vector2(rect.x + (rect.width / 2f), rect.y + (rect.height / 2f)));
  257. }
  258. else
  259. {
  260. GUIUtility.ScaleAroundPivot(new Vector2(1f, 1f/par), new Vector2(rect.x + (rect.width / 2f), rect.y + (rect.height / 2f)));
  261. }
  262. }
  263. #endif
  264. GUI.DrawTexture(rect, texture, _scaleMode, _allowTransparency);
  265. }
  266. }
  267. }
  268. }
  269. public Rect GetAreaRect()
  270. {
  271. Rect rect;
  272. if (_isAreaFullScreen)
  273. {
  274. rect = new Rect(0.0f, 0.0f, Screen.width, Screen.height);
  275. }
  276. else
  277. {
  278. rect = new Rect(_areaX * (Screen.width - 1), _areaY * (Screen.height - 1), _areaWidth * Screen.width, _areaHeight * Screen.height);
  279. }
  280. return rect;
  281. }
  282. }
  283. }