Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f8a026c24 | ||
|
|
dc702c6e1d | ||
|
|
5a3af11d08 | ||
|
|
0646621f73 | ||
|
|
c9d6d3ad6a | ||
|
|
78ee75a875 | ||
|
|
c83ce50468 | ||
|
|
3567182a4d | ||
|
|
e466aa65db | ||
|
|
a0edc1a439 | ||
|
|
1eb821b34d | ||
|
|
212d8ccb9b | ||
|
|
fac8fe1ea7 | ||
|
|
f90178f1db | ||
|
|
74e25f2bd7 | ||
|
|
70c126be6c |
Binary file not shown.
BIN
Assets/uDesktopDuplication/Examples/Scenes/Switch Scenes.unity
Normal file
BIN
Assets/uDesktopDuplication/Examples/Scenes/Switch Scenes.unity
Normal file
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ce9467b01f36d647ace156faef9cb9f
|
||||
timeCreated: 1478927635
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -14,22 +14,35 @@ public class Loupe : MonoBehaviour
|
||||
|
||||
void Update()
|
||||
{
|
||||
CheckVariables();
|
||||
|
||||
if (uDesktopDuplication.Manager.cursorMonitorId < 0) return;
|
||||
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
|
||||
|
||||
// To get other monitor textures, set dirty flag.
|
||||
foreach (var monitor in uDesktopDuplication.Manager.monitors) {
|
||||
monitor.CreateTexture();
|
||||
monitor.shouldBeUpdated = true;
|
||||
foreach (var target in uDesktopDuplication.Manager.monitors) {
|
||||
target.CreateTexture();
|
||||
target.shouldBeUpdated = true;
|
||||
}
|
||||
|
||||
var x = (float)uddTexture_.monitor.cursorX / uddTexture_.monitor.width;
|
||||
var y = (float)uddTexture_.monitor.cursorY / uddTexture_.monitor.height;
|
||||
var monitor = uddTexture_.monitor;
|
||||
var cursorX = monitor.isCursorVisible ? monitor.cursorX : monitor.systemCursorX;
|
||||
var cursorY = monitor.isCursorVisible ? monitor.cursorY : monitor.systemCursorY;
|
||||
|
||||
var x = (float)cursorX / monitor.width;
|
||||
var y = (float)cursorY / monitor.height;
|
||||
var w = 1f / zoom;
|
||||
var h = w / aspect * uddTexture_.monitor.aspect;
|
||||
var h = w / aspect * monitor.aspect;
|
||||
x = Mathf.Clamp(x - w / 2, 0f, 1f - w);
|
||||
y = Mathf.Clamp(y - h / 2, 0f, 1f - h);
|
||||
uddTexture_.clipPos = new Vector2(x, y);
|
||||
uddTexture_.clipScale = new Vector2(w, h);
|
||||
}
|
||||
|
||||
void CheckVariables()
|
||||
{
|
||||
if (zoom < 1f) zoom = 1f;
|
||||
if (aspect < 0.01f) aspect = 0.01f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,33 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
|
||||
|
||||
public class MultipleMonitorCreator : MonoBehaviour
|
||||
{
|
||||
[SerializeField] GameObject monitorPrefab;
|
||||
[SerializeField] bool removeIfUnsupported = true;
|
||||
[SerializeField] float removeWaitDuration = 5f;
|
||||
[Tooltip("Create monitors using this prefab.")]
|
||||
[SerializeField]
|
||||
GameObject monitorPrefab;
|
||||
|
||||
[Tooltip("Use same scale as real using DPI.")]
|
||||
[SerializeField]
|
||||
bool useRealScale = true;
|
||||
|
||||
[Tooltip("Use this sacle as width if useRealScale is false.")]
|
||||
[SerializeField]
|
||||
float scale = 0.5f;
|
||||
|
||||
[Tooltip("Remove unsupported monitors automatically after removeWaitDuration.")]
|
||||
[SerializeField]
|
||||
bool removeIfUnsupported = true;
|
||||
|
||||
[Tooltip("Remove unsupported monitors automatically after removeWaitDuration.")]
|
||||
[SerializeField]
|
||||
float removeWaitDuration = 5f;
|
||||
|
||||
bool hasMonitorUnsupportStateChecked = false;
|
||||
float removeWaitTimer_ = 0f;
|
||||
|
||||
public enum MeshForwardDirection { Y, Z }
|
||||
[Tooltip("Please specify the upper vector direction of the mesh (e.g. Plane's upper direction is Y.)")]
|
||||
[Tooltip("Please specify the surface direction of the mesh (e.g. Plane => Y.)")]
|
||||
public MeshForwardDirection meshForwardDirection = MeshForwardDirection.Z;
|
||||
|
||||
public class MonitorInfo
|
||||
@@ -35,6 +52,10 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
if (removeIfUnsupported) {
|
||||
RemoveUnsupportedDisplayAfterRemoveTimer();
|
||||
}
|
||||
|
||||
if (uDesktopDuplication.Manager.monitorCount != monitors.Count) {
|
||||
Recreate();
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
@@ -92,10 +113,18 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
var monitor = texture.monitor;
|
||||
|
||||
// Set width / height
|
||||
if (meshForwardDirection == MeshForwardDirection.Y) {
|
||||
go.transform.localScale = new Vector3(monitor.widthMeter, go.transform.localScale.y, monitor.heightMeter);
|
||||
float width, height;
|
||||
if (useRealScale) {
|
||||
width = monitor.widthMeter;
|
||||
height = monitor.heightMeter;
|
||||
} else {
|
||||
go.transform.localScale = new Vector3(monitor.widthMeter, monitor.heightMeter, go.transform.localScale.z);
|
||||
width = scale * (monitor.isHorizontal ? 1f : monitor.aspect);
|
||||
height = scale * (monitor.isHorizontal ? 1f / monitor.aspect : 1f);
|
||||
}
|
||||
if (meshForwardDirection == MeshForwardDirection.Y) {
|
||||
go.transform.localScale = new Vector3(width, go.transform.localScale.y, height);
|
||||
} else {
|
||||
go.transform.localScale = new Vector3(width, height, go.transform.localScale.z);
|
||||
}
|
||||
|
||||
// Set parent as this object
|
||||
@@ -122,7 +151,8 @@ public class MultipleMonitorCreator : MonoBehaviour
|
||||
monitors_.Clear();
|
||||
}
|
||||
|
||||
void Recreate()
|
||||
[ContextMenu("Recreate")]
|
||||
public void Recreate()
|
||||
{
|
||||
Clear();
|
||||
Create();
|
||||
|
||||
@@ -6,6 +6,7 @@ public class MultipleMonitorLayouter : MonoBehaviour
|
||||
protected MultipleMonitorCreator creator_;
|
||||
[SerializeField] bool updateEveryFrame = true;
|
||||
[SerializeField] protected float margin = 0.1f;
|
||||
[SerializeField][Range(0f, 10f)] protected float thickness = 1f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
@@ -15,16 +16,13 @@ public class MultipleMonitorLayouter : MonoBehaviour
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
margin = Mathf.Max(margin, 0f);
|
||||
|
||||
if (updateEveryFrame) {
|
||||
Layout();
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
margin = Mathf.Max(margin, 0f);
|
||||
}
|
||||
|
||||
protected virtual void Layout()
|
||||
{
|
||||
var monitors = creator_.monitors;
|
||||
@@ -32,19 +30,23 @@ public class MultipleMonitorLayouter : MonoBehaviour
|
||||
|
||||
var totalWidth = 0f;
|
||||
foreach (var info in monitors) {
|
||||
var width = info.uddTexture.monitor.widthMeter * (info.mesh.bounds.extents.x * 2f);
|
||||
var width = info.gameObject.transform.localEulerAngles.x * (info.mesh.bounds.extents.x * 2f);
|
||||
totalWidth += width;
|
||||
}
|
||||
totalWidth += margin * (n - 1);
|
||||
|
||||
var x = -totalWidth / 2;
|
||||
|
||||
foreach (var info in creator_.monitors) {
|
||||
var monitor = info.uddTexture.monitor;
|
||||
x += (monitor.widthMeter * info.mesh.bounds.extents.x);
|
||||
foreach (var info in monitors) {
|
||||
var width = info.gameObject.transform.localEulerAngles.x;
|
||||
x += (width * info.mesh.bounds.extents.x);
|
||||
info.gameObject.transform.localPosition = new Vector3(x, 0f, 0f);
|
||||
info.gameObject.transform.localRotation = info.originalRotation;
|
||||
x += (monitor.widthMeter * info.mesh.bounds.extents.x) + margin;
|
||||
x += (width * info.mesh.bounds.extents.x) + margin;
|
||||
}
|
||||
|
||||
foreach (var info in monitors) {
|
||||
info.uddTexture.thickness = thickness;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
|
||||
{
|
||||
[SerializeField] float radius = 10f;
|
||||
[SerializeField] Vector3 offsetAngle = Vector3.zero;
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
foreach (var info in creator_.monitors) {
|
||||
info.uddTexture.bend = uDesktopDuplication.Texture.Bend.Off;
|
||||
info.uddTexture.bend = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +19,7 @@ public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
|
||||
|
||||
var totalWidth = 0f;
|
||||
foreach (var info in monitors) {
|
||||
var width = info.uddTexture.monitor.widthMeter * (info.mesh.bounds.extents.x * 2f);
|
||||
var width = info.gameObject.transform.localScale.x * (info.mesh.bounds.extents.x * 2f);
|
||||
totalWidth += width;
|
||||
}
|
||||
totalWidth += margin * (n - 1);
|
||||
@@ -27,21 +28,24 @@ public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
|
||||
var totalAngle = totalWidth / radius;
|
||||
|
||||
float angle = -totalAngle / 2;
|
||||
var offsetRot = Quaternion.Euler(offsetAngle);
|
||||
foreach (var info in monitors) {
|
||||
var uddTex = info.uddTexture;
|
||||
var width = uddTex.monitor.widthMeter * (info.mesh.bounds.extents.x * 2f);
|
||||
var width = info.gameObject.transform.localScale.x * (info.mesh.bounds.extents.x * 2f);
|
||||
|
||||
angle += (width / radius) * 0.5f;
|
||||
uddTex.transform.localPosition = radius * new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle) - 1f);
|
||||
uddTex.transform.localRotation = Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.up) * info.originalRotation;
|
||||
var pos = radius * new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle) - 1f);
|
||||
pos += radius * Vector3.forward;
|
||||
pos = offsetRot * pos;
|
||||
pos -= radius * Vector3.forward;
|
||||
uddTex.transform.localPosition = pos;
|
||||
uddTex.transform.localRotation = offsetRot * Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.up) * info.originalRotation;
|
||||
angle += (width * 0.5f + margin) / radius;
|
||||
|
||||
if (creator_.meshForwardDirection == MultipleMonitorCreator.MeshForwardDirection.Y) {
|
||||
uddTex.bend = uDesktopDuplication.Texture.Bend.Y;
|
||||
} else {
|
||||
uddTex.bend = uDesktopDuplication.Texture.Bend.Z;
|
||||
}
|
||||
uddTex.bend = true;
|
||||
uddTex.meshForwardDirection = creator_.meshForwardDirection;
|
||||
uddTex.radius = radius;
|
||||
uddTex.thickness = thickness;
|
||||
uddTex.width = uddTex.transform.localScale.x;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class UddSceneManager : MonoBehaviour
|
||||
{
|
||||
public static UddSceneManager instance { get; set; }
|
||||
[SerializeField] string[] scenes;
|
||||
[SerializeField] int sceneNo = 0;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (!instance) {
|
||||
instance = this;
|
||||
} else {
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
Load();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.RightArrow)) {
|
||||
Next();
|
||||
} else if (Input.GetKeyDown(KeyCode.LeftArrow)) {
|
||||
Prev();
|
||||
}
|
||||
}
|
||||
|
||||
void Next()
|
||||
{
|
||||
sceneNo = (sceneNo + 1) % scenes.Length;
|
||||
Load();
|
||||
}
|
||||
|
||||
void Prev()
|
||||
{
|
||||
sceneNo = (sceneNo - 1) % scenes.Length;
|
||||
Load();
|
||||
}
|
||||
|
||||
void Load()
|
||||
{
|
||||
SceneManager.LoadScene(scenes[sceneNo]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 426ff762e9c02b0499e1453018ecdc94
|
||||
timeCreated: 1478927673
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -37,6 +37,7 @@ public enum MonitorState
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
AccessLost = 6,
|
||||
Unknown = 999,
|
||||
}
|
||||
|
||||
public enum DebugMode
|
||||
|
||||
@@ -65,6 +65,15 @@ public class Manager : MonoBehaviour
|
||||
return go.AddComponent<Manager>();
|
||||
}
|
||||
|
||||
public static Monitor GetMonitor(int id)
|
||||
{
|
||||
if (id < 0 || id >= Manager.monitors.Count) {
|
||||
Debug.LogErrorFormat("[uDD::Error] there is no monitor whose id is {0}.", id);
|
||||
return Manager.primary;
|
||||
}
|
||||
return monitors[Mathf.Clamp(id, 0, Manager.monitorCount - 1)];
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
Lib.SetDebugMode(debugMode);
|
||||
@@ -106,9 +115,12 @@ public class Manager : MonoBehaviour
|
||||
[ContextMenu("Reinitialize")]
|
||||
void Reinitialize()
|
||||
{
|
||||
Debug.Log("[uDesktopDuplication] Reinitialize");
|
||||
Debug.Log("[uDD] Reinitialize");
|
||||
Lib.Reinitialize();
|
||||
if (onReinitialized != null) onReinitialized();
|
||||
CreateMonitors();
|
||||
if (onReinitialized != null) {
|
||||
onReinitialized();
|
||||
}
|
||||
}
|
||||
|
||||
void ReinitializeIfNeeded()
|
||||
@@ -182,6 +194,17 @@ public class Manager : MonoBehaviour
|
||||
monitors[i].Reinitialize();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitThenDo(System.Action func, float sec)
|
||||
{
|
||||
StartCoroutine(_WaitThenDo(func, sec));
|
||||
}
|
||||
|
||||
IEnumerator _WaitThenDo(System.Action func, float sec)
|
||||
{
|
||||
yield return new WaitForSeconds(sec);
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace uDesktopDuplication
|
||||
{
|
||||
@@ -11,24 +12,31 @@ public class Monitor
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case MonitorState.Available:
|
||||
break;
|
||||
case MonitorState.InvalidArg:
|
||||
Debug.LogErrorFormat("[{0}:{1}] Invalid.", id, name);
|
||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Invalid.", id, name);
|
||||
break;
|
||||
case MonitorState.AccessDenied:
|
||||
Debug.LogErrorFormat("[{0}:{1}] Access Denied.", id, name);
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Access Denied.", id, name);
|
||||
break;
|
||||
case MonitorState.Unsupported:
|
||||
Debug.LogErrorFormat("[{0}:{1}] Unsupported.", id, name);
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Unsupported.", id, name);
|
||||
break;
|
||||
case MonitorState.SessionDisconnected:
|
||||
Debug.LogErrorFormat("[{0}:{1}] Disconnected.", id, name);
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Disconnected.", id, name);
|
||||
break;
|
||||
case MonitorState.NotSet:
|
||||
Debug.LogErrorFormat("[{0}:{1}] Something wrong.", id, name);
|
||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Something wrong.", id, name);
|
||||
break;
|
||||
default:
|
||||
Debug.LogErrorFormat("[uDD] {0}:{1} => Unknown error.", id, name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dpiX == 0 || dpiY == 0) {
|
||||
Debug.LogWarningFormat("[uDD] {0}:{1} => Could not get DPI", id, name);
|
||||
}
|
||||
}
|
||||
|
||||
public int id
|
||||
@@ -94,12 +102,22 @@ public class Monitor
|
||||
|
||||
public int dpiX
|
||||
{
|
||||
get { return Lib.GetDpiX(id); }
|
||||
get
|
||||
{
|
||||
var dpi = Lib.GetDpiX(id);
|
||||
if (dpi == 0) dpi = 100; // when monitors are duplicated
|
||||
return dpi;
|
||||
}
|
||||
}
|
||||
|
||||
public int dpiY
|
||||
{
|
||||
get { return Lib.GetDpiY(id); }
|
||||
get
|
||||
{
|
||||
var dpi = Lib.GetDpiY(id);
|
||||
if (dpi == 0) dpi = 100; // when monitors are duplicated
|
||||
return dpi;
|
||||
}
|
||||
}
|
||||
|
||||
public float widthMeter
|
||||
@@ -147,6 +165,24 @@ public class Monitor
|
||||
get { return Lib.GetCursorY(id); }
|
||||
}
|
||||
|
||||
public int systemCursorX
|
||||
{
|
||||
get
|
||||
{
|
||||
var p = Utility.GetCursorPos();
|
||||
return p.x - left;
|
||||
}
|
||||
}
|
||||
|
||||
public int systemCursorY
|
||||
{
|
||||
get
|
||||
{
|
||||
var p = Utility.GetCursorPos();
|
||||
return p.y - top;
|
||||
}
|
||||
}
|
||||
|
||||
public int cursorShapeWidth
|
||||
{
|
||||
get { return Lib.GetCursorShapeWidth(id); }
|
||||
|
||||
@@ -22,7 +22,7 @@ public class Texture : MonoBehaviour
|
||||
public int monitorId
|
||||
{
|
||||
get { return monitor.id; }
|
||||
set { monitor = Manager.monitors[Mathf.Clamp(value, 0, Manager.monitorCount - 1)]; }
|
||||
set { monitor = Manager.GetMonitor(value); }
|
||||
}
|
||||
|
||||
[Header("Invert UVs")]
|
||||
@@ -34,37 +34,44 @@ public class Texture : MonoBehaviour
|
||||
public Vector2 clipPos = Vector2.zero;
|
||||
public Vector2 clipScale = new Vector2(0.2f, 0.2f);
|
||||
|
||||
public enum Bend
|
||||
public enum MeshForwardDirection
|
||||
{
|
||||
Off = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
Y = 0,
|
||||
Z = 1,
|
||||
}
|
||||
|
||||
public Bend bend
|
||||
public bool bend
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Bend)material.GetInt("_Bend");
|
||||
return material.GetInt("_Bend") != 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value) {
|
||||
material.EnableKeyword("BEND_ON");
|
||||
} else {
|
||||
material.DisableKeyword("BEND_ON");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MeshForwardDirection meshForwardDirection
|
||||
{
|
||||
get
|
||||
{
|
||||
return (MeshForwardDirection)material.GetInt("_Forward");
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (value) {
|
||||
case Bend.Off:
|
||||
material.SetInt("_Bend", 0);
|
||||
material.DisableKeyword("_BEND_OFF");
|
||||
material.DisableKeyword("_BEND_Y");
|
||||
material.DisableKeyword("_BEND_Z");
|
||||
break;
|
||||
case Bend.Y:
|
||||
material.SetInt("_Bend", 1);
|
||||
material.DisableKeyword("_BEND_OFF");
|
||||
case MeshForwardDirection.Y:
|
||||
material.SetInt("_Forward", 0);
|
||||
material.EnableKeyword("_BEND_Y");
|
||||
material.DisableKeyword("_BEND_Z");
|
||||
break;
|
||||
case Bend.Z:
|
||||
material.SetInt("_Bend", 2);
|
||||
material.DisableKeyword("_BEND_OFF");
|
||||
case MeshForwardDirection.Z:
|
||||
material.SetInt("_Forward", 1);
|
||||
material.DisableKeyword("_BEND_Y");
|
||||
material.EnableKeyword("_BEND_Z");
|
||||
break;
|
||||
@@ -84,6 +91,12 @@ public class Texture : MonoBehaviour
|
||||
set { material.SetFloat("_Width", value); }
|
||||
}
|
||||
|
||||
public float thickness
|
||||
{
|
||||
get { return material.GetFloat("_Thickness"); }
|
||||
set { material.SetFloat("_Thickness", value); }
|
||||
}
|
||||
|
||||
public Material material
|
||||
{
|
||||
get;
|
||||
|
||||
30
Assets/uDesktopDuplication/Scripts/Utility.cs
Normal file
30
Assets/uDesktopDuplication/Scripts/Utility.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace uDesktopDuplication
|
||||
{
|
||||
|
||||
public struct MousePoint
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
}
|
||||
|
||||
public static class Utility
|
||||
{
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetCursorPos(out MousePoint point);
|
||||
|
||||
public static MousePoint GetCursorPos()
|
||||
{
|
||||
MousePoint p;
|
||||
if (!GetCursorPos(out p)) {
|
||||
p.x = -1;
|
||||
p.y = -1;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
Assets/uDesktopDuplication/Scripts/Utility.cs.meta
Normal file
12
Assets/uDesktopDuplication/Scripts/Utility.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c7e8da181b03ce4fb343ffa33cbb929
|
||||
timeCreated: 1479043365
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 89616e59e1cccb346bd4e959257990ca, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -21,7 +21,7 @@ struct Input
|
||||
float2 uv_MainTex;
|
||||
};
|
||||
|
||||
float2 uddInvertUV(float2 uv)
|
||||
inline float2 uddInvertUV(float2 uv)
|
||||
{
|
||||
#ifdef INVERT_X
|
||||
uv.x = 1.0 - uv.x;
|
||||
@@ -32,7 +32,7 @@ float2 uddInvertUV(float2 uv)
|
||||
return uv;
|
||||
}
|
||||
|
||||
float2 uddRotateUV(float2 uv)
|
||||
inline float2 uddRotateUV(float2 uv)
|
||||
{
|
||||
#ifdef ROTATE90
|
||||
float2 tmp = uv;
|
||||
@@ -49,7 +49,7 @@ float2 uddRotateUV(float2 uv)
|
||||
return uv;
|
||||
}
|
||||
|
||||
float2 uddClipUV(float2 uv)
|
||||
inline float2 uddClipUV(float2 uv)
|
||||
{
|
||||
uv.x = _ClipX + uv.x * _ClipWidth;
|
||||
uv.y = _ClipY + uv.y * _ClipHeight;
|
||||
@@ -92,18 +92,26 @@ inline fixed4 uddGetScreenTextureWithCursor(float2 uv)
|
||||
return color;
|
||||
}
|
||||
|
||||
inline void uddBendVertex(inout float4 v, half radius, half width)
|
||||
inline void uddBendVertex(inout float4 v, half radius, half width, half thickness)
|
||||
{
|
||||
#if !defined(_BEND_OFF)
|
||||
#ifdef BEND_ON
|
||||
half angle = width * v.x / radius;
|
||||
#ifdef _BEND_Y
|
||||
#ifdef _FORWARD_Z
|
||||
v.y *= thickness;
|
||||
radius -= v.y;
|
||||
v.y += radius * (1 - cos(angle));
|
||||
#elif _BEND_Z
|
||||
#elif _FORWARD_Y
|
||||
v.z *= thickness;
|
||||
radius -= v.z;
|
||||
v.z += radius * (1 - cos(angle));
|
||||
#endif
|
||||
v.x = radius * sin(angle) / width;
|
||||
#else
|
||||
#ifdef _FORWARD_Z
|
||||
v.y *= thickness;
|
||||
#elif _FORWARD_Y
|
||||
v.z *= thickness;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@ Properties
|
||||
_Color ("Color", Color) = (1, 1, 1, 1)
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_CursorTex ("Cursor Texture", 2D) = "white" {}
|
||||
[KeywordEnum(Off, Y, Z)] _Bend("Bending", Int) = 0
|
||||
[PowerSlider(10.0)] _Radius("Radius", Range(1, 100)) = 30
|
||||
[KeywordEnum(Y, Z)] _Forward("Mesh Forward Direction", Int) = 0
|
||||
[Toggle(BEND_ON)] _Bend("Use Bend", Int) = 0
|
||||
[PowerSlider(10.0)] _Radius("Bend Radius", Range(1, 100)) = 30
|
||||
[PowerSlider(10.0)] _Thickness("Thickness", Range(0.01, 10)) = 1
|
||||
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
|
||||
}
|
||||
|
||||
@@ -24,11 +26,12 @@ CGINCLUDE
|
||||
|
||||
half _Radius;
|
||||
half _Width;
|
||||
half _Thickness;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
uddBendVertex(v.vertex, _Radius, _Width);
|
||||
uddBendVertex(v.vertex, _Radius, _Width, _Thickness);
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
return o;
|
||||
@@ -50,7 +53,8 @@ Pass
|
||||
#pragma multi_compile ___ INVERT_Y
|
||||
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
|
||||
#pragma multi_compile ___ USE_CLIP
|
||||
#pragma multi_compile _BEND_OFF _BEND_Y _BEND_Z
|
||||
#pragma multi_compile ___ BEND_ON
|
||||
#pragma multi_compile _FORWARD_Y _FORWARD_Z
|
||||
ENDCG
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@ Properties
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_Mask ("Mask", Range(0, 1)) = 0.1
|
||||
_CursorTex ("Cursor Texture", 2D) = "white" {}
|
||||
[KeywordEnum(Off, Y, Z)] _Bend("Bending", Int) = 0
|
||||
[PowerSlider(10.0)] _Radius("Radius", Range(1, 100)) = 30
|
||||
[KeywordEnum(Y, Z)] _Forward("Mesh Forward Direction", Int) = 0
|
||||
[Toggle(BEND_ON)] _Bend("Use Bend", Int) = 0
|
||||
[PowerSlider(10.0)] _Radius("Bend Radius", Range(1, 100)) = 30
|
||||
[PowerSlider(10.0)] _Thickness("Thickness", Range(0.01, 10)) = 1
|
||||
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
|
||||
}
|
||||
|
||||
@@ -28,11 +30,12 @@ CGINCLUDE
|
||||
fixed _Mask;
|
||||
half _Radius;
|
||||
half _Width;
|
||||
half _Thickness;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
uddBendVertex(v.vertex, _Radius, _Width);
|
||||
uddBendVertex(v.vertex, _Radius, _Width, _Thickness);
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
return o;
|
||||
|
||||
@@ -6,8 +6,10 @@ Properties
|
||||
_Color ("Color", Color) = (1, 1, 1, 1)
|
||||
_MainTex ("Texture", 2D) = "white" {}
|
||||
_CursorTex ("Cursor Texture", 2D) = "white" {}
|
||||
[KeywordEnum(Off, Y, Z)] _Bend("Bending", Int) = 0
|
||||
[PowerSlider(10.0)] _Radius("Radius", Range(1, 100)) = 30
|
||||
[KeywordEnum(Y, Z)] _Forward("Mesh Forward Direction", Int) = 0
|
||||
[Toggle(BEND_ON)] _Bend("Use Bend", Int) = 0
|
||||
[PowerSlider(10.0)] _Radius("Bend Radius", Range(1, 100)) = 30
|
||||
[PowerSlider(10.0)] _Thickness("Thickness", Range(0.01, 10)) = 1
|
||||
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
|
||||
}
|
||||
|
||||
@@ -26,11 +28,12 @@ CGINCLUDE
|
||||
|
||||
half _Radius;
|
||||
half _Width;
|
||||
half _Thickness;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
uddBendVertex(v.vertex, _Radius, _Width);
|
||||
uddBendVertex(v.vertex, _Radius, _Width, _Thickness);
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
return o;
|
||||
|
||||
@@ -4,81 +4,28 @@
|
||||
#include "Debug.h"
|
||||
|
||||
|
||||
decltype(Debug::mode_) Debug::mode_ = Debug::Mode::kFile;
|
||||
decltype(Debug::mode_) Debug::mode_ = Debug::Mode::File;
|
||||
decltype(Debug::logFunc_) Debug::logFunc_ = nullptr;
|
||||
decltype(Debug::errFunc_) Debug::errFunc_ = nullptr;
|
||||
decltype(Debug::fs_) Debug::fs_;
|
||||
decltype(Debug::ss_) Debug::ss_;
|
||||
|
||||
|
||||
void Debug::Initialize()
|
||||
{
|
||||
if (mode_ == Mode::kFile)
|
||||
if (mode_ == Mode::File)
|
||||
{
|
||||
fs_.open("uDesktopDuplication.log");
|
||||
Debug::Log("Start");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::Finalize()
|
||||
{
|
||||
fs_.close();
|
||||
}
|
||||
|
||||
|
||||
void Debug::Log(const char* msg)
|
||||
{
|
||||
switch (mode_)
|
||||
if (mode_ == Mode::File)
|
||||
{
|
||||
case Mode::kNone:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Mode::kFile:
|
||||
{
|
||||
if (fs_.good())
|
||||
{
|
||||
fs_ << "[uDD::Log] " << msg << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::kUnityLog:
|
||||
{
|
||||
if (logFunc_ == nullptr)
|
||||
{
|
||||
char buf[256];
|
||||
sprintf_s(buf, 256, "[uDD::Log] %s", msg);
|
||||
logFunc_(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Debug::Error(const char* msg)
|
||||
{
|
||||
switch (mode_)
|
||||
{
|
||||
case Mode::kNone:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Mode::kFile:
|
||||
{
|
||||
if (fs_.good())
|
||||
{
|
||||
fs_ << "[uDD::Err] " << msg << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::kUnityLog:
|
||||
{
|
||||
if (logFunc_ == nullptr)
|
||||
{
|
||||
char buf[256];
|
||||
sprintf_s(buf, 256, "[uDD::Err] %s", msg);
|
||||
errFunc_(buf);
|
||||
}
|
||||
}
|
||||
Debug::Log("Stop");
|
||||
fs_.close();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "IUnityInterface.h"
|
||||
|
||||
// Logging
|
||||
@@ -8,9 +9,9 @@ class Debug
|
||||
public:
|
||||
enum class Mode
|
||||
{
|
||||
kNone = 0,
|
||||
kFile = 1,
|
||||
kUnityLog = 2,
|
||||
None = 0,
|
||||
File = 1,
|
||||
UnityLog = 2,
|
||||
};
|
||||
|
||||
using DebugLogFuncPtr = void(UNITY_INTERFACE_API *)(const char*);
|
||||
@@ -21,13 +22,89 @@ public:
|
||||
static void SetLogFunc(DebugLogFuncPtr func) { logFunc_ = func; }
|
||||
static void SetErrorFunc(DebugLogFuncPtr func) { errFunc_ = func; }
|
||||
|
||||
private:
|
||||
enum class Level
|
||||
{
|
||||
Log,
|
||||
Error
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static void Output(T&& arg)
|
||||
{
|
||||
if (mode_ == Mode::None) return;
|
||||
if (ss_.good())
|
||||
{
|
||||
ss_ << std::forward<T>(arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void Flush(Level level)
|
||||
{
|
||||
switch (mode_)
|
||||
{
|
||||
case Mode::None:
|
||||
{
|
||||
return;
|
||||
}
|
||||
case Mode::File:
|
||||
{
|
||||
if (fs_.good() && ss_.good())
|
||||
{
|
||||
const auto str = ss_.str();
|
||||
fs_ << str << std::endl;
|
||||
fs_.flush();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::UnityLog:
|
||||
{
|
||||
if (ss_.good())
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case Level::Log : logFunc_(ss_.str().c_str()); break;
|
||||
case Level::Error : errFunc_(ss_.str().c_str()); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ss_.str("");
|
||||
ss_.clear(std::stringstream::goodbit);
|
||||
}
|
||||
|
||||
template <class Arg, class... RestArgs>
|
||||
static void _Log(Level level, Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
Output(std::forward<Arg>(arg));
|
||||
_Log(level, std::forward<RestArgs>(restArgs)...);
|
||||
}
|
||||
|
||||
static void _Log(Level level)
|
||||
{
|
||||
Flush(level);
|
||||
}
|
||||
|
||||
public:
|
||||
static void Log(const char* msg);
|
||||
static void Error(const char* msg);
|
||||
template <class Arg, class... RestArgs>
|
||||
static void Log(Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
Output("[uDD::Log] ");
|
||||
_Log(Level::Log, std::forward<Arg>(arg), std::forward<RestArgs>(restArgs)...);
|
||||
}
|
||||
|
||||
template <class Arg, class... RestArgs>
|
||||
static void Error(Arg&& arg, RestArgs&&... restArgs)
|
||||
{
|
||||
Output("[uDD::Err] ");
|
||||
_Log(Level::Error, std::forward<Arg>(arg), std::forward<RestArgs>(restArgs)...);
|
||||
}
|
||||
|
||||
private:
|
||||
static Mode mode_;
|
||||
static std::ofstream fs_;
|
||||
static std::ostringstream ss_;
|
||||
static DebugLogFuncPtr logFunc_;
|
||||
static DebugLogFuncPtr errFunc_;
|
||||
};
|
||||
@@ -38,6 +38,9 @@ void Monitor::Initialize(IDXGIOutput* output)
|
||||
case S_OK:
|
||||
state_ = State::Available;
|
||||
Debug::Log("Monitor::Initialize() => OK.");
|
||||
Debug::Log(" ID : ", GetId());
|
||||
Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")");
|
||||
Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")");
|
||||
break;
|
||||
case E_INVALIDARG:
|
||||
state_ = State::InvalidArg;
|
||||
@@ -64,6 +67,10 @@ void Monitor::Initialize(IDXGIOutput* output)
|
||||
state_ = State::SessionDisconnected;
|
||||
Debug::Error("Monitor::Initialize() => Session disconnected.");
|
||||
break;
|
||||
default:
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +105,8 @@ void Monitor::Render(UINT timeout)
|
||||
Debug::Error("Monitor::Render() => E_INVALIDARG.");
|
||||
break;
|
||||
default:
|
||||
state_ = State::Unknown;
|
||||
Debug::Error("Monitor::Render() => Unknown Error.");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
@@ -108,9 +117,22 @@ void Monitor::Render(UINT timeout)
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
resource.As<ID3D11Texture2D>(&texture);
|
||||
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(unityTexture_, texture.Get());
|
||||
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
|
||||
texture->GetDesc(&srcDesc);
|
||||
texture->GetDesc(&dstDesc);
|
||||
if (srcDesc.Width != dstDesc.Width ||
|
||||
srcDesc.Height != dstDesc.Height)
|
||||
{
|
||||
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
|
||||
Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")");
|
||||
Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
GetDevice()->GetImmediateContext(&context);
|
||||
context->CopyResource(unityTexture_, texture.Get());
|
||||
}
|
||||
}
|
||||
|
||||
cursor_->UpdateBuffer(frameInfo);
|
||||
@@ -180,25 +202,25 @@ bool Monitor::IsPrimary() const
|
||||
|
||||
int Monitor::GetLeft() const
|
||||
{
|
||||
return outputDesc_.DesktopCoordinates.left;
|
||||
return static_cast<int>(outputDesc_.DesktopCoordinates.left);
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetRight() const
|
||||
{
|
||||
return outputDesc_.DesktopCoordinates.right;
|
||||
return static_cast<int>(outputDesc_.DesktopCoordinates.right);
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetTop() const
|
||||
{
|
||||
return outputDesc_.DesktopCoordinates.top;
|
||||
return static_cast<int>(outputDesc_.DesktopCoordinates.top);
|
||||
}
|
||||
|
||||
|
||||
int Monitor::GetBottom() const
|
||||
{
|
||||
return outputDesc_.DesktopCoordinates.bottom;
|
||||
return static_cast<int>(outputDesc_.DesktopCoordinates.bottom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ enum class MonitorState
|
||||
CurrentlyNotAvailable = 4,
|
||||
SessionDisconnected = 5,
|
||||
AccessLost = 6,
|
||||
Unknown = 999,
|
||||
};
|
||||
|
||||
class Monitor
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "IUnityGraphicsD3D11.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "Debug.h"
|
||||
#include "Monitor.h"
|
||||
#include "Cursor.h"
|
||||
#include "MonitorManager.h"
|
||||
@@ -67,11 +68,36 @@ void MonitorManager::RequireReinitilization()
|
||||
|
||||
void MonitorManager::Reinitialize()
|
||||
{
|
||||
Debug::Log("MonitorManager::Reinitialize()");
|
||||
Initialize();
|
||||
SendMessageToUnity(Message::Reinitialized);
|
||||
}
|
||||
|
||||
|
||||
void MonitorManager::CheckMonitorNumbers()
|
||||
{
|
||||
ComPtr<IDXGIFactory1> factory;
|
||||
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
||||
|
||||
int id = 0;
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
|
||||
{
|
||||
ComPtr<IDXGIOutput> output;
|
||||
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
|
||||
{
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetMonitorCount() != id)
|
||||
{
|
||||
Debug::Log("Monitor number changed: ", GetMonitorCount(), " => ", id);
|
||||
RequireReinitilization();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
|
||||
{
|
||||
if (id >= 0 && id < monitors_.size())
|
||||
@@ -84,6 +110,8 @@ std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
|
||||
|
||||
void MonitorManager::Update()
|
||||
{
|
||||
CheckMonitorNumbers();
|
||||
|
||||
if (isReinitializationRequired_)
|
||||
{
|
||||
Reinitialize();
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
explicit MonitorManager();
|
||||
~MonitorManager();
|
||||
void Reinitialize();
|
||||
void CheckMonitorNumbers();
|
||||
void RequireReinitilization();
|
||||
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
|
||||
int GetCursorMonitorId() const { return cursorMonitorId_; }
|
||||
|
||||
@@ -29,21 +29,24 @@ extern "C"
|
||||
{
|
||||
if (g_unity && !g_manager)
|
||||
{
|
||||
g_manager = std::make_unique<MonitorManager>();
|
||||
Debug::Initialize();
|
||||
g_manager = std::make_unique<MonitorManager>();
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API FinalizeUDD()
|
||||
{
|
||||
g_manager.reset();
|
||||
if (g_manager)
|
||||
{
|
||||
g_manager.reset();
|
||||
|
||||
std::queue<Message> empty;
|
||||
g_messages.swap(empty);
|
||||
std::queue<Message> empty;
|
||||
g_messages.swap(empty);
|
||||
|
||||
Debug::SetLogFunc(nullptr);
|
||||
Debug::SetErrorFunc(nullptr);
|
||||
Debug::Finalize();
|
||||
Debug::SetLogFunc(nullptr);
|
||||
Debug::SetErrorFunc(nullptr);
|
||||
Debug::Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user