Compare commits

...

11 Commits

Author SHA1 Message Date
hecomi
dc4fe44342 support rotation 90/180/270 degs. 2016-11-05 01:33:29 +09:00
hecomi
6bb9846510 remove unnecessary debug.log. 2016-11-05 00:11:54 +09:00
hecomi
90b811cd31 add function to fetch left/right/top/bottom/rotation. 2016-11-05 00:09:04 +09:00
hecomi
1d7b7e8650 add bending test. 2016-11-04 23:29:40 +09:00
hecomi
6f784860e5 make shaders simpler. 2016-11-04 22:58:19 +09:00
hecomi
690dba23cc make shader one pass. 2016-11-04 22:45:57 +09:00
hecomi
908988dcaa tweak multiple monitors example. 2016-11-04 21:37:08 +09:00
hecomi
0f72396540 rename initialize/finalize to suppress warning. 2016-11-04 21:35:34 +09:00
hecomi
8f7659d7c2 build with release mode. 2016-11-04 19:28:47 +09:00
hecomi
2e763d994d prevent screen lost after admin screen. 2016-11-04 19:11:17 +09:00
hecomi
2c61fcd470 refactoring. 2016-11-04 15:45:35 +09:00
38 changed files with 1445 additions and 837 deletions

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 281e2991d4d33984fa180845e56cd3f3
timeCreated: 1477648643
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,32 +3,51 @@
public class MultipleMonitorCreator : MonoBehaviour
{
[SerializeField] GameObject monitorPrefab;
[SerializeField] float scale = 10f;
[SerializeField] float width = 0.3f;
[SerializeField] float margin = 1f;
[SerializeField] float ratio = 0.001f;
void Start()
{
// Sort monitors in coordinate order
var monitors = uDesktopDuplication.Manager.monitors;
var n = monitors.Count;
monitors.Sort((a, b) => a.left - b.left);
// Create monitors
var n = monitors.Count;
var totalWidth = 0f;
for (int i = 0 ; i < n; ++i) {
// Create monitor obeject
var go = Instantiate(monitorPrefab);
go.name = "Monitor " + i;
// Assign monitor
var texture = go.GetComponent<uDesktopDuplication.Texture>();
texture.monitorId = i;
go.transform.localScale = new Vector3(texture.monitor.width * ratio, 1f, texture.monitor.height * ratio);
// 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);
// Set parent as this object
go.transform.SetParent(transform);
totalWidth += texture.monitor.width * ratio * scale;
// Calc actual size considering mesh size
var scaleX = go.GetComponent<MeshFilter>().sharedMesh.bounds.extents.x * 2f;
totalWidth += w * scaleX;
}
// 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 halfWidth = texture.monitor.width * ratio * scale / 2;
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;

View File

@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 4fad0d0b5018b8649ac41af2fef8dbf2
folderAsset: yes
timeCreated: 1478011152
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,81 +0,0 @@
Shader "uDesktopDuplication/Cursor"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
}
SubShader
{
Tags { "RenderType"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "Queue" = "Transparent+1" }
Cull [_Cull]
ZWrite Off
Offset -0.01, -0.01
CGINCLUDE
#include "UnityCG.cginc"
#include "../../../Shaders/uDD_Common.cginc"
half4 _PositionScale;
#define _PointerX _PositionScale.x
#define _PointerY _PositionScale.y
#define _PointerWidth _PositionScale.z
#define _PointerHeight _PositionScale.w
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
uddInvertUV(i.uv);
i.uv.x = (i.uv.x - _PointerX) / _PointerWidth;
i.uv.y = (i.uv.y - _PointerY) / _PointerHeight;
fixed4 color = tex2D(_MainTex, i.uv);
color.a *= step(0, i.uv.x) * step(0, i.uv.y) * step(i.uv.x, 1) * step(i.uv.y, 1);
clip(color.a - 0.01);
uddToLinearIfNeeded(color.rgb);
return color;
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
ENDCG
}
}
Fallback "Unlit/Texture"
}

View File

