Compare commits

..

14 Commits

Author SHA1 Message Date
hecomi
fb7bcbfa5b change texture cache key. 2016-11-09 00:13:55 +09:00
hecomi
9ed8bb8d5b fix mouse cursor mono mask bug. 2016-11-09 00:02:43 +09:00
hecomi
fab67bbc61 add null check. 2016-11-08 23:28:37 +09:00
hecomi
5fa9f03a0e separate multiple monitors examples. 2016-11-08 22:10:47 +09:00
hecomi
941bb2da91 add round layout example. 2016-11-08 22:09:55 +09:00
hecomi
d423e0d1db remove collider from prefab. 2016-11-06 23:29:19 +09:00
hecomi
33a55d95bd add clipping function and the example. 2016-11-06 23:28:33 +09:00
hecomi
8e2d8d3218 fix cursor visibility bug. 2016-11-06 21:16:35 +09:00
hecomi
6ac1a5ee60 get dpi of monitor and calculate actual size of it. 2016-11-06 12:17:29 +09:00
hecomi
15a98cd774 fix singleton bug. 2016-11-06 11:55:01 +09:00
hecomi
06bb971a42 support display setting change in realtime. 2016-11-06 04:04:23 +09:00
hecomi
217e63d40c fix indent. 2016-11-06 03:33:21 +09:00
hecomi
9e42fb0abf there is only one cursor in screens. 2016-11-06 03:30:21 +09:00
hecomi
9de5064fbe do reinitialization from unity. 2016-11-06 00:39:07 +09:00
37 changed files with 785 additions and 239 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4bae91f55031b98488c9e668031f7387
timeCreated: 1478610618
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f3d41026babadc241b9d0852b0831584
timeCreated: 1478436298
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using UnityEngine;
public class Loupe : MonoBehaviour
{
private uDesktopDuplication.Texture uddTexture_;
public float zoom = 3f;
public float aspect = 1f;
void Start()
{
uddTexture_ = GetComponent<uDesktopDuplication.Texture>();
uddTexture_.useClip = true;
}
void Update()
{
// To get other monitor textures, set dirty flag.
foreach (var monitor in uDesktopDuplication.Manager.monitors) {
monitor.CreateTexture();
monitor.shouldBeUpdated = true;
}
if (!uddTexture_.monitor.isCursorVisible) {
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
}
var x = (float)uddTexture_.monitor.cursorX / uddTexture_.monitor.width;
var y = (float)uddTexture_.monitor.cursorY / uddTexture_.monitor.height;
var w = 1f / zoom;
var h = w / aspect * uddTexture_.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);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: efd9499cdb931b945947a2cd47909676
timeCreated: 1478438457
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,21 +1,44 @@
using UnityEngine;
using System.Collections.Generic;
public class MultipleMonitorCreator : MonoBehaviour
{
[SerializeField] GameObject monitorPrefab;
[SerializeField] float width = 0.3f;
[SerializeField] float margin = 1f;
public class MonitorInfo
{
public GameObject gameObject { get; set; }
public Quaternion originalRotation { get; set; }
public uDesktopDuplication.Texture uddTexture { get; set; }
public Vector3 meshBounds;
}
private List<MonitorInfo> monitors_ = new List<MonitorInfo>();
public List<MonitorInfo> monitors { get { return monitors_; } }
void Start()
{
Create();
}
void OnEnable()
{
uDesktopDuplication.Manager.onReinitialized += Recreate;
}
void OnDisable()
{
uDesktopDuplication.Manager.onReinitialized -= Recreate;
}
void Create()
{
// Sort monitors in coordinate order
var monitors = uDesktopDuplication.Manager.monitors;
monitors.Sort((a, b) => a.left - b.left);
// Create monitors
var n = monitors.Count;
var totalWidth = 0f;
for (int i = 0 ; i < n; ++i) {
for (int i = 0 ; i < uDesktopDuplication.Manager.monitorCount; ++i) {
// Create monitor obeject
var go = Instantiate(monitorPrefab);
go.name = "Monitor " + i;
@@ -23,35 +46,39 @@ public class MultipleMonitorCreator : MonoBehaviour
// Assign monitor
var texture = go.GetComponent<uDesktopDuplication.Texture>();
texture.monitorId = i;
var monitor = texture.monitor;
// Set width / height
var isHorizontal = texture.monitor.isHorizontal;
var w = isHorizontal ? width : (width * texture.monitor.aspect);
var h = isHorizontal ? width / texture.monitor.aspect : width;
go.transform.localScale = new Vector3(w, go.transform.localScale.y, h);
go.transform.localScale = new Vector3(monitor.widthMeter, go.transform.localScale.y, monitor.heightMeter);
// Set parent as this object
go.transform.SetParent(transform);
// Calc actual size considering mesh size
var scaleX = go.GetComponent<MeshFilter>().sharedMesh.bounds.extents.x * 2f;
totalWidth += w * scaleX;
}
var bounds = go.GetComponent<MeshFilter>().sharedMesh.bounds.extents * 2f;
// Set positions with margin
totalWidth += margin * (n - 1);
var x = -totalWidth / 2;
for (int i = 0 ; i < n; ++i) {
//
var go = transform.FindChild("Monitor " + i);
var texture = go.GetComponent<uDesktopDuplication.Texture>();
var halfScaleX = go.GetComponent<MeshFilter>().sharedMesh.bounds.extents.x;
var w = texture.monitor.isHorizontal ? width : (width * texture.monitor.aspect);
var halfWidth = w * halfScaleX;
x += halfWidth;
go.transform.localPosition = new Vector3(x, 0f, 0f);
x += halfWidth + margin;
// Save
var info = new MonitorInfo();
info.gameObject = go;
info.originalRotation = go.transform.rotation;
info.uddTexture = texture;
info.meshBounds = bounds;
monitors_.Add(info);
}
}
void Clear()
{
foreach (var info in monitors_) {
Destroy(info.gameObject);
}
monitors_.Clear();
}
void Recreate()
{
Clear();
Create();
}
}

View File

@@ -0,0 +1,52 @@
using UnityEngine;
[RequireComponent(typeof(MultipleMonitorCreator))]
public class MultipleMonitorLayouter : MonoBehaviour
{
protected MultipleMonitorCreator creator_;
[SerializeField] bool updateEveryFrame = true;
[SerializeField] protected float margin = 0.1f;
void Start()
{
creator_ = GetComponent<MultipleMonitorCreator>();
Layout();
}
protected virtual void Update()
{
if (updateEveryFrame) {
Layout();
}
}
void LateUpdate()
{
margin = Mathf.Max(margin, 0f);
}
protected virtual void Layout()
{
var monitors = creator_.monitors;
var n = monitors.Count;
var totalWidth = 0f;
foreach (var info in monitors) {
var width = info.uddTexture.monitor.widthMeter * info.meshBounds.x;
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.meshBounds.x) / 2;
info.gameObject.transform.localPosition = new Vector3(x, 0f, 0f);
info.gameObject.transform.localRotation = info.originalRotation;
x += (monitor.widthMeter * info.meshBounds.x) / 2 + margin;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0db1dcac2dedc724194c423ee75b3bf4
timeCreated: 1478608632
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using UnityEngine;
public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
{
[SerializeField] float radius = 10f;
void OnDisable()
{
foreach (var info in creator_.monitors) {
info.uddTexture.bend = uDesktopDuplication.Texture.Bend.Off;
}
}
protected override void Layout()
{
var monitors = creator_.monitors;
var n = monitors.Count;
var totalWidth = 0f;
foreach (var info in monitors) {
var width = info.uddTexture.monitor.widthMeter * info.meshBounds.x;
totalWidth += width;
}
totalWidth += margin * (n - 1);
radius = Mathf.Max(radius, (totalWidth + margin) / (2 * Mathf.PI));
var totalAngle = totalWidth / radius;
float angle = -totalAngle / 2;
foreach (var info in monitors) {
var uddTex = info.uddTexture;
var width = uddTex.monitor.widthMeter * info.meshBounds.x;
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;
angle += (width * 0.5f + margin) / radius;
uddTex.bend = uDesktopDuplication.Texture.Bend.Y;
uddTex.radius = radius;
uddTex.width = uddTex.monitor.widthMeter;
}
}
protected override void Update()
{
base.Update();
var scale = transform.localScale.x;
var center = transform.position - Vector3.forward * radius * scale;
for (int i = 0; i < 100; ++i) {
var a0 = 2 * Mathf.PI * i / 100;
var a1 = 2 * Mathf.PI * (i + 1) / 100;
var p0 = center + radius * scale * new Vector3(Mathf.Cos(a0), 0f, Mathf.Sin(a0));
var p1 = center + radius * scale * new Vector3(Mathf.Cos(a1), 0f, Mathf.Sin(a1));
Debug.DrawLine(p0, p1, Color.red);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a31b05fdfa301f14e88365e64622b43a
timeCreated: 1478524060
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,14 +8,13 @@ namespace uDesktopDuplication
RequireComponent(typeof(Texture))]
public class Cursor : MonoBehaviour
{
[SerializeField] Vector2 modelScale = Vector2.one;
Vector3 worldPosition { get; set; }
private Texture uddTexture_;
private Monitor monitor { get { return uddTexture_.monitor; } }
private Texture2D currentTexture_;
private Dictionary<Vector2, Texture2D> textures_ = new Dictionary<Vector2, Texture2D>();
[SerializeField] Vector2 modelScale = Vector2.one;
private Dictionary<int, Texture2D> textures_ = new Dictionary<int, Texture2D>();
void Start()
{
@@ -27,8 +26,8 @@ public class Cursor : MonoBehaviour
if (monitor.isCursorVisible) {
UpdatePosition();
UpdateTexture();
UpdateMaterial();
}
UpdateMaterial();
}
void UpdatePosition()
@@ -46,22 +45,22 @@ public class Cursor : MonoBehaviour
var h = monitor.cursorShapeHeight;
if (w == 0 || h == 0) return;
var scale = new Vector2(w, h);
if (!textures_.ContainsKey(scale)) {
var key = w + h * 100;
if (!textures_.ContainsKey(key)) {
var texture = new Texture2D(w, h, TextureFormat.BGRA32, false);
texture.wrapMode = TextureWrapMode.Clamp;
textures_.Add(scale, texture);
textures_.Add(key, texture);
}
var cursorTexture = textures_[scale];
monitor.UpdateCursorTexture(cursorTexture.GetNativeTexturePtr());
var cursorTexture = textures_[key];
monitor.GetCursorTexture(cursorTexture.GetNativeTexturePtr());
uddTexture_.material.SetTexture("_CursorTex", cursorTexture);
}
void UpdateMaterial()
{
var x = (float)monitor.cursorX / monitor.width;
var y = (float)monitor.cursorY / monitor.height;
var x = monitor.isCursorVisible ? (float)monitor.cursorX / monitor.width : -9999f;
var y = monitor.isCursorVisible ? (float)monitor.cursorY / monitor.height : -9999f;
var w = (float)monitor.cursorShapeWidth / monitor.width;
var h = (float)monitor.cursorShapeHeight / monitor.height;
uddTexture_.material.SetVector("_CursorPositionScale", new Vector4(x, y, w, h));

View File

@@ -27,6 +27,18 @@ public enum MonitorRotation
Rotate270 = 4
}
public enum MonitorState
{
NotSet = -1,
Available = 0,
InvalidArg = 1,
AccessDenied = 2,
Unsupported = 3,
CurrentlyNotAvailable = 4,
SessionDisconnected = 5,
AccessLost = 6,
}
public static class Lib
{
public delegate void MessageHandler(Message message);
@@ -36,12 +48,16 @@ public static class Lib
[DllImport("uDesktopDuplication")]
public static extern void FinalizeUDD();
[DllImport("uDesktopDuplication")]
public static extern void Reinitialize();
[DllImport("uDesktopDuplication")]
public static extern void Update();
[DllImport("uDesktopDuplication")]
public static extern Message PopMessage();
[DllImport("uDesktopDuplication")]
public static extern int GetMonitorCount();
[DllImport("uDesktopDuplication")]
public static extern int GetCursorMonitorId();
[DllImport("uDesktopDuplication")]
public static extern int GetTotalWidth();
[DllImport("uDesktopDuplication")]
public static extern int GetTotalHeight();
@@ -50,7 +66,7 @@ public static class Lib
[DllImport("uDesktopDuplication")]
public static extern IntPtr GetRenderEventFunc();
[DllImport("uDesktopDuplication")]
public static extern bool IsAvailable(int id);
public static extern MonitorState GetState(int id);
[DllImport("uDesktopDuplication")]
public static extern void GetName(int id, StringBuilder buf, int len);
[DllImport("uDesktopDuplication")]
@@ -66,6 +82,10 @@ public static class Lib
[DllImport("uDesktopDuplication")]
public static extern int GetHeight(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetDpiX(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetDpiY(int id);
[DllImport("uDesktopDuplication")]
public static extern MonitorRotation GetRotation(int id);
[DllImport("uDesktopDuplication")]
public static extern bool IsPrimary(int id);
@@ -84,7 +104,7 @@ public static class Lib
[DllImport("uDesktopDuplication")]
public static extern CursorShapeType GetCursorShapeType(int id);
[DllImport("uDesktopDuplication")]
public static extern void UpdateCursorTexture(int id, System.IntPtr ptr);
public static extern void GetCursorTexture(int id, System.IntPtr ptr);
[DllImport("uDesktopDuplication")]
public static extern int SetTexturePtr(int id, IntPtr ptr);

View File

@@ -12,7 +12,16 @@ public class Manager : MonoBehaviour
{
get
{
if (instance_) return instance_;
if (instance_) {
return instance_;
}
var manager = FindObjectOfType<Manager>();
if (manager) {
manager.Awake();
return manager;
}
var go = new GameObject("uDesktopDuplicationManager");
return go.AddComponent<Manager>();
}
@@ -29,6 +38,11 @@ public class Manager : MonoBehaviour
get { return Lib.GetMonitorCount(); }
}
static public int cursorMonitorId
{
get { return Lib.GetCursorMonitorId(); }
}
static public Monitor primary
{
get
@@ -37,10 +51,15 @@ public class Manager : MonoBehaviour
}
}
[SerializeField, Tooltip("Set Desktop Duplication API timeout (milliseconds).")]
int timeout = 0;
[SerializeField] int desktopDuplicationApiTimeout = 0;
[SerializeField] float retryReinitializationDuration = 1f;
private Coroutine renderCoroutine_ = null;
private bool shouldReinitialize = false;
private float reinitializationTimer = 0f;
public delegate void ReinitializeHandler();
public static event ReinitializeHandler onReinitialized;
void Awake()
{
@@ -51,7 +70,7 @@ public class Manager : MonoBehaviour
CreateMonitors();
Lib.SetTimeout(timeout);
Lib.SetTimeout(desktopDuplicationApiTimeout);
}
void OnApplicationQuit()
@@ -75,13 +94,56 @@ public class Manager : MonoBehaviour
void Update()
{
Lib.Update();
ReinitializeIfNeeded();
UpdateMessage();
/*
foreach (var monitor in monitors_) {
Debug.LogFormat("[{0}] {1}", monitor.id, monitor.state);
}
*/
}
[ContextMenu("Reinitialize")]
void Reinitialize()
{
Debug.Log("[uDesktopDuplication] Reinitialize");
Lib.Reinitialize();
if (onReinitialized != null) onReinitialized();
}
void ReinitializeIfNeeded()
{
for (int i = 0; i < monitors.Count; ++i) {
var monitor = monitors[i];
if (monitor.state == MonitorState.NotSet ||
monitor.state == MonitorState.AccessLost ||
monitor.state == MonitorState.AccessDenied ||
monitor.state == MonitorState.SessionDisconnected) {
if (!shouldReinitialize) {
shouldReinitialize = true;
reinitializationTimer = 0f;
break;
}
}
}
if (shouldReinitialize) {
if (reinitializationTimer > retryReinitializationDuration) {
Reinitialize();
shouldReinitialize = false;
}
reinitializationTimer += Time.deltaTime;
}
}
void UpdateMessage()
{
var message = Lib.PopMessage();
while (message != Message.None) {
switch (message) {
case Message.Reinitialized:
Debug.Log("Reinitialize");
Reinitialize();
ReinitializeMonitors();
break;
default:
break;
@@ -111,7 +173,7 @@ public class Manager : MonoBehaviour
}
}
void Reinitialize()
void ReinitializeMonitors()
{
for (int i = 0; i < monitorCount; ++i) {
if (i == monitors.Count) {

View File

@@ -8,6 +8,27 @@ public class Monitor
public Monitor(int id)
{
this.id = id;
switch (state)
{
case MonitorState.InvalidArg:
Debug.LogErrorFormat("[{0}:{1}] Invalid.", id, name);
break;
case MonitorState.AccessDenied:
Debug.LogErrorFormat("[{0}:{1}] Access Denied.", id, name);
break;
case MonitorState.Unsupported:
Debug.LogErrorFormat("[{0}:{1}] Unsupported.", id, name);
break;
case MonitorState.SessionDisconnected:
Debug.LogErrorFormat("[{0}:{1}] Disconnected.", id, name);
break;
case MonitorState.NotSet:
Debug.LogErrorFormat("[{0}:{1}] Something wrong.", id, name);
break;
default:
break;
}
}
public int id
@@ -21,9 +42,14 @@ public class Monitor
get { return id < Manager.monitorCount; }
}
public MonitorState state
{
get { return Lib.GetState(id); }
}
public bool available
{
get { return Lib.IsAvailable(id); }
get { return state == MonitorState.Available; }
}
public string name
@@ -66,6 +92,26 @@ public class Monitor
get { return Lib.GetHeight(id); }
}
public int dpiX
{
get { return Lib.GetDpiX(id); }
}
public int dpiY
{
get { return Lib.GetDpiY(id); }
}
public float widthMeter
{
get { return width / dpiX * 0.0254f; }
}
public float heightMeter
{
get { return height / dpiY * 0.0254f; }
}
public MonitorRotation rotation
{
get { return Lib.GetRotation(id); }
@@ -145,12 +191,12 @@ public class Monitor
}
}
public void UpdateCursorTexture(System.IntPtr ptr)
public void GetCursorTexture(System.IntPtr ptr)
{
Lib.UpdateCursorTexture(id, ptr);
Lib.GetCursorTexture(id, ptr);
}
void CreateTexture()
public void CreateTexture()
{
if (!available) return;

View File

@@ -24,9 +24,65 @@ public class Texture : MonoBehaviour
set { monitor = Manager.monitors[Mathf.Clamp(value, 0, Manager.monitorCount - 1)]; }
}
[Header("Invert UVs")]
public bool invertX = false;
public bool invertY = false;
[Header("Clip")]
public bool useClip = false;
public Vector2 clipPos = Vector2.zero;
public Vector2 clipScale = new Vector2(0.2f, 0.2f);
public enum Bend
{
Off = 0,
Y = 1,
Z = 2,
}
public Bend bend
{
get
{
return (Bend)material.GetInt("_Bend");
}
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");
material.EnableKeyword("_BEND_Y");
material.DisableKeyword("_BEND_Z");
break;
case Bend.Z:
material.SetInt("_Bend", 2);
material.DisableKeyword("_BEND_OFF");
material.DisableKeyword("_BEND_Y");
material.EnableKeyword("_BEND_Z");
break;
}
}
}
public float radius
{
get { return material.GetFloat("_Radius"); }
set { material.SetFloat("_Radius", value); }
}
public float width
{
get { return material.GetFloat("_Width"); }
set { material.SetFloat("_Width", value); }
}
public Material material
{
get;
@@ -50,12 +106,18 @@ public class Texture : MonoBehaviour
void Update()
{
Debug.Log(monitor.available);
monitor.shouldBeUpdated = true;
UpdateMaterial();
}
void UpdateMaterial()
{
Invert();
Rotate();
Clip();
}
void Invert()
{
if (invertX) {
material.EnableKeyword("INVERT_X");
@@ -68,7 +130,10 @@ public class Texture : MonoBehaviour
} else {
material.DisableKeyword("INVERT_Y");
}
}
void Rotate()
{
switch (monitor.rotation)
{
case MonitorRotation.Identity:
@@ -95,6 +160,16 @@ public class Texture : MonoBehaviour
break;
}
}
void Clip()
{
if (useClip) {
material.EnableKeyword("USE_CLIP");
material.SetVector("_ClipPositionScale", new Vector4(clipPos.x, clipPos.y, clipScale.x, clipScale.y));
} else {
material.DisableKeyword("USE_CLIP");
}
}
}
}

View File

@@ -2,6 +2,7 @@
#define UDD_COMMON_CGINC
#include "UnityCG.cginc"
#include "./uDD_Params.cginc"
struct appdata
{
@@ -48,6 +49,13 @@ float2 uddRotateUV(float2 uv)
return uv;
}
float2 uddClipUV(float2 uv)
{
uv.x = _ClipX + uv.x * _ClipWidth;
uv.y = _ClipY + uv.y * _ClipHeight;
return uv;
}
inline void uddConvertToLinearIfNeeded(inout fixed3 rgb)
{
if (!IsGammaSpace()) {
@@ -55,27 +63,30 @@ inline void uddConvertToLinearIfNeeded(inout fixed3 rgb)
}
}
inline fixed4 uddGetScreenTexture(sampler2D tex, float2 uv)
inline fixed4 uddGetScreenTexture(float2 uv)
{
fixed4 c = tex2D(tex, uv);
fixed4 c = tex2D(_MainTex, uv);
return c;
}
inline fixed4 uddGetCursorTexture(sampler2D tex, float2 uv, fixed4 cursorPosScale)
inline fixed4 uddGetCursorTexture(float2 uv)
{
uv.x = (uv.x - cursorPosScale.x) / cursorPosScale.z;
uv.y = (uv.y - cursorPosScale.y) / cursorPosScale.w;
fixed4 c = tex2D(tex, uv);
fixed a = c.a * step(0, uv.x) * step(0, uv.y) * step(uv.x, 1) * step(uv.y, 1);
c *= step(0.01, a);
uv.x = (uv.x - _CursorX) / _CursorWidth;
uv.y = (uv.y - _CursorY) / _CursorHeight;
fixed4 c = tex2D(_CursorTex, uv);
fixed a = step(0, uv.x) * step(0, uv.y) * step(uv.x, 1) * step(uv.y, 1);
c.a *= step(0.01, a);
return c;
}
inline fixed4 uddGetScreenTextureWithCursor(sampler2D screenTex, sampler2D cursorTex, float2 uv, fixed4 cursorPosScale)
inline fixed4 uddGetScreenTextureWithCursor(float2 uv)
{
uv = uddInvertUV(uv);
fixed4 screen = uddGetScreenTexture(screenTex, uddRotateUV(uv));
fixed4 cursor = uddGetCursorTexture(cursorTex, uv, cursorPosScale);
#ifdef USE_CLIP
uv = uddClipUV(uv);
#endif
fixed4 screen = uddGetScreenTexture(uddRotateUV(uv));
fixed4 cursor = uddGetCursorTexture(uv);
fixed4 color = lerp(screen, cursor, cursor.a);
uddConvertToLinearIfNeeded(color.rgb);
return color;

View File

@@ -4,7 +4,18 @@
sampler2D _MainTex;
fixed4 _Color;
sampler2D _CursorTex;
half4 _CursorPositionScale;
#define _CursorX _CursorPositionScale.x
#define _CursorY _CursorPositionScale.y
#define _CursorWidth _CursorPositionScale.z
#define _CursorHeight _CursorPositionScale.w
half4 _ClipPositionScale;
#define _ClipX _ClipPositionScale.x
#define _ClipY _ClipPositionScale.y
#define _ClipWidth _ClipPositionScale.z
#define _ClipHeight _ClipPositionScale.w
#ifndef SURFACE_SHADER
float4 _MainTex_ST;

View File

@@ -22,19 +22,19 @@ SubShader
#pragma surface surf Standard fullforwardshadows
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
#pragma multi_compile ___ USE_BEND
#pragma multi_compile ___ USE_CLIP
#define SURFACE_SHADER
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
half _Glossiness;
half _Metallic;
void surf(Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = uddGetScreenTextureWithCursor(_MainTex, _CursorTex, IN.uv_MainTex, _CursorPositionScale) * _Color;
fixed4 c = uddGetScreenTextureWithCursor(IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;

View File

@@ -5,8 +5,9 @@ Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
_MainTex ("Texture", 2D) = "white" {}
[Toggle(USE_BEND)] _UseBend("UseBend", Float) = 0
[PowerSlider(10.0)]_Radius ("Radius", Range(3, 100)) = 10
_CursorTex ("Cursor Texture", 2D) = "white" {}
[KeywordEnum(Off, Y, Z)] _Bend("Bending", Int) = 0
[PowerSlider(10.0)]_Radius ("Radius", Range(1, 100)) = 30
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
}
@@ -20,17 +21,21 @@ Cull [_Cull]
CGINCLUDE
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
fixed _Radius;
half _Radius;
half _Width;
v2f vert(appdata v)
{
v2f o;
#ifdef USE_BEND
half a = v.vertex.x / _Radius;
v.vertex.x = _Radius * sin(a);
#if defined(_BEND_Z) || defined(_BEND_Y)
half a = _Width * v.vertex.x / _Radius;
v.vertex.x = _Radius * sin(a) / _Width;
#ifdef _BEND_Y
v.vertex.y += _Radius * (1 - cos(a));
#elif _BEND_Z
v.vertex.z += _Radius * (1 - cos(a));
#endif
#endif
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
@@ -39,7 +44,7 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
return uddGetScreenTextureWithCursor(_MainTex, _CursorTex, i.uv, _CursorPositionScale);
return uddGetScreenTextureWithCursor(i.uv);
}
ENDCG
@@ -51,9 +56,9 @@ Pass
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma shader_feature ___ USE_BEND
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
#pragma multi_compile ___ USE_CLIP
#pragma multi_compile _BEND_OFF _BEND_Y _BEND_Z
ENDCG
}

View File

@@ -21,7 +21,6 @@ Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
fixed _Mask;
@@ -35,7 +34,7 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
fixed4 tex = uddGetScreenTextureWithCursor(_MainTex, _CursorTex, i.uv, _CursorPositionScale);
fixed4 tex = uddGetScreenTextureWithCursor(i.uv);
fixed alpha = pow((tex.r + tex.g + tex.b) / 3.0, _Mask);
return fixed4(tex.rgb * _Color.rgb, alpha * _Color.a);
}
@@ -49,8 +48,9 @@ Pass
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
#pragma multi_compile ___ USE_BEND
#pragma multi_compile ___ USE_CLIP
ENDCG
}

View File

@@ -20,7 +20,6 @@ Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
v2f vert(appdata v)
{
@@ -32,7 +31,7 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
return fixed4(uddGetScreenTextureWithCursor(_MainTex, _CursorTex, i.uv, _CursorPositionScale).rgb, 1.0) * _Color;
return fixed4(uddGetScreenTextureWithCursor(i.uv).rgb, 1.0) * _Color;
}
ENDCG
@@ -44,8 +43,9 @@ Pass
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
#pragma multi_compile ___ USE_BEND
#pragma multi_compile ___ USE_CLIP
ENDCG
}

View File

@@ -9,7 +9,7 @@ const std::unique_ptr<MonitorManager>& GetMonitorManager();
enum class Message
{
None = -1,
Reinitialized = 0,
None = -1,
Reinitialized = 0,
};
void SendMessageToUnity(Message message);

View File

@@ -26,19 +26,25 @@ Cursor::~Cursor()
}
void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
{
isVisible_ = frameInfo.PointerPosition.Visible != 0;
if (frameInfo.LastMouseUpdateTime.QuadPart == 0)
{
return;
}
x_ = frameInfo.PointerPosition.Position.x;
y_ = frameInfo.PointerPosition.Position.y;
isVisible_ = frameInfo.PointerPosition.Visible != 0;
timestamp_ = frameInfo.LastMouseUpdateTime;
// TODO: see more information to check where the cursor is.
if (isVisible_)
if (isVisible_)
{
GetMonitorManager()->SetCursorMonitorId(monitor_->GetId());
}
if (GetMonitorManager()->GetCursorMonitorId() != monitor_->GetId()) {
if (frameInfo.PointerShapeBufferSize == 0)
{
return;
}
@@ -51,29 +57,35 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
}
if (apiBuffer_ == nullptr) return;
// Get information about the mouse pointer if needed
if (frameInfo.PointerShapeBufferSize != 0)
// Get mouse pointer information
UINT bufferSize;
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
frameInfo.PointerShapeBufferSize,
reinterpret_cast<void*>(apiBuffer_),
&bufferSize,
&shapeInfo_);
if (FAILED(hr))
{
UINT bufferSize;
monitor_->GetDeskDupl()->GetFramePointerShape(
frameInfo.PointerShapeBufferSize,
reinterpret_cast<void*>(apiBuffer_),
&bufferSize,
&shapeInfo_);
delete[] apiBuffer_;
apiBuffer_ = nullptr;
apiBufferSize_ = 0;
}
}
void Cursor::UpdateTexture()
{
// cursor type
const auto cursorType = shapeInfo_.Type;
const bool isMono = cursorType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
const bool isColorMask = cursorType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
const bool isMono = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
const bool isColorMask = GetType() == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
// Size
const auto w = shapeInfo_.Width;
const auto h = shapeInfo_.Height / (isMono ? 2 : 1);
const auto p = shapeInfo_.Pitch;
const auto w = GetWidth();
const auto h = GetHeight();
const auto p = GetPitch();
// Convert the buffer given by API into BGRA32
const auto bgraBufferSize = w * h * 4;
const UINT bgraBufferSize = w * h * 4;
if (bgraBufferSize > bgra32BufferSize_)
{
if (bgra32Buffer_) delete[] bgra32Buffer_;
@@ -145,16 +157,16 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
if (isMono)
{
for (UINT row = 0; row < h; ++row)
for (int row = 0; row < h; ++row)
{
BYTE mask = 0x80;
for (UINT col = 0; col < w; ++col)
for (int col = 0; col < w; ++col)
{
const int i = row * w + col;
const BYTE andMask = apiBuffer_[col / 8 + row * p] & mask;
const BYTE xorMask = apiBuffer_[col / 8 + (row + h) * p] & mask;
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0xFF000000;
const UINT xorMask32 = xorMask ? 0x00FFFFFF : 0x00000000;
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
}
@@ -164,9 +176,9 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
{
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
for (UINT row = 0; row < h; ++row)
for (int row = 0; row < h; ++row)
{
for (UINT col = 0; col < w; ++col)
for (int col = 0; col < w; ++col)
{
const int i = row * w + col;
const int j = row * p / sizeof(UINT) + col;
@@ -195,7 +207,7 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
{
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
for (UINT i = 0; i < w * h; ++i)
for (int i = 0; i < w * h; ++i)
{
output32[i] = buffer32[i];
}
@@ -205,9 +217,9 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
}
void Cursor::UpdateTexture(ID3D11Texture2D* texture)
void Cursor::GetTexture(ID3D11Texture2D* texture)
{
if (bgra32Buffer_ == nullptr) return;
if (bgra32Buffer_ == nullptr || texture == nullptr) return;
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_, shapeInfo_.Width * 4, 0);

View File

@@ -9,8 +9,9 @@ class Cursor
public:
explicit Cursor(Monitor* monitor);
~Cursor();
void Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
void UpdateTexture(ID3D11Texture2D* texture);
void UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
void UpdateTexture();
void GetTexture(ID3D11Texture2D* texture);
bool IsVisible() const;
int GetX() const;
@@ -30,4 +31,5 @@ private:
BYTE* bgra32Buffer_ = nullptr;
UINT bgra32BufferSize_ = 0;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
LARGE_INTEGER timestamp_;
};

View File

@@ -1,4 +1,5 @@
#include <d3d11.h>
#include <ShellScalingAPI.h>
#include "Common.h"
#include "Cursor.h"
#include "MonitorManager.h"
@@ -11,37 +12,44 @@ Monitor::Monitor(int id)
{
}
HRESULT Monitor::Initialize(IDXGIOutput* output)
{
output->GetDesc(&outputDesc_);
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_);
GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_);
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
const auto hr = output1->DuplicateOutput(GetDevice(), &deskDupl_);
// TODO: error check
// TODO: error check
switch (hr)
{
case S_OK:
available_ = true;
state_ = State::Available;
break;
case E_INVALIDARG:
state_ = State::InvalidArg;
break;
case E_ACCESSDENIED:
// For example, when the user presses Ctrl + Alt + Delete and the screen
// switches to admin screen, this error occurs.
// GetMonitorManager()->RequireReinitilization();
// For example, when the user presses Ctrl + Alt + Delete and the screen
// switches to admin screen, this error occurs.
state_ = State::AccessDenied;
break;
case DXGI_ERROR_UNSUPPORTED:
// If the display adapter on the computer is running under the Microsoft Hybrid system,
// this error occurs.
state_ = State::Unsupported;
break;
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
// When other application use Desktop Duplication API, this error occurs.
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
// When other application use Desktop Duplication API, this error occurs.
state_ = State::CurrentlyNotAvailable;
break;
case DXGI_ERROR_SESSION_DISCONNECTED:
break;
state_ = State::SessionDisconnected;
break;
}
return hr;
@@ -50,21 +58,19 @@ HRESULT Monitor::Initialize(IDXGIOutput* output)
Monitor::~Monitor()
{
if (deskDupl_ != nullptr)
{
deskDupl_->Release();
}
if (deskDupl_ != nullptr)
{
deskDupl_->Release();
}
}
HRESULT Monitor::Render(UINT timeout)
{
if (deskDupl_ == nullptr)
{
return 0;
}
if (unityTexture_ == nullptr) return 0;
if (deskDupl_ == nullptr)
{
return S_OK;
}
IDXGIResource* resource = nullptr;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
@@ -72,20 +78,39 @@ HRESULT Monitor::Render(UINT timeout)
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
if (FAILED(hr))
{
switch (hr)
{
case DXGI_ERROR_ACCESS_LOST:
// If any monitor setting has changed (e.g. monitor size has changed),
// it is necessary to re-initialize monitors.
state_ = State::AccessLost;
break;
case DXGI_ERROR_WAIT_TIMEOUT:
break;
case DXGI_ERROR_INVALID_CALL:
break;
case E_INVALIDARG:
break;
}
return hr;
}
ID3D11Texture2D* texture;
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
if (unityTexture_)
{
ID3D11Texture2D* texture;
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture);
context->Release();
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture);
context->Release();
cursor_->Update(frameInfo);
resource->Release();
}
cursor_->UpdateBuffer(frameInfo);
cursor_->UpdateTexture();
resource->Release();
deskDupl_->ReleaseFrame();
return S_OK;
@@ -98,9 +123,9 @@ int Monitor::GetId() const
}
bool Monitor::IsAvailable() const
MonitorState Monitor::GetState() const
{
return available_;
return state_;
}
@@ -128,9 +153,9 @@ const std::unique_ptr<Cursor>& Monitor::GetCursor()
}
void Monitor::UpdateCursorTexture(ID3D11Texture2D* texture)
void Monitor::GetCursorTexture(ID3D11Texture2D* texture)
{
cursor_->UpdateTexture(texture);
cursor_->GetTexture(texture);
}
@@ -148,31 +173,43 @@ bool Monitor::IsPrimary() const
int Monitor::GetLeft() const
{
return outputDesc_.DesktopCoordinates.left;
return outputDesc_.DesktopCoordinates.left;
}
int Monitor::GetRight() const
{
return outputDesc_.DesktopCoordinates.right;
return outputDesc_.DesktopCoordinates.right;
}
int Monitor::GetTop() const
{
return outputDesc_.DesktopCoordinates.top;
return outputDesc_.DesktopCoordinates.top;
}
int Monitor::GetBottom() const
{
return outputDesc_.DesktopCoordinates.bottom;
return outputDesc_.DesktopCoordinates.bottom;
}
int Monitor::GetRotation() const
{
return static_cast<int>(outputDesc_.Rotation);
return static_cast<int>(outputDesc_.Rotation);
}
int Monitor::GetDpiX() const
{
return static_cast<int>(dpiX_);
}
int Monitor::GetDpiY() const
{
return static_cast<int>(dpiY_);
}

View File

@@ -4,35 +4,52 @@
class Cursor;
enum class MonitorState
{
NotSet = -1,
Available = 0,
InvalidArg = 1,
AccessDenied = 2,
Unsupported = 3,
CurrentlyNotAvailable = 4,
SessionDisconnected = 5,
AccessLost = 6,
};
class Monitor
{
public:
using State = MonitorState;
explicit Monitor(int id);
~Monitor();
HRESULT Initialize(IDXGIOutput* output);
HRESULT Render(UINT timeout = 0);
void UpdateCursorTexture(ID3D11Texture2D* texture);
void GetCursorTexture(ID3D11Texture2D* texture);
public:
int GetId() const;
bool IsAvailable() const;
State GetState() const;
void SetUnityTexture(ID3D11Texture2D* texture);
ID3D11Texture2D* GetUnityTexture() const;
void GetName(char* buf, int len) const;
bool IsPrimary() const;
int GetLeft() const;
int GetRight() const;
int GetTop() const;
int GetBottom() const;
int GetLeft() const;
int GetRight() const;
int GetTop() const;
int GetBottom() const;
int GetWidth() const;
int GetHeight() const;
int GetRotation() const;
int GetRotation() const;
int GetDpiX() const;
int GetDpiY() const;
IDXGIOutputDuplication* GetDeskDupl();
const std::unique_ptr<Cursor>& GetCursor();
private:
int id_ = -1;
bool available_ = false;
UINT dpiX_ = -1, dpiY_ = -1;
State state_ = State::NotSet;
std::unique_ptr<Cursor> cursor_;
IDXGIOutputDuplication* deskDupl_ = nullptr;
ID3D11Texture2D* unityTexture_ = nullptr;

View File

@@ -59,10 +59,16 @@ void MonitorManager::Finalize()
}
void MonitorManager::RequireReinitilization()
{
isReinitializationRequired_ = true;
}
void MonitorManager::Reinitialize()
{
Initialize();
SendMessageToUnity(Message::Reinitialized);
Initialize();
SendMessageToUnity(Message::Reinitialized);
}
@@ -78,28 +84,10 @@ std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
void MonitorManager::Update()
{
if (isReinitializationRequired_)
{
Reinitialize();
isReinitializationRequired_ = false;
}
}
void MonitorManager::OnRender(int id)
{
if (auto monitor = GetMonitor(id))
if (isReinitializationRequired_)
{
if (!monitor->IsAvailable()) return;
const auto hr = monitor->Render(timeout_);
// If any monitor setting has changed (e.g. monitor size has changed),
// it is necessary to re-initialize monitors.
if (hr == DXGI_ERROR_ACCESS_LOST)
{
isReinitializationRequired_ = true;
}
Reinitialize();
isReinitializationRequired_ = false;
}
}
@@ -123,26 +111,26 @@ int MonitorManager::GetMonitorCount() const
int MonitorManager::GetTotalWidth() const
{
std::vector<int> lefts, rights;
for (const auto& monitor : monitors_)
{
lefts.push_back(monitor->GetLeft());
rights.push_back(monitor->GetRight());
}
const auto minLeft = *std::min_element(lefts.begin(), lefts.end());
const auto maxRight = *std::max_element(rights.begin(), rights.end());
return maxRight - minLeft;
std::vector<int> lefts, rights;
for (const auto& monitor : monitors_)
{
lefts.push_back(monitor->GetLeft());
rights.push_back(monitor->GetRight());
}
const auto minLeft = *std::min_element(lefts.begin(), lefts.end());
const auto maxRight = *std::max_element(rights.begin(), rights.end());
return maxRight - minLeft;
}
int MonitorManager::GetTotalHeight() const
{
std::vector<int> tops, bottoms;
for (const auto& monitor : monitors_)
{
tops.push_back(monitor->GetTop());
bottoms.push_back(monitor->GetBottom());
}
const auto minTop = *std::min_element(tops.begin(), tops.end());
const auto maxBottom = *std::max_element(bottoms.begin(), bottoms.end());
return maxBottom - minTop;
std::vector<int> tops, bottoms;
for (const auto& monitor : monitors_)
{
tops.push_back(monitor->GetTop());
bottoms.push_back(monitor->GetBottom());
}
const auto minTop = *std::min_element(tops.begin(), tops.end());
const auto maxBottom = *std::max_element(bottoms.begin(), bottoms.end());
return maxBottom - minTop;
}

View File

@@ -13,9 +13,8 @@ class MonitorManager
public:
explicit MonitorManager();
~MonitorManager();
void RequireReinitilization() { isReinitializationRequired_ = true; }
void Reinitialize();
void RequireReinitilization();
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
int GetCursorMonitorId() const { return cursorMonitorId_; }
std::shared_ptr<Monitor> GetMonitor(int id) const;
@@ -23,12 +22,10 @@ public:
private:
void Initialize();
void Finalize();
void Reinitialize();
// Setters from Unity
public:
void OnRender(int id);
void Update();
void Update();
void SetTimeout(int timeout);
int GetTimeout() const;
@@ -43,5 +40,5 @@ private:
std::vector<std::shared_ptr<Monitor>> monitors_;
std::shared_ptr<Cursor> cursor_;
int cursorMonitorId_ = -1;
bool isReinitializationRequired_ = false;
bool isReinitializationRequired_ = false;
};

View File

@@ -15,13 +15,14 @@
#include "MonitorManager.h"
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "Shcore.lib")
namespace
{
IUnityInterfaces* g_unity = nullptr;
std::unique_ptr<MonitorManager> g_manager;
std::queue<Message> g_messages;
std::queue<Message> g_messages;
}
@@ -45,7 +46,7 @@ const std::unique_ptr<MonitorManager>& GetMonitorManager()
void SendMessageToUnity(Message message)
{
g_messages.push(message);
g_messages.push(message);
}
@@ -53,33 +54,36 @@ extern "C"
{
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API InitializeUDD()
{
if (g_unity && !g_manager)
{
g_manager = std::make_unique<MonitorManager>();
}
if (g_unity && !g_manager)
{
g_manager = std::make_unique<MonitorManager>();
}
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API FinalizeUDD()
{
g_manager.reset();
g_manager.reset();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
g_unity = unityInterfaces;
InitializeUDD();
InitializeUDD();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload()
{
g_unity = nullptr;
FinalizeUDD();
g_unity = nullptr;
FinalizeUDD();
}
void UNITY_INTERFACE_API OnRenderEvent(int id)
{
if (!g_manager) return;
g_manager->OnRender(id);
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
monitor->Render(g_manager->GetTimeout());
}
}
UNITY_INTERFACE_EXPORT UnityRenderingEvent UNITY_INTERFACE_API GetRenderEventFunc()
@@ -87,58 +91,70 @@ extern "C"
return OnRenderEvent;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update()
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Reinitialize()
{
if (!g_manager) return;
g_manager->Update();
if (!g_manager) return;
return g_manager->Reinitialize();
}
UNITY_INTERFACE_EXPORT Message PopMessage()
{
if (g_messages.empty()) return Message::None;
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update()
{
if (!g_manager) return;
g_manager->Update();
}
const auto message = g_messages.front();
g_messages.pop();
return message;
}
UNITY_INTERFACE_EXPORT Message PopMessage()
{
if (g_messages.empty()) return Message::None;
const auto message = g_messages.front();
g_messages.pop();
return message;
}
UNITY_INTERFACE_EXPORT size_t UNITY_INTERFACE_API GetMonitorCount()
{
if (!g_manager) return 0;
if (!g_manager) return 0;
return g_manager->GetMonitorCount();
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorMonitorId()
{
if (!g_manager) return -1;
return g_manager->GetCursorMonitorId();
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetTotalWidth()
{
if (!g_manager) return 0;
if (!g_manager) return 0;
return g_manager->GetTotalWidth();
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetTotalHeight()
{
if (!g_manager) return 0;
if (!g_manager) return 0;
return g_manager->GetTotalHeight();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTimeout(int timeout)
{
if (!g_manager) return;
if (!g_manager) return;
g_manager->SetTimeout(timeout);
}
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsAvailable(int id)
UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id)
{
if (!g_manager) return false;
if (!g_manager) return MonitorState::NotSet;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->IsAvailable();
return monitor->GetState();
}
return false;
return MonitorState::NotSet;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
{
if (!g_manager) return;
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
monitor->GetName(buf, len);
@@ -147,7 +163,7 @@ extern "C"
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsPrimary(int id)
{
if (!g_manager) return false;
if (!g_manager) return false;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->IsPrimary();
@@ -225,6 +241,26 @@ extern "C"
return DXGI_MODE_ROTATION_UNSPECIFIED;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetDpiX(int id)
{
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetDpiX();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetDpiY(int id)
{
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetDpiY();
}
return -1;
}
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsCursorVisible(int id)
{
if (!g_manager) return false;
@@ -295,12 +331,12 @@ extern "C"
return -1;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdateCursorTexture(int id, ID3D11Texture2D* texture)
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetCursorTexture(int id, ID3D11Texture2D* texture)
{
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
monitor->UpdateCursorTexture(texture);
monitor->GetCursorTexture(texture);
}
}