1
0
mirror of https://github.com/xiaopeng12138/MaiDXR.git synced 2024-12-18 11:55:52 +01:00
MaiDXR/Assets/uWindowCapture/Runtime/UwcWindowTexture.cs
2022-01-05 19:44:30 +01:00

441 lines
11 KiB
C#

using UnityEngine;
using System.Collections.Generic;
namespace uWindowCapture
{
public class UwcWindowTexture : MonoBehaviour
{
bool shouldUpdateWindow_ = true;
bool shouldUpdateWindow
{
get
{
return shouldUpdateWindow_;
}
set
{
if (value && searchTiming == WindowSearchTiming.Manual) return;
shouldUpdateWindow_ = value;
}
}
[SerializeField]
WindowSearchTiming searchTiming_ = WindowSearchTiming.OnlyWhenParameterChanged;
public WindowSearchTiming searchTiming
{
get
{
return searchTiming_;
}
set
{
searchTiming_ = value;
if (searchTiming_ == WindowSearchTiming.Manual) {
shouldUpdateWindow = false;
} else {
shouldUpdateWindow = true;
}
}
}
[SerializeField]
WindowTextureType type_ = WindowTextureType.Window;
public WindowTextureType type
{
get
{
return type_;
}
set
{
shouldUpdateWindow = true;
type_ = value;
}
}
[SerializeField]
bool altTabWindow_ = false;
public bool altTabWindow
{
get
{
return altTabWindow_;
}
set
{
shouldUpdateWindow = true;
altTabWindow_ = value;
}
}
[SerializeField]
bool createChildWindows_ = true;
public bool createChildWindows
{
get
{
return createChildWindows_;
}
set
{
createChildWindows_ = value;
var manager = GetComponent<UwcWindowTextureChildrenManager>();
if (createChildWindows_) {
if (!manager) {
gameObject.AddComponent<UwcWindowTextureChildrenManager>();
}
} else {
if (manager) {
Destroy(manager);
}
}
}
}
public GameObject childWindowPrefab;
public float childWindowZDistance = 0.02f;
[SerializeField]
string partialWindowTitle_;
public string partialWindowTitle
{
get
{
return partialWindowTitle_;
}
set
{
shouldUpdateWindow = true;
partialWindowTitle_ = value;
}
}
[SerializeField]
int desktopIndex_ = 0;
public int desktopIndex
{
get
{
return desktopIndex_;
}
set
{
shouldUpdateWindow = true;
desktopIndex_ = (UwcManager.desktopCount > 0) ?
Mathf.Clamp(value, 0, UwcManager.desktopCount - 1) : 0;
}
}
public CaptureMode captureMode = CaptureMode.Auto;
public CapturePriority capturePriority = CapturePriority.Auto;
public WindowTextureCaptureTiming captureRequestTiming = WindowTextureCaptureTiming.OnlyWhenVisible;
public int captureFrameRate = 30;
public bool drawCursor = true;
public bool updateTitle = true;
public bool searchAnotherWindowWhenInvalid = false;
public WindowTextureScaleControlType scaleControlType = WindowTextureScaleControlType.BaseScale;
public float scalePer1000Pixel = 1f;
public bool updateScaleForcely = false;
static HashSet<UwcWindowTexture> list_ = new HashSet<UwcWindowTexture>();
public static HashSet<UwcWindowTexture> list
{
get { return list_; }
}
UwcWindow window_;
public UwcWindow window
{
get
{
return window_;
}
set
{
if (window_ == value) {
return;
}
if (window_ != null) {
window_.onCaptured.RemoveListener(OnCaptured);
}
var old = window_;
window_ = value;
onWindowChanged_.Invoke(window_, old);
if (window_ != null) {
shouldUpdateWindow = false;
window_.onCaptured.AddListener(OnCaptured);
window_.RequestCapture(CapturePriority.High);
}
}
}
public UwcWindowTextureManager manager { get; set; }
public UwcWindowTexture parent { get; set; }
UwcWindowChangeEvent onWindowChanged_ = new UwcWindowChangeEvent();
public UwcWindowChangeEvent onWindowChanged
{
get { return onWindowChanged_; }
}
float basePixel
{
get { return 1000f / scalePer1000Pixel; }
}
public bool isValid
{
get
{
return window != null && window.isValid;
}
}
Material material_;
Renderer renderer_;
MeshFilter meshFilter_;
Collider collider_;
float captureTimer_ = 0f;
bool isCaptureRequested_ = false;
bool hasBeenCaptured_ = false;
void Awake()
{
renderer_ = GetComponent<Renderer>();
material_ = renderer_.material; // clone
meshFilter_ = GetComponent<MeshFilter>();
collider_ = GetComponent<Collider>();
list_.Add(this);
}
void OnDestroy()
{
list_.Remove(this);
}
void Update()
{
UpdateSearchTiming();
UpdateTargetWindow();
if (!isValid) {
material_.mainTexture = null;
return;
}
UpdateTexture();
UpdateRenderer();
UpdateScale();
UpdateTitle();
UpdateCaptureTimer();
UpdateRequestCapture();
UpdateBasicComponents();
}
void OnWillRenderObject()
{
if (!isCaptureRequested_) return;
if (captureRequestTiming == WindowTextureCaptureTiming.OnlyWhenVisible) {
RequestCapture();
}
}
void UpdateTexture()
{
if (!isValid) return;
window.cursorDraw = drawCursor;
if (material_.mainTexture != window.texture) {
material_.mainTexture = window.texture;
}
}
void UpdateRenderer()
{
if (hasBeenCaptured_) {
renderer_.enabled = !window.isIconic && window.isVisible;
}
}
void UpdateScale()
{
if (!isValid || (!updateScaleForcely && window.isChild)) return;
var scale = transform.localScale;
switch (scaleControlType) {
case WindowTextureScaleControlType.BaseScale: {
var extents = meshFilter_.sharedMesh.bounds.extents;
var meshWidth = extents.x * 2f;
var meshHeight = extents.y * 2f;
var baseHeight = meshHeight * basePixel;
var baseWidth = meshWidth * basePixel;
scale.x = window.width / baseWidth;
scale.y = window.height / baseHeight;
break;
}
case WindowTextureScaleControlType.FixedWidth: {
scale.y = transform.localScale.x * window.height / window.width;
break;
}
case WindowTextureScaleControlType.FixedHeight: {
scale.x = transform.localScale.y * window.width / window.height;
break;
}
case WindowTextureScaleControlType.Manual: {
break;
}
}
if (float.IsNaN(scale.x)) scale.x = 0f;
if (float.IsNaN(scale.y)) scale.y = 0f;
transform.localScale = scale;
}
void UpdateTitle()
{
if (updateTitle && isValid) {
window.RequestUpdateTitle();
}
}
void UpdateCaptureTimer()
{
if (captureFrameRate < 0) {
captureTimer_ = 0f;
isCaptureRequested_ = true;
} else {
captureTimer_ += Time.deltaTime;
float T = 1f / captureFrameRate;
if (captureTimer_ < T) return;
while (captureTimer_ > T) {
captureTimer_ -= T;
}
}
isCaptureRequested_ = true;
}
void UpdateRequestCapture()
{
if (!isCaptureRequested_) return;
if (captureRequestTiming == WindowTextureCaptureTiming.EveryFrame) {
RequestCapture();
}
}
void UpdateSearchTiming()
{
if (searchTiming == WindowSearchTiming.Always) {
shouldUpdateWindow = true;
}
}
void UpdateTargetWindow()
{
if (!shouldUpdateWindow) return;
switch (type)
{
case WindowTextureType.Window:
window = UwcManager.Find(partialWindowTitle, altTabWindow);
break;
case WindowTextureType.Desktop:
window = UwcManager.FindDesktop(desktopIndex);
break;
case WindowTextureType.Child:
break;
}
}
void UpdateBasicComponents()
{
if (renderer_) renderer_.enabled = isValid;
if (collider_) collider_.enabled = isValid;
}
void OnCaptured()
{
hasBeenCaptured_ = true;
}
public void RequestCapture()
{
if (!isValid) return;
isCaptureRequested_ = false;
window.captureMode = captureMode;
var priority = capturePriority;
if (priority == CapturePriority.Auto) {
priority = CapturePriority.Low;
if (window == UwcManager.cursorWindow) {
priority = CapturePriority.High;
} else if (window.zOrder < UwcSetting.MiddlePriorityMaxZ) {
priority = CapturePriority.Middle;
}
}
window.RequestCapture(priority);
}
public void RequestWindowUpdate()
{
shouldUpdateWindow = true;
}
static public RayCastResult RayCast(Vector3 from, Vector3 dir, float distance, LayerMask layerMask)
{
var ray = new Ray();
ray.origin = from;
ray.direction = dir;
RaycastHit hit;
if (Physics.Raycast(ray, out hit, distance, layerMask)) {
var collider = hit.collider;
var texture =
collider.GetComponent<UwcWindowTexture>() ??
collider.GetComponentInChildren<UwcWindowTexture>();
if (texture) {
var window = texture.window;
var meshFilter = texture.GetComponent<MeshFilter>();
if (window != null && meshFilter && meshFilter.sharedMesh) {
var localPos = texture.transform.InverseTransformPoint(hit.point);
var meshScale = 2f * meshFilter.sharedMesh.bounds.extents;
var windowLocalX = (int)((localPos.x / meshScale.x + 0.5f) * window.width);
var windowLocalY = (int)((0.5f - localPos.y / meshScale.y) * window.height);
var desktopX = window.x + windowLocalX;
var desktopY = window.y + windowLocalY;
return new RayCastResult {
hit = true,
texture = texture,
position = hit.point,
normal = hit.normal,
windowCoord = new Vector2(windowLocalX, windowLocalY),
desktopCoord = new Vector2(desktopX, desktopY),
};
}
}
}
return new RayCastResult() {
hit = false,
};
}
}
}