@@ -8,46 +8,23 @@ 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 pointerTexture_;
private Material cursorMaterial_;
private Texture2D currentTexture_;
private Dictionary<Vector2, Texture2D> textures_ = new Dictionary<Vector2, Texture2D>();
[SerializeField] Vector2 modelScale = Vector2.one;
private Dictionary<Vector2, Texture2D> pointerTextures_ = new Dictionary<Vector2, Texture2D>();
void OnEnable()
void Start()
{
uddTexture_ = GetComponent<Texture>();
}
void Start()
{
var clone = new GameObject(name + " Cursor");
clone.transform.SetParent(transform);
clone.transform.localPosition = Vector3.zero;
clone.transform.localRotation = Quaternion.identity;
clone.transform.localScale = Vector3.one;
var filter = clone.AddComponent<MeshFilter>();
filter.mesh = GetComponent<MeshFilter>().sharedMesh;
var renderer = clone.AddComponent<MeshRenderer>();
var shader = Shader.Find("uDesktopDuplication/Cursor");
cursorMaterial_ = new Material(shader);
renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
renderer.receiveShadows = false;
renderer.motionVectors = false;
renderer.material = cursorMaterial_;
}
void Update()
{
if (monitor.isPointerVisible) {
if (monitor.isCursorVisible) {
UpdatePosition();
UpdateTexture();
UpdateMaterial();
@@ -70,41 +47,24 @@ public class Cursor : MonoBehaviour
if (w == 0 || h == 0) return;
var scale = new Vector2(w, h);
if (!pointerTextures_.ContainsKey(scale)) {
if (!textures_.ContainsKey(scale)) {
var texture = new Texture2D(w, h, TextureFormat.BGRA32, false);
texture.wrapMode = TextureWrapMode.Clamp;
pointerTextures_.Add(scale, texture);
textures_.Add(scale, texture);
}
var pointerTexture = pointerTextures_[scale];
monitor.UpdatePointerTexture(pointerTexture.GetNativeTexturePtr());
cursorMaterial_.SetTexture("_MainTex", pointerTexture);
var pointerTexture = textures_[scale];
monitor.UpdateCursorTexture(pointerTexture.GetNativeTexturePtr());
uddTexture_.material.SetTexture("_CursorTex", pointerTexture);
}
void UpdateMaterial()
{
if (uddTexture_.invertX) {
cursorMaterial_.EnableKeyword("INVERT_X");
} else {
cursorMaterial_.DisableKeyword("INVERT_X");
}
if (uddTexture_.invertY) {
cursorMaterial_.EnableKeyword("INVERT_Y");
} else {
cursorMaterial_.DisableKeyword("INVERT_Y");
}
if (monitor.isVertical) {
cursorMaterial_.EnableKeyword("VERTICAL");
} else {
cursorMaterial_.DisableKeyword("VERTICAL");
}
var x = (float)monitor.pointerX / monitor.width;
var y = (float)monitor.pointerY / monitor.height;
var w = (float)monitor.pointerShapeWidth / monitor.width;
var h = (float)monitor.pointerShapeHeight / monitor.height;
cursorMaterial_.SetVector("_PositionScale", new Vector4(x, y, w, h));
uddTexture_.material.SetVector("_CursorPositionScale", new Vector4(x, y, w, h));
}
}

View File

@@ -5,51 +5,86 @@ using System.Runtime.InteropServices;
namespace uDesktopDuplication
{
public enum PointerShapeType
public enum Message
{
None = -1,
Reinitialized = 0,
}
public enum CursorShapeType
{
MonoChrome = 1,
Color = 2,
MaskedColor = 4,
}
public enum MonitorRotation
{
Unspecified = 0,
Identity = 1,
Rotate90 = 2,
Rotate180 = 3,
Rotate270 = 4
}
public static class Lib
{
public delegate void MessageHandler(Message message);
[DllImport("uDesktopDuplication")]
public static extern void InitializeUDD();
[DllImport("uDesktopDuplication")]
public static extern void FinalizeUDD();
[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 GetTotalWidth();
[DllImport("uDesktopDuplication")]
public static extern int GetTotalHeight();
[DllImport("uDesktopDuplication")]
public static extern void SetTimeout(int timeout);
[DllImport("uDesktopDuplication")]
public static extern IntPtr GetRenderEventFunc();
[DllImport("uDesktopDuplication")]
public static extern void GetName(int id, StringBuilder buf, int len);
[DllImport("uDesktopDuplication")]
public static extern int GetLeft(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetRight(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetTop(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetBottom(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetWidth(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetHeight(int id);
[DllImport("uDesktopDuplication")]
public static extern MonitorRotation GetRotation(int id);
[DllImport("uDesktopDuplication")]
public static extern bool IsPrimary(int id);
[DllImport("uDesktopDuplication")]
public static extern bool IsPointerVisible(int id);
public static extern bool IsCursorVisible(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetPointerX(int id);
public static extern int GetCursorX(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetPointerY(int id);
public static extern int GetCursorY(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetPointerShapeWidth(int id);
public static extern int GetCursorShapeWidth(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetPointerShapeHeight(int id);
public static extern int GetCursorShapeHeight(int id);
[DllImport("uDesktopDuplication")]
public static extern int GetPointerShapePitch(int id);
public static extern int GetCursorShapePitch(int id);
[DllImport("uDesktopDuplication")]
public static extern PointerShapeType GetPointerShapeType(int id);
public static extern CursorShapeType GetCursorShapeType(int id);
[DllImport("uDesktopDuplication")]
public static extern void UpdatePointerTexture(int id, System.IntPtr ptr);
public static extern void UpdateCursorTexture(int id, System.IntPtr ptr);
[DllImport("uDesktopDuplication")]
public static extern int SetTexturePtr(int id, IntPtr ptr);
[DllImport("uDesktopDuplication")]
public static extern int GetErrorCode();
[DllImport("uDesktopDuplication")]
public static extern void GetErrorMessage(StringBuilder buf, int len);
public static string GetName(int id)
{
@@ -57,13 +92,6 @@ public static class Lib
GetName(id, buf, buf.Capacity);
return buf.ToString();
}
public static string GetErrorMessage()
{
var buf = new StringBuilder(64);
GetErrorMessage(buf, buf.Capacity);
return buf.ToString();
}
}
}

View File

@@ -26,7 +26,7 @@ public class Manager : MonoBehaviour
static public int monitorCount
{
get { return instance.monitors_.Count; }
get { return Lib.GetMonitorCount(); }
}
static public Monitor primary
@@ -40,23 +40,25 @@ public class Manager : MonoBehaviour
[SerializeField, Tooltip("Set Desktop Duplication API timeout (milliseconds).")]
int timeout = 0;
[SerializeField, Tooltip("Output logs given by the plugin.")]
bool outputDebugLog = false;
private Coroutine renderCoroutine_ = null;
void Awake()
{
Lib.InitializeUDD();
if (instance_ != null) return;
instance_ = this;
for (int i = 0; i < Lib.GetMonitorCount(); ++i) {
monitors.Add(new Monitor(i));
}
CreateMonitors();
Lib.SetTimeout(timeout);
}
void OnApplicationQuit()
{
Lib.FinalizeUDD();
}
void OnEnable()
{
renderCoroutine_ = StartCoroutine(OnRender());
@@ -70,6 +72,24 @@ public class Manager : MonoBehaviour
}
}
void Update()
{
Lib.Update();
var message = Lib.PopMessage();
while (message != Message.None) {
switch (message) {
case Message.Reinitialized:
Debug.Log("Reinitialize");
Reinitialize();
break;
default:
break;
}
message = Lib.PopMessage();
}
}
IEnumerator OnRender()
{
for (;;) {
@@ -81,10 +101,23 @@ public class Manager : MonoBehaviour
}
monitor.shouldBeUpdated = false;
}
if (outputDebugLog && Lib.GetErrorCode() != 0)
{
Debug.Log(Lib.GetErrorMessage());
}
}
void CreateMonitors()
{
for (int i = 0; i < monitorCount; ++i) {
monitors.Add(new Monitor(i));
}
}
void Reinitialize()
{
for (int i = 0; i < monitorCount; ++i) {
if (i == monitors.Count) {
monitors.Add(new Monitor(i));
}
monitors[i].Reinitialize();
}
}
}

View File

@@ -16,6 +16,11 @@ public class Monitor
private set;
}
public bool exists
{
get { return id < Manager.monitorCount; }
}
public string name
{
get { return Lib.GetName(id); }
@@ -26,6 +31,26 @@ public class Monitor
get { return Lib.IsPrimary(id); }
}
public int left
{
get { return Lib.GetLeft(id); }
}
public int right
{
get { return Lib.GetRight(id); }
}
public int top
{
get { return Lib.GetTop(id); }
}
public int bottom
{
get { return Lib.GetBottom(id); }
}
public int width
{
get { return Lib.GetWidth(id); }
@@ -36,6 +61,11 @@ public class Monitor
get { return Lib.GetHeight(id); }
}
public MonitorRotation rotation
{
get { return Lib.GetRotation(id); }
}
public float aspect
{
get { return (float)width / height; }
@@ -51,34 +81,34 @@ public class Monitor
get { return height > width; }
}
public bool isPointerVisible
public bool isCursorVisible
{
get { return Lib.IsPointerVisible(id); }
get { return Lib.IsCursorVisible(id); }
}
public int pointerX
{
get { return Lib.GetPointerX(id); }
get { return Lib.GetCursorX(id); }
}
public int pointerY
{
get { return Lib.GetPointerY(id); }
get { return Lib.GetCursorY(id); }
}
public int pointerShapeWidth
{
get { return Lib.GetPointerShapeWidth(id); }
get { return Lib.GetCursorShapeWidth(id); }
}
public int pointerShapeHeight
{
get { return Lib.GetPointerShapeHeight(id); }
get { return Lib.GetCursorShapeHeight(id); }
}
public PointerShapeType pointerShapeType
public CursorShapeType pointerShapeType
{
get { return Lib.GetPointerShapeType(id); }
get { return Lib.GetCursorShapeType(id); }
}
public bool shouldBeUpdated
@@ -93,10 +123,7 @@ public class Monitor
get
{
if (texture_ == null) {
var w = isHorizontal ? width : height;
var h = isHorizontal ? height : width;
texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false);
Lib.SetTexturePtr(id, texture_.GetNativeTexturePtr());
CreateTexture();
}
return texture_;
}
@@ -104,12 +131,38 @@ public class Monitor
public void Render()
{
Lib.SetTexturePtr(id, texture_.GetNativeTexturePtr());
GL.IssuePluginEvent(Lib.GetRenderEventFunc(), id);
}
public void UpdatePointerTexture(System.IntPtr ptr)
public void UpdateCursorTexture(System.IntPtr ptr)
{
Lib.UpdatePointerTexture(id, ptr);
Lib.UpdateCursorTexture(id, ptr);
}
void CreateTexture()
{
var w = isHorizontal ? width : height;
var h = isHorizontal ? height : width;
bool shouldCreate = true;
if (texture_) {
if (texture_.width != w || texture_.height != h) {
if (texture_) Object.DestroyImmediate(texture_);
shouldCreate = true;
} else {
shouldCreate = false;
}
}
if (shouldCreate) {
texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false);
}
}
public void Reinitialize()
{
CreateTexture();
}
}

View File

@@ -13,8 +13,8 @@ public class Texture : MonoBehaviour
set
{
monitor_ = value;
material_ = GetComponent<Renderer>().material;
material_.mainTexture = monitor_.texture;
material = GetComponent<Renderer>().material;
material.mainTexture = monitor_.texture;
}
}
@@ -27,7 +27,19 @@ public class Texture : MonoBehaviour
public bool invertX = false;
public bool invertY = false;
private Material material_;
public Material material
{
get;
private set;
}
void Awake()
{
if (!GetComponent<Cursor>())
{
gameObject.AddComponent<Cursor>();
}
}
void OnEnable()
{
@@ -45,21 +57,41 @@ public class Texture : MonoBehaviour
void UpdateMaterial()
{
if (invertX) {
material_.EnableKeyword("INVERT_X");
material.EnableKeyword("INVERT_X");
} else {
material_.DisableKeyword("INVERT_X");
material.DisableKeyword("INVERT_X");
}
if (invertY) {
material_.EnableKeyword("INVERT_Y");
material.EnableKeyword("INVERT_Y");
} else {
material_.DisableKeyword("INVERT_Y");
material.DisableKeyword("INVERT_Y");
}
if (monitor.isVertical) {
material_.EnableKeyword("VERTICAL");
} else {
material_.DisableKeyword("VERTICAL");
switch (monitor.rotation)
{
case MonitorRotation.Identity:
material.DisableKeyword("ROTATE90");
material.DisableKeyword("ROTATE180");
material.DisableKeyword("ROTATE270");
break;
case MonitorRotation.Rotate90:
material.EnableKeyword("ROTATE90");
material.DisableKeyword("ROTATE180");
material.DisableKeyword("ROTATE270");
break;
case MonitorRotation.Rotate180:
material.DisableKeyword("ROTATE90");
material.EnableKeyword("ROTATE180");
material.DisableKeyword("ROTATE270");
break;
case MonitorRotation.Rotate270:
material.DisableKeyword("ROTATE90");
material.DisableKeyword("ROTATE180");
material.EnableKeyword("ROTATE270");
break;
default:
break;
}
}
}

View File

@@ -3,34 +3,82 @@
#include "UnityCG.cginc"
inline void uddInvertUV(inout float2 uv)
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
struct Input
{
float2 uv_MainTex;
};
float2 uddInvertUV(float2 uv)
{
#ifdef INVERT_X
uv.x = 1.0 - uv.x;
uv.x = 1.0 - uv.x;
#endif
#ifdef INVERT_Y
uv.y = 1.0 - uv.y;
uv.y = 1.0 - uv.y;
#endif
#ifdef VERTICAL
return uv;
}
float2 uddRotateUV(float2 uv)
{
#ifdef ROTATE90
float2 tmp = uv;
uv.x = tmp.y;
uv.y = 1.0 - tmp.x;
#elif ROTATE180
uv.x = 1.0 - uv.x;
uv.y = 1.0 - uv.y;
#elif ROTATE270
float2 tmp = uv;
uv.x = 1.0 - tmp.y;
uv.y = tmp.x;
#endif
return uv;
}
inline void uddToLinearIfNeeded(inout fixed3 rgb)
inline void uddConvertToLinearIfNeeded(inout fixed3 rgb)
{
if (!IsGammaSpace()) {
rgb = GammaToLinearSpace(rgb);
}
}
inline fixed4 uddGetTexture(sampler2D tex, float2 uv)
inline fixed4 uddGetScreenTexture(sampler2D tex, float2 uv)
{
uddInvertUV(uv);
fixed4 c = tex2D(tex, uv);
uddToLinearIfNeeded(c.rgb);
return c;
}
inline fixed4 uddGetCursorTexture(sampler2D tex, float2 uv, fixed4 cursorPosScale)
{
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);
return c;
}
inline fixed4 uddGetScreenTextureWithCursor(sampler2D screenTex, sampler2D cursorTex, float2 uv, fixed4 cursorPosScale)
{
uv = uddInvertUV(uv);
fixed4 screen = uddGetScreenTexture(screenTex, uddRotateUV(uv));
fixed4 cursor = uddGetCursorTexture(cursorTex, uv, cursorPosScale);
fixed4 color = lerp(screen, cursor, cursor.a);
uddConvertToLinearIfNeeded(color.rgb);
return color;
}
#endif

View File

@@ -0,0 +1,13 @@
#ifndef UDD_PARAMS_CGINC
#define UDD_PARAMS_CGINC
sampler2D _MainTex;
fixed4 _Color;
sampler2D _CursorTex;
half4 _CursorPositionScale;
#ifndef SURFACE_SHADER
float4 _MainTex_ST;
#endif
#endif

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: d224cadaa1bfa2d46a6224ce2a1443c7
timeCreated: 1477847636
guid: 54044418ab4785c4a84dd4be507db6c2
timeCreated: 1478266678
licenseType: Pro
ShaderImporter:
defaultTextures: []

View File

@@ -23,23 +23,18 @@ SubShader
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
#define SURFACE_SHADER
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
half _Glossiness;
half _Metallic;
void surf(Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = uddGetTexture(_MainTex, IN.uv_MainTex) * _Color;
fixed4 c = uddGetScreenTextureWithCursor(_MainTex, _CursorTex, IN.uv_MainTex, _CursorPositionScale) * _Color;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;

View File

@@ -5,6 +5,8 @@ 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
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
}
@@ -17,28 +19,19 @@ Cull [_Cull]
CGINCLUDE
#include "UnityCG.cginc"
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
fixed _Radius;
v2f vert(appdata v)
{
v2f o;
#ifdef USE_BEND
half a = v.vertex.x / _Radius;
v.vertex.x = _Radius * sin(a);
v.vertex.y += _Radius * (1 - cos(a));
#endif
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
@@ -46,7 +39,7 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
return uddGetTexture(_MainTex, i.uv) * _Color;
return uddGetScreenTextureWithCursor(_MainTex, _CursorTex, i.uv, _CursorPositionScale);
}
ENDCG
@@ -59,6 +52,8 @@ Pass
#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
ENDCG
}
@@ -66,4 +61,4 @@ Pass
Fallback "Unlit/Texture"
}
}

View File

@@ -20,24 +20,9 @@ Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "UnityCG.cginc"
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
fixed _Mask;
v2f vert(appdata v)
@@ -50,22 +35,23 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
fixed4 tex = uddGetTexture(_MainTex, i.uv);
fixed alpha = pow((tex.r + tex.g + tex.b) / 3.0, _Mask);
return fixed4(tex.rgb * _Color.rgb, alpha);
fixed4 tex = uddGetScreenTextureWithCursor(_MainTex, _CursorTex, i.uv, _CursorPositionScale);
fixed alpha = pow((tex.r + tex.g + tex.b) / 3.0, _Mask);
return fixed4(tex.rgb * _Color.rgb, alpha * _Color.a);
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
ENDCG
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
ENDCG
}
}

