#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_IOS || UNITY_TVOS || UNITY_ANDROID || (UNITY_WEBGL && UNITY_2017_2_OR_NEWER)
#define UNITY_PLATFORM_SUPPORTS_LINEAR
#endif
#if (UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN))
#define UNITY_PLATFORM_SUPPORTS_VIDEOASPECTRATIO
#endif
using UnityEngine;
using UnityEngine.Serialization;
//-----------------------------------------------------------------------------
// Copyright 2015-2022 RenderHeads Ltd. All rights reserved.
//-----------------------------------------------------------------------------
namespace RenderHeads.Media.AVProVideo
{
///
/// Displays the video from MediaPlayer component using IMGUI
///
[AddComponentMenu("AVPro Video/Display IMGUI", 200)]
[HelpURL("https://www.renderheads.com/products/avpro-video/")]
[ExecuteInEditMode]
public class DisplayIMGUI : MonoBehaviour
{
[SerializeField] MediaPlayer _mediaPlayer = null;
public MediaPlayer Player
{
get { return _mediaPlayer; }
set { _mediaPlayer = value; Update(); }
}
[SerializeField] ScaleMode _scaleMode = ScaleMode.ScaleToFit;
public ScaleMode ScaleMode { get { return _scaleMode; } set { _scaleMode = value; } }
[SerializeField] Color _color = UnityEngine.Color.white;
public Color Color { get { return _color; } set { _color = value; } }
[FormerlySerializedAs("_alphaBlend")]
[SerializeField] bool _allowTransparency = false;
public bool AllowTransparency { get { return _allowTransparency; } set { _allowTransparency = value; } }
[SerializeField] bool _useDepth = false;
public bool UseDepth { get { return _useDepth; } set { _useDepth = value; } }
[SerializeField] int _depth = 0;
public int Depth { get { return _depth; } set { _depth = value; } }
[Header("Area")]
[FormerlySerializedAs("_fullScreen")]
[SerializeField] bool _isAreaFullScreen = true;
public bool IsAreaFullScreen { get { return _isAreaFullScreen; } set { _isAreaFullScreen = value; } }
[FormerlySerializedAs("_x")]
[Range(0f, 1f)]
[SerializeField] float _areaX = 0f;
public float AreaX { get { return _areaX; } set { _areaX = value; } }
[FormerlySerializedAs("_y")]
[Range(0f, 1f)]
[SerializeField] float _areaY = 0f;
public float AreaY { get { return _areaY; } set { _areaY = value; } }
[FormerlySerializedAs("_width")]
[Range(0f, 1f)]
[SerializeField] float _areaWidth = 1f;
public float AreaWidth { get { return _areaWidth; } set { _areaWidth = value; } }
[FormerlySerializedAs("_height")]
[Range(0f, 1f)]
[SerializeField] float _areaHeight = 1f;
public float AreaHeight { get { return _areaHeight; } set { _areaHeight = value; } }
[FormerlySerializedAs("_displayInEditor")]
[SerializeField] bool _showAreaInEditor = false;
public bool ShowAreaInEditor { get { return _showAreaInEditor; } set { _showAreaInEditor = value; } }
private static Shader _shaderAlphaPacking;
private Material _material;
void Start()
{
// Disabling useGUILayout lets you skip the GUI layout phase which helps performance, but this also breaks the GUI.depth usage.
if (!_useDepth)
{
this.useGUILayout = false;
}
if (!_shaderAlphaPacking)
{
_shaderAlphaPacking = Shader.Find("AVProVideo/Internal/IMGUI/Texture Transparent");
if (!_shaderAlphaPacking)
{
Debug.LogWarning("[AVProVideo] Missing shader 'AVProVideo/Internal/IMGUI/Texture Transparent'");
}
}
}
public void Update()
{
if (_mediaPlayer != null)
{
SetupMaterial();
}
}
void OnDestroy()
{
// Destroy existing material
if (_material != null)
{
#if UNITY_EDITOR
Material.DestroyImmediate(_material);
#else
Material.Destroy(_material);
#endif
_material = null;
}
}
private Shader GetRequiredShader()
{
Shader result = null;
if (result == null && _mediaPlayer.TextureProducer != null)
{
switch (_mediaPlayer.TextureProducer.GetTextureAlphaPacking())
{
case AlphaPacking.None:
break;
case AlphaPacking.LeftRight:
case AlphaPacking.TopBottom:
result = _shaderAlphaPacking;
break;
}
}
#if UNITY_PLATFORM_SUPPORTS_LINEAR
if (result == null && _mediaPlayer.Info != null)
{
// If the player does support generating sRGB textures then we need to use a shader to convert them for display via IMGUI
if (QualitySettings.activeColorSpace == ColorSpace.Linear && !_mediaPlayer.Info.PlayerSupportsLinearColorSpace())
{
result = _shaderAlphaPacking;
}
}
#endif
if (result == null && _mediaPlayer.TextureProducer != null)
{
if (_mediaPlayer.TextureProducer.GetTextureCount() == 2)
{
result = _shaderAlphaPacking;
}
}
return result;
}
private void SetupMaterial()
{
// Get required shader
Shader currentShader = null;
if (_material != null)
{
currentShader = _material.shader;
}
Shader nextShader = GetRequiredShader();
// If the shader requirement has changed
if (currentShader != nextShader)
{
// Destroy existing material
if (_material != null)
{
#if UNITY_EDITOR
Material.DestroyImmediate(_material);
#else
Material.Destroy(_material);
#endif
_material = null;
}
// Create new material
if (nextShader != null)
{
_material = new Material(nextShader);
}
}
}
#if UNITY_EDITOR
private void DrawArea()
{
Rect rect = GetAreaRect();
Rect uv = rect;
uv.x /= Screen.width;
uv.width /= Screen.width;
uv.y /= Screen.height;
uv.height /= Screen.height;
uv.width *= 16f;
uv.height *= 16f;
uv.x += 0.5f;
uv.y += 0.5f;
Texture2D icon = Resources.Load("AVProVideoIcon");
GUI.depth = _depth;
GUI.color = _color;
GUI.DrawTextureWithTexCoords(rect, icon, uv);
}
#endif
void OnGUI()
{
#if UNITY_EDITOR
if (_showAreaInEditor && !Application.isPlaying)
{
DrawArea();
return;
}
#endif
if (_mediaPlayer == null)
{
return;
}
Texture texture = null;
if (_showAreaInEditor)
{
#if UNITY_EDITOR
texture = Texture2D.whiteTexture;
#endif
}
texture = VideoRender.GetTexture(_mediaPlayer, 0);
if (_mediaPlayer.Info != null && !_mediaPlayer.Info.HasVideo())
{
texture = null;
}
if (texture != null)
{
bool isTextureVisible = (_color.a > 0f || !_allowTransparency);
if (isTextureVisible)
{
GUI.depth = _depth;
GUI.color = _color;
Rect rect = GetAreaRect();
// TODO: change this to a material-only path so we only have a single drawing path
if (_material != null)
{
// TODO: Only setup material when needed
VideoRender.SetupMaterialForMedia(_material, _mediaPlayer);
// NOTE: It seems that Graphics.DrawTexture() behaves differently than GUI.DrawTexture() when it comes to sRGB writing
// on newer versions of Unity (at least 2018.2.19 and above), so now we have to force the conversion to sRGB on writing
bool restoreSRGBWrite = false;
#if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
if (QualitySettings.activeColorSpace == ColorSpace.Linear && !GL.sRGBWrite)
{
restoreSRGBWrite = true;
}
#endif
if (restoreSRGBWrite)
{
GL.sRGBWrite = true;
}
VideoRender.DrawTexture(rect, texture, _scaleMode, _mediaPlayer.TextureProducer.GetTextureAlphaPacking(), _mediaPlayer.TextureProducer.GetTexturePixelAspectRatio(), _material);
if (restoreSRGBWrite)
{
GL.sRGBWrite = false;
}
}
else
{
bool requiresVerticalFlip = false;
if (_mediaPlayer.TextureProducer != null)
{
requiresVerticalFlip = _mediaPlayer.TextureProducer.RequiresVerticalFlip();
}
if (requiresVerticalFlip)
{
GUIUtility.ScaleAroundPivot(new Vector2(1f, -1f), new Vector2(0f, rect.y + (rect.height / 2f)));
}
#if UNITY_PLATFORM_SUPPORTS_VIDEOASPECTRATIO
float par = _mediaPlayer.TextureProducer.GetTexturePixelAspectRatio();
if (par > 0f)
{
if (par > 1f)
{
GUIUtility.ScaleAroundPivot(new Vector2(par, 1f), new Vector2(rect.x + (rect.width / 2f), rect.y + (rect.height / 2f)));
}
else
{
GUIUtility.ScaleAroundPivot(new Vector2(1f, 1f/par), new Vector2(rect.x + (rect.width / 2f), rect.y + (rect.height / 2f)));
}
}
#endif
GUI.DrawTexture(rect, texture, _scaleMode, _allowTransparency);
}
}
}
}
public Rect GetAreaRect()
{
Rect rect;
if (_isAreaFullScreen)
{
rect = new Rect(0.0f, 0.0f, Screen.width, Screen.height);
}
else
{
rect = new Rect(_areaX * (Screen.width - 1), _areaY * (Screen.height - 1), _areaWidth * Screen.width, _areaHeight * Screen.height);
}
return rect;
}
}
}