View File

@@ -19,24 +19,8 @@ Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "UnityCG.cginc"
#include "./uDD_Common.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
#include "./uDD_Params.cginc"
v2f vert(appdata v)
{
@@ -48,7 +32,7 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
return fixed4(uddGetTexture(_MainTex, i.uv).rgb, 1.0) * _Color;
return fixed4(uddGetScreenTextureWithCursor(_MainTex, _CursorTex, i.uv, _CursorPositionScale).rgb, 1.0) * _Color;
}
ENDCG
@@ -61,6 +45,7 @@ Pass
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
ENDCG
}

View File

@@ -0,0 +1,15 @@
#include <memory>
#include "IUnityInterface.h"
class MonitorManager;
IUnityInterfaces* GetUnity();
ID3D11Device* GetDevice();
const std::unique_ptr<MonitorManager>& GetMonitorManager();
enum class Message
{
None = -1,
Reinitialized = 0,
};
void SendMessageToUnity(Message message);

View File

@@ -0,0 +1,259 @@
#include <d3d11.h>
#include "Common.h"
#include "MonitorManager.h"
#include "Monitor.h"
#include "Cursor.h"
Cursor::Cursor(Monitor* monitor)
: monitor_(monitor)
{
}
Cursor::~Cursor()
{
if (apiBuffer_ != nullptr)
{
delete[] apiBuffer_;
apiBuffer_ = nullptr;
}
if (bgra32Buffer_ != nullptr)
{
delete[] bgra32Buffer_;
bgra32Buffer_ = nullptr;
}
}
void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
{
isVisible_ = frameInfo.PointerPosition.Visible != 0;
x_ = frameInfo.PointerPosition.Position.x;
y_ = frameInfo.PointerPosition.Position.y;
// TODO: see more information to check where the cursor is.
if (isVisible_)
{
GetMonitorManager()->SetCursorMonitorId(monitor_->GetId());
}
if (GetMonitorManager()->GetCursorMonitorId() != monitor_->GetId()) {
return;
}
// Increase the buffer size if needed
if (frameInfo.PointerShapeBufferSize > apiBufferSize_)
{
if (apiBuffer_) delete[] apiBuffer_;
apiBuffer_ = new BYTE[frameInfo.PointerShapeBufferSize];
apiBufferSize_ = frameInfo.PointerShapeBufferSize;
}
if (apiBuffer_ == nullptr) return;
// Get information about the mouse pointer if needed
if (frameInfo.PointerShapeBufferSize != 0)
{
UINT bufferSize;
monitor_->GetDeskDupl()->GetFramePointerShape(
frameInfo.PointerShapeBufferSize,
reinterpret_cast<void*>(apiBuffer_),
&bufferSize,
&shapeInfo_);
}
// 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;
// Size
const auto w = shapeInfo_.Width;
const auto h = shapeInfo_.Height / (isMono ? 2 : 1);
const auto p = shapeInfo_.Pitch;
// Convert the buffer given by API into BGRA32
const auto bgraBufferSize = w * h * 4;
if (bgraBufferSize > bgra32BufferSize_)
{
if (bgra32Buffer_) delete[] bgra32Buffer_;
bgra32Buffer_ = new BYTE[bgraBufferSize];
bgra32BufferSize_ = bgraBufferSize;
}
if (bgra32Buffer_ == nullptr) return;
// If masked, copy the desktop image and merge it with masked image.
if (isMono || isColorMask)
{
HRESULT hr;
D3D11_TEXTURE2D_DESC desc;
desc.Width = w;
desc.Height = h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
ID3D11Texture2D* texture = nullptr;
hr = GetDevice()->CreateTexture2D(&desc, nullptr, &texture);
if (FAILED(hr))
{
return;
}
D3D11_BOX box;
box.front = 0;
box.back = 1;
box.left = x_;
box.top = y_;
box.right = x_ + w;
box.bottom = y_ + h;
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
context->Release();
IDXGISurface* surface = nullptr;
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
texture->Release();
if (FAILED(hr))
{
return;
}
DXGI_MAPPED_RECT mappedSurface;
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
if (FAILED(hr))
{
surface->Release();
return;
}
// Finally, get the texture behind the mouse cursor.
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
// Access RGBA values at the same time
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
if (isMono)
{
for (UINT row = 0; row < h; ++row)
{
BYTE mask = 0x80;
for (UINT 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;
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
}
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
{
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
for (UINT row = 0; row < h; ++row)
{
for (UINT col = 0; col < w; ++col)
{
const int i = row * w + col;
const int j = row * p / sizeof(UINT) + col;
UINT mask = 0xFF000000 & buffer32[j];
if (mask)
{
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
}
else
{
output32[i] = buffer32[j] | 0xFF000000;
}
}
}
}
hr = surface->Unmap();
surface->Release();
if (FAILED(hr))
{
return;
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
{
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
for (UINT i = 0; i < w * h; ++i)
{
output32[i] = buffer32[i];
}
}
return;
}
void Cursor::UpdateTexture(ID3D11Texture2D* texture)
{
if (bgra32Buffer_ == nullptr) return;
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_, shapeInfo_.Width * 4, 0);
context->Release();
}
bool Cursor::IsVisible() const
{
return isVisible_;
}
int Cursor::GetX() const
{
return x_;
}
int Cursor::GetY() const
{
return y_;
}
int Cursor::GetWidth() const
{
return shapeInfo_.Width;
}
int Cursor::GetHeight() const
{
return (shapeInfo_.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) ?
shapeInfo_.Height / 2 :
shapeInfo_.Height;
}
int Cursor::GetPitch() const
{
return shapeInfo_.Pitch;
}
int Cursor::GetType() const
{
return shapeInfo_.Type;
}

View File

@@ -0,0 +1,33 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <memory>
class Monitor;
class Cursor
{
public:
explicit Cursor(Monitor* monitor);
~Cursor();
void Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo);
void UpdateTexture(ID3D11Texture2D* texture);
bool IsVisible() const;
int GetX() const;
int GetY() const;
int GetWidth() const;
int GetHeight() const;
int GetPitch() const;
int GetType() const;
private:
Monitor* monitor_;
bool isVisible_ = false;
int x_ = -1;
int y_ = -1;
BYTE* apiBuffer_ = nullptr;
UINT apiBufferSize_ = 0;
BYTE* bgra32Buffer_ = nullptr;
UINT bgra32BufferSize_ = 0;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
};

View File

@@ -1,424 +0,0 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <vector>
#include <string>
#include "IUnityInterface.h"
#include "IUnityGraphicsD3D11.h"
#include "Duplication.h"
Duplication::Duplication(IUnityInterfaces* unity)
: unity_(unity)
, device_(unity->Get<IUnityGraphicsD3D11>()->GetDevice())
{
Initialize();
}
Duplication::~Duplication()
{
Finalize();
unity_ = nullptr;
}
void Duplication::Initialize()
{
Finalize();
// Get factory
IDXGIFactory1* factory;
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
// Check all display adapters
int id = 0;
IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
// Search the main monitor from all outputs
IDXGIOutput* output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{
Monitor monitor;
monitor.id = id++;
output->GetDesc(&monitor.outputDesc);
monitor.monitorInfo.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(monitor.outputDesc.Monitor, &monitor.monitorInfo);
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
output1->DuplicateOutput(device_, &monitor.deskDupl);
output->Release();
monitors_.push_back(monitor);
}
adapter->Release();
}
factory->Release();
}
void Duplication::Finalize()
{
// Release all duplicaitons
for (auto& monitor : monitors_)
{
monitor.deskDupl->Release();
}
monitors_.clear();
}
bool Duplication::IsValidId(int id) const
{
return id >= 0 && id < monitors_.size();
}
void Duplication::OnRender(int id)
{
errorCode_ = 0;
errorMessage_ = "";
if (!IsValidId(id)) return;
auto& monitor = monitors_[id];
if (monitor.deskDupl == nullptr || monitor.texture == nullptr) return;
IDXGIResource* resource = nullptr;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
errorCode_ = monitor.deskDupl->AcquireNextFrame(timeout_, &frameInfo, &resource);
if (FAILED(errorCode_))
{
if (errorCode_ == DXGI_ERROR_ACCESS_LOST)
{
Initialize();
errorMessage_ = "[IDXGIOutputDuplication::AcquireNextFrame()] Access lost.";
}
else
{
errorMessage_ = "[IDXGIOutputDuplication::AcquireNextFrame()] Maybe timeout.";
}
return;
}
ID3D11Texture2D* texture;
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
ID3D11DeviceContext* context;
device_->GetImmediateContext(&context);
context->CopyResource(monitor.texture, texture);
if (!UpdateMouse(frameInfo, monitor))
{
errorCode_ = -999;
errorMessage_ = "[UpdateMouse()] failed.";
}
resource->Release();
monitor.deskDupl->ReleaseFrame();
}
bool Duplication::UpdateMouse(const DXGI_OUTDUPL_FRAME_INFO& frameInfo, Monitor& monitor)
{
auto& pointer = monitor.pointer;
pointer.isVisible = frameInfo.PointerPosition.Visible != 0;
pointer.x = frameInfo.PointerPosition.Position.x;
pointer.y = frameInfo.PointerPosition.Position.y;
// Pointer type
const auto pointerType = pointer.shapeInfo.Type;
const bool isMono = pointerType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME;
const bool isColorMask = pointerType == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR;
if (pointer.isVisible)
{
mouseMonitor_ = monitor.id;
}
if (mouseMonitor_ != monitor.id) {
return true;
}
// Increase the buffer size if needed
if (frameInfo.PointerShapeBufferSize > pointer.apiBufferSize)
{
if (pointer.apiBuffer) delete[] pointer.apiBuffer;
pointer.apiBuffer = new BYTE[frameInfo.PointerShapeBufferSize];
pointer.apiBufferSize = frameInfo.PointerShapeBufferSize;
}
if (!pointer.apiBuffer) return true;
// Get information about the mouse pointer if needed
if (frameInfo.PointerShapeBufferSize != 0)
{
UINT bufferSize;
monitor.deskDupl->GetFramePointerShape(
frameInfo.PointerShapeBufferSize,
reinterpret_cast<void*>(pointer.apiBuffer),
&bufferSize,
&pointer.shapeInfo);
}
// Size
const auto w = pointer.shapeInfo.Width;
const auto h = pointer.shapeInfo.Height / (isMono ? 2 : 1);
const auto p = pointer.shapeInfo.Pitch;
// Convert the buffer given by API into BGRA32
const auto bgraBufferSize = w * h * 4;
if (bgraBufferSize > pointer.bgra32BufferSize)
{
if (pointer.bgra32Buffer) delete[] pointer.bgra32Buffer;
pointer.bgra32Buffer = new BYTE[bgraBufferSize];
pointer.bgra32BufferSize = bgraBufferSize;
}
if (!pointer.bgra32Buffer) return true;
// If masked, copy the desktop image and merge it with masked image.
if (isMono || isColorMask)
{
HRESULT hr;
D3D11_TEXTURE2D_DESC desc;
desc.Width = w;
desc.Height = h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
ID3D11DeviceContext* context;
device_->GetImmediateContext(&context);
ID3D11Texture2D* texture = nullptr;
hr = device_->CreateTexture2D(&desc, nullptr, &texture);
if (FAILED(hr))
{
return false;
}
D3D11_BOX box;
box.front = 0;
box.back = 1;
box.left = pointer.x;
box.top = pointer.y;
box.right = pointer.x + w;
box.bottom = pointer.y + h;
context->CopySubresourceRegion(texture, 0, 0, 0, 0, monitor.texture, 0, &box);
IDXGISurface* surface = nullptr;
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
texture->Release();
if (FAILED(hr))
{
return false;
}
DXGI_MAPPED_RECT mappedSurface;
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
if (FAILED(hr))
{
surface->Release();
return false;
}
// Finally, get the texture behind the mouse pointer.
const auto desktop32 = reinterpret_cast<UINT*>(mappedSurface.pBits);
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
// Access RGBA values at the same time
auto output32 = reinterpret_cast<UINT*>(pointer.bgra32Buffer);
if (isMono)
{
for (UINT row = 0; row < h; ++row)
{
BYTE mask = 0x80;
for (UINT col = 0; col < w; ++col)
{
const int i = row * w + col;
const BYTE andMask = pointer.apiBuffer[col / 8 + row * p] & mask;
const BYTE xorMask = pointer.apiBuffer[col / 8 + (row + h) * p] & mask;
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0xFF000000;
const UINT xorMask32 = xorMask ? 0x00FFFFFF : 0x00000000;
output32[i] = (desktop32[row * desktopPitch + col] & andMask32) ^ xorMask32;
mask = (mask == 0x01) ? 0x80 : (mask >> 1);
}
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
{
const auto buffer32 = reinterpret_cast<UINT*>(pointer.apiBuffer);
for (UINT row = 0; row < h; ++row)
{
for (UINT col = 0; col < w; ++col)
{
const int i = row * w + col;
const int j = row * p / sizeof(UINT) + col;
UINT mask = 0xFF000000 & buffer32[j];
if (mask)
{
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
}
else
{
output32[i] = buffer32[j] | 0xFF000000;
}
}
}
}
hr = surface->Unmap();
surface->Release();
if (FAILED(hr))
{
return false;
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR
{
auto output32 = reinterpret_cast<UINT*>(pointer.bgra32Buffer);
const auto buffer32 = reinterpret_cast<UINT*>(pointer.apiBuffer);
for (UINT i = 0; i < w * h; ++i)
{
output32[i] = buffer32[i];
}
}
return true;
}
void Duplication::UpdatePointerTexture(int id, ID3D11Texture2D* ptr)
{
if (!IsValidId(id)) return;
const auto& pointer = monitors_[id].pointer;
if (!pointer.bgra32Buffer) return;
ID3D11DeviceContext* context;
device_->GetImmediateContext(&context);
context->UpdateSubresource(ptr, 0, nullptr, pointer.bgra32Buffer, pointer.shapeInfo.Width * 4, 0);
}
void Duplication::SetTimeout(int timeout)
{
timeout_ = timeout;
}
void Duplication::SetTexturePtr(int id, void* texture)
{
if (!IsValidId(id)) return;
monitors_[id].texture = reinterpret_cast<ID3D11Texture2D*>(texture);
}
int Duplication::GetMonitorCount() const
{
return static_cast<int>(monitors_.size());
}
void Duplication::GetName(int id, char* buf, int len) const
{
if (!IsValidId(id)) return;
strcpy_s(buf, len, monitors_[id].monitorInfo.szDevice);
}
bool Duplication::IsPrimary(int id) const
{
if (!IsValidId(id)) return false;
return monitors_[id].monitorInfo.dwFlags == MONITORINFOF_PRIMARY;
}
int Duplication::GetWidth(int id) const
{
if (!IsValidId(id)) return -1;
const auto rect = monitors_[id].monitorInfo.rcMonitor;
return rect.right - rect.left;
}
int Duplication::GetHeight(int id) const
{
if (!IsValidId(id)) return -1;
const auto rect = monitors_[id].monitorInfo.rcMonitor;
return rect.bottom - rect.top;
}
int Duplication::IsPointerVisible(int id) const
{
if (!IsValidId(id)) return false;
return monitors_[id].pointer.isVisible;
}
int Duplication::GetPointerX(int id) const
{
if (!IsValidId(id)) return -1;
return monitors_[id].pointer.x;
}
int Duplication::GetPointerY(int id) const
{
if (!IsValidId(id)) return -1;
return monitors_[id].pointer.y;
}
int Duplication::GetPointerShapeWidth(int id) const
{
if (!IsValidId(id)) return -1;
return monitors_[id].pointer.shapeInfo.Width;
}
int Duplication::GetPointerShapeHeight(int id) const
{
if (!IsValidId(id)) return -1;
const auto& info = monitors_[id].pointer.shapeInfo;
return (info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) ? info.Height / 2 : info.Height;
}
int Duplication::GetPointerShapePitch(int id) const
{
if (!IsValidId(id)) return -1;
return monitors_[id].pointer.shapeInfo.Pitch;
}
int Duplication::GetPointerShapeType(int id) const
{
if (!IsValidId(id)) return -1;
return monitors_[id].pointer.shapeInfo.Type;
}
int Duplication::GetErrorCode() const
{
return errorCode_;
}
void Duplication::GetErrorMessage(char* buf, int len) const
{
strcpy_s(buf, len, errorMessage_.c_str());
}

View File

@@ -1,72 +0,0 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <vector>
#include <string>
struct IUnityInterfaces;
struct Pointer
{
bool isVisible = false;
int x = -1;
int y = -1;
BYTE* apiBuffer = nullptr;
UINT apiBufferSize = 0;
BYTE* bgra32Buffer = nullptr;
UINT bgra32BufferSize = 0;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
};
struct Monitor
{
int id = -1;
IDXGIOutputDuplication* deskDupl = nullptr;
ID3D11Texture2D* texture = nullptr;
DXGI_OUTPUT_DESC outputDesc;
MONITORINFOEX monitorInfo;
Pointer pointer;
};
class Duplication
{
public:
explicit Duplication(IUnityInterfaces* unity);
~Duplication();
void OnRender(int id);
public:
void UpdatePointerTexture(int id, ID3D11Texture2D* ptr);
void SetTimeout(int timeout);
void SetTexturePtr(int id, void* texture);
public:
int GetMonitorCount() const;
void GetName(int id, char* buf, int len) const;
bool IsPrimary(int id) const;
int GetWidth(int id) const;
int GetHeight(int id) const;
int IsPointerVisible(int id) const;
int GetPointerX(int id) const;
int GetPointerY(int id) const;
int GetPointerShapeWidth(int id) const;
int GetPointerShapeHeight(int id) const;
int GetPointerShapePitch(int id) const;
int GetPointerShapeType(int id) const;
int GetErrorCode() const;
void GetErrorMessage(char* buf, int len) const;
private:
void Initialize();
void Finalize();
bool UpdateMouse(const DXGI_OUTDUPL_FRAME_INFO& frameInfo, Monitor& monitor);
bool IsValidId(int id) const;
IUnityInterfaces* unity_ = nullptr;
ID3D11Device* device_ = nullptr;
int mouseMonitor_ = 0;
int timeout_ = 10;
HRESULT errorCode_ = 0;
std::string errorMessage_ = "";
std::vector<Monitor> monitors_;
};

View File

@@ -0,0 +1,185 @@
#include <d3d11.h>
#include "Common.h"
#include "Cursor.h"
#include "MonitorManager.h"
#include "Monitor.h"
Monitor::Monitor(int id, IDXGIOutput* output)
: id_(id)
{
output->GetDesc(&outputDesc_);
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_);
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
const auto hr = output1->DuplicateOutput(GetDevice(), &deskDupl_);
auto error = 0;
// TODO: error check
switch (hr)
{
case S_OK:
break;
case E_INVALIDARG:
error = 1;
break;
case E_ACCESSDENIED:
error = 2;
// For example, when the user presses Ctrl + Alt + Delete and the screen
// switches to admin screen, this error occurs.
break;
case DXGI_ERROR_UNSUPPORTED:
error = 3;
break;
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
error = 4;
// Other application use Desktop Duplication API...
break;
case DXGI_ERROR_SESSION_DISCONNECTED:
error = 5;
break;
}
cursor_ = std::make_unique<Cursor>(this);
// MEMO: 'output' will be released automatically after this ctor.
}
Monitor::~Monitor()
{
if (deskDupl_ != nullptr)
{
deskDupl_->Release();
}
}
HRESULT Monitor::Render(UINT timeout)
{
if (deskDupl_ == nullptr)
{
GetMonitorManager()->RequireReinitilization();
return 0;
}
if (unityTexture_ == nullptr) return 0;
IDXGIResource* resource = nullptr;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
if (FAILED(hr))
{
return hr;
}
ID3D11Texture2D* texture;
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture);
context->Release();
cursor_->Update(frameInfo);
resource->Release();
deskDupl_->ReleaseFrame();
return 0;
}
int Monitor::GetId() const
{
return id_;
}
void Monitor::SetUnityTexture(ID3D11Texture2D* texture)
{
unityTexture_ = texture;
}
ID3D11Texture2D* Monitor::GetUnityTexture() const
{
return unityTexture_;
}
IDXGIOutputDuplication* Monitor::GetDeskDupl()
{
return deskDupl_;
}
const std::unique_ptr<Cursor>& Monitor::GetCursor()
{
return cursor_;
}
void Monitor::UpdateCursorTexture(ID3D11Texture2D* texture)
{
cursor_->UpdateTexture(texture);
}
void Monitor::GetName(char* buf, int len) const
{
strcpy_s(buf, len, monitorInfo_.szDevice);
}
bool Monitor::IsPrimary() const
{
return monitorInfo_.dwFlags == MONITORINFOF_PRIMARY;
}
int Monitor::GetLeft() const
{
return outputDesc_.DesktopCoordinates.left;
}
int Monitor::GetRight() const
{
return outputDesc_.DesktopCoordinates.right;
}
int Monitor::GetTop() const
{
return outputDesc_.DesktopCoordinates.top;
}
int Monitor::GetBottom() const
{
return outputDesc_.DesktopCoordinates.bottom;
}
int Monitor::GetRotation() const
{
return static_cast<int>(outputDesc_.Rotation);
}
int Monitor::GetWidth() const
{
const auto rect = monitorInfo_.rcMonitor;
return rect.right - rect.left;
}
int Monitor::GetHeight() const
{
const auto rect = monitorInfo_.rcMonitor;
return rect.bottom - rect.top;
}

View File

@@ -0,0 +1,38 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <memory>
class Cursor;
class Monitor
{
public:
Monitor(int id, IDXGIOutput* output);
~Monitor();
HRESULT Render(UINT timeout = 0);
void UpdateCursorTexture(ID3D11Texture2D* texture);
public:
int GetId() 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 GetWidth() const;
int GetHeight() const;
int GetRotation() const;
IDXGIOutputDuplication* GetDeskDupl();
const std::unique_ptr<Cursor>& GetCursor();
private:
int id_ = -1;
std::unique_ptr<Cursor> cursor_;
IDXGIOutputDuplication* deskDupl_ = nullptr;
ID3D11Texture2D* unityTexture_ = nullptr;
DXGI_OUTPUT_DESC outputDesc_;
MONITORINFOEX monitorInfo_;
};

View File

@@ -0,0 +1,316 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <vector>
#include <string>
#include <algorithm>
#include "IUnityInterface.h"
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
#include "Monitor.h"
#include "Cursor.h"
#include "MonitorManager.h"
MonitorManager::MonitorManager()
{
Initialize();
}
MonitorManager::~MonitorManager()
{
Finalize();
}
void MonitorManager::Initialize()
{
Finalize();
// Get factory
IDXGIFactory1* factory;
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
// Check all display adapters
int id = 0;
IDXGIAdapter1* adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
// Search the main monitor from all outputs
IDXGIOutput* output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{
auto monitor = std::make_shared<Monitor>(id++, output);
monitors_.push_back(monitor);
output->Release();
}
adapter->Release();
}
factory->Release();
}
void MonitorManager::Finalize()
{
monitors_.clear();
}
void MonitorManager::Reinitialize()
{
Initialize();
SendMessageToUnity(Message::Reinitialized);
}
std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
{
if (id >= 0 && id < monitors_.size())
{
return monitors_[id];
}
return nullptr;
}
void MonitorManager::Update()
{
if (isReinitializationRequired_)
{
Reinitialize();
isReinitializationRequired_ = false;
}
}
void MonitorManager::OnRender(int id)
{
if (auto monitor = GetMonitor(id))
{
// If any monitor setting has changed (e.g. monitor size has changed),
// it is necessary to re-initialize monitors.
const auto hr = monitor->Render(timeout_);
if (hr == DXGI_ERROR_ACCESS_LOST)
{
isReinitializationRequired_ = true;
}
}
}
void MonitorManager::UpdateCursorTexture(int id, ID3D11Texture2D* texture)
{
if (auto monitor = GetMonitor(id))
{
monitor->UpdateCursorTexture(texture);
}
}
void MonitorManager::SetTimeout(int timeout)
{
timeout_ = timeout;
}
void MonitorManager::SetTexturePtr(int id, void* texture)
{
if (auto monitor = GetMonitor(id))
{
auto d3d11Texture = reinterpret_cast<ID3D11Texture2D*>(texture);
monitor->SetUnityTexture(d3d11Texture);
}
}
int MonitorManager::GetMonitorCount() const
{
return static_cast<int>(monitors_.size());
}
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;
}
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;
}
void MonitorManager::GetName(int id, char* buf, int len) const
{
if (auto monitor = GetMonitor(id))
{
monitor->GetName(buf, len);
}
}
bool MonitorManager::IsPrimary(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->IsPrimary();
}
return false;
}
int MonitorManager::GetLeft(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetLeft();
}
return 0;
}
int MonitorManager::GetRight(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetRight();
}
return 0;
}
int MonitorManager::GetTop(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetTop();
}
return 0;
}
int MonitorManager::GetBottom(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetBottom();
}
return 0;
}
int MonitorManager::GetWidth(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetWidth();
}
return -1;
}
int MonitorManager::GetHeight(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetHeight();
}
return -1;
}
int MonitorManager::GetRotation(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetRotation();
}
return DXGI_MODE_ROTATION_UNSPECIFIED;
}
bool MonitorManager::IsCursorVisible(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->IsVisible();
}
return false;
}
int MonitorManager::GetCursorX(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->GetX();
}
return -1;
}
int MonitorManager::GetCursorY(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->GetY();
}
return -1;
}
int MonitorManager::GetCursorShapeWidth(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->GetWidth();
}
return -1;
}
int MonitorManager::GetCursorShapeHeight(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->GetHeight();
}
return -1;
}
int MonitorManager::GetCursorShapePitch(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->GetPitch();
}
return -1;
}
int MonitorManager::GetCursorShapeType(int id) const
{
if (auto monitor = GetMonitor(id))
{
return monitor->GetCursor()->GetType();
}
return -1;
}

View File

@@ -0,0 +1,64 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <vector>
#include <string>
#include <memory>
struct IUnityInterfaces;
class Monitor;
class Cursor;
class MonitorManager
{
public:
explicit MonitorManager();
~MonitorManager();
void RequireReinitilization() { isReinitializationRequired_ = true; }
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
int GetCursorMonitorId() const { return cursorMonitorId_; }
std::shared_ptr<Monitor> GetMonitor(int id) const;
private:
void Initialize();
void Finalize();
void Reinitialize();
// Setters from Unity
public:
void OnRender(int id);
void Update();
void UpdateCursorTexture(int id, ID3D11Texture2D* ptr);
void SetTimeout(int timeout);
void SetTexturePtr(int id, void* texture);
// Getters from Unity
public:
int GetMonitorCount() const;
int GetTotalWidth() const;
int GetTotalHeight() const;
void GetName(int id, char* buf, int len) const;
bool IsPrimary(int id) const;
int GetLeft(int id) const;
int GetRight(int id) const;
int GetTop(int id) const;
int GetBottom(int id) const;
int GetWidth(int id) const;
int GetHeight(int id) const;
int GetRotation(int id) const;
bool IsCursorVisible(int id) const;
int GetCursorX(int id) const;
int GetCursorY(int id) const;
int GetCursorShapeWidth(int id) const;
int GetCursorShapeHeight(int id) const;
int GetCursorShapePitch(int id) const;
int GetCursorShapeType(int id) const;
private:
int timeout_ = 10;
std::vector<std::shared_ptr<Monitor>> monitors_;
std::shared_ptr<Cursor> cursor_;
int cursorMonitorId_ = -1;
bool isReinitializationRequired_ = false;
};

View File

@@ -3,35 +3,81 @@
#include <vector>
#include <string>
#include <memory>
#include <queue>
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
#include "Duplication.h"
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
#include "MonitorManager.h"
#pragma comment(lib, "dxgi.lib")
namespace
{
std::unique_ptr<Duplication> g_dupl;
IUnityInterfaces* g_unity = nullptr;
std::unique_ptr<MonitorManager> g_manager;
std::queue<Message> g_messages;
}
IUnityInterfaces* GetUnity()
{
return g_unity;
}
ID3D11Device* GetDevice()
{
return GetUnity()->Get<IUnityGraphicsD3D11>()->GetDevice();
}
const std::unique_ptr<MonitorManager>& GetMonitorManager()
{
return g_manager;
}
void SendMessageToUnity(Message message)
{
g_messages.push(message);
}
extern "C"
{
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API InitializeUDD()
{
if (g_unity && !g_manager)
{
g_manager = std::make_unique<MonitorManager>();
}
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API FinalizeUDD()
{
g_manager.reset();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
g_dupl = std::make_unique<Duplication>(unityInterfaces);
g_unity = unityInterfaces;
InitializeUDD();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UnityPluginUnload()
{
g_dupl.reset();
g_unity = nullptr;
FinalizeUDD();
}
void UNITY_INTERFACE_API OnRenderEvent(int id)
{
g_dupl->OnRender(id);
if (!g_manager) return;
g_manager->OnRender(id);
}
UNITY_INTERFACE_EXPORT UnityRenderingEvent UNITY_INTERFACE_API GetRenderEventFunc()
@@ -39,89 +85,150 @@ extern "C"
return OnRenderEvent;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API Update()
{
if (!g_manager) return;
g_manager->Update();
}
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()
{
return g_dupl->GetMonitorCount();
if (!g_manager) return 0;
return g_manager->GetMonitorCount();
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetTotalWidth()
{
if (!g_manager) return 0;
return g_manager->GetTotalWidth();
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetTotalHeight()
{
if (!g_manager) return 0;
return g_manager->GetTotalHeight();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTimeout(int timeout)
{
g_dupl->SetTimeout(timeout);
if (!g_manager) return;
g_manager->SetTimeout(timeout);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
{
g_dupl->GetName(id, buf, len);
if (!g_manager) return;
g_manager->GetName(id, buf, len);
}
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsPrimary(int id)
{
return g_dupl->IsPrimary(id);
if (!g_manager) return false;
return g_manager->IsPrimary(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetLeft(int id)
{
if (!g_manager) return -1;
return g_manager->GetLeft(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetRight(int id)
{
if (!g_manager) return -1;
return g_manager->GetRight(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetTop(int id)
{
if (!g_manager) return -1;
return g_manager->GetTop(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetBottom(int id)
{
if (!g_manager) return -1;
return g_manager->GetBottom(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetWidth(int id)
{
return g_dupl->GetWidth(id);
if (!g_manager) return -1;
return g_manager->GetWidth(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetHeight(int id)
{
return g_dupl->GetHeight(id);
if (!g_manager) return -1;
return g_manager->GetHeight(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API IsPointerVisible(int id)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetRotation(int id)
{
return g_dupl->IsPointerVisible(id);
if (!g_manager) return -1;
return g_manager->GetRotation(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerX(int id)
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsCursorVisible(int id)
{
return g_dupl->GetPointerX(id);
if (!g_manager) return false;
return g_manager->IsCursorVisible(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerY(int id)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorX(int id)
{
return g_dupl->GetPointerY(id);
if (!g_manager) return -1;
return g_manager->GetCursorX(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapeWidth(int id)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorY(int id)
{
return g_dupl->GetPointerShapeWidth(id);
if (!g_manager) return -1;
return g_manager->GetCursorY(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapeHeight(int id)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeWidth(int id)
{
return g_dupl->GetPointerShapeHeight(id);
if (!g_manager) return -1;
return g_manager->GetCursorShapeWidth(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapePitch(int id)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeHeight(int id)
{
return g_dupl->GetPointerShapePitch(id);
if (!g_manager) return -1;
return g_manager->GetCursorShapeHeight(id);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetPointerShapeType(int id)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapePitch(int id)
{
return g_dupl->GetPointerShapeType(id);
if (!g_manager) return -1;
return g_manager->GetCursorShapePitch(id);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdatePointerTexture(int id, ID3D11Texture2D* ptr)
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeType(int id)
{
g_dupl->UpdatePointerTexture(id, ptr);
if (!g_manager) return -1;
return g_manager->GetCursorShapeType(id);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdateCursorTexture(int id, ID3D11Texture2D* ptr)
{
if (!g_manager) return;
g_manager->UpdateCursorTexture(id, ptr);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTexturePtr(int id, void* texture)
{
g_dupl->SetTexturePtr(id, texture);
if (!g_manager) return;
g_manager->SetTexturePtr(id, texture);
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetErrorCode()
{
return g_dupl->GetErrorCode();
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetErrorMessage(char* buf, int len)
{
g_dupl->GetErrorMessage(buf, len);
}
}

View File

@@ -69,8 +69,12 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);include</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);include</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@@ -122,14 +126,19 @@
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Duplication.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="MonitorManager.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Monitor.cpp" />
<ClCompile Include="Cursor.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Duplication.h" />
<ClInclude Include="IUnityGraphics.h" />
<ClInclude Include="IUnityGraphicsD3D11.h" />
<ClInclude Include="IUnityInterface.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="MonitorManager.h" />
<ClInclude Include="include\IUnityGraphics.h" />
<ClInclude Include="include\IUnityGraphicsD3D11.h" />
<ClInclude Include="include\IUnityInterface.h" />
<ClInclude Include="Monitor.h" />
<ClInclude Include="Cursor.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Include">
<UniqueIdentifier>{a820eab3-2c2a-4d56-9670-064198e6a1cf}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\IUnityInterface.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\IUnityGraphics.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="include\IUnityGraphicsD3D11.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="Monitor.h" />
<ClInclude Include="Cursor.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="MonitorManager.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Monitor.cpp" />
<ClCompile Include="Cursor.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MonitorManager.cpp" />
</ItemGroup>
</Project>