Compare commits

..

60 Commits

Author SHA1 Message Date
hecomi
9f8a026c24 add offset angle xyz. 2016-11-13 23:25:53 +09:00
hecomi
dc702c6e1d support option to choise real / fixed scale. 2016-11-13 23:18:00 +09:00
hecomi
5a3af11d08 add thickness control. 2016-11-13 22:58:14 +09:00
hecomi
0646621f73 modify utility icon. 2016-11-13 22:22:57 +09:00
hecomi
c9d6d3ad6a check texture sizes. 2016-11-13 22:22:33 +09:00
hecomi
78ee75a875 improve detection for monitor state change. 2016-11-13 22:15:22 +09:00
hecomi
c83ce50468 improve log. 2016-11-13 21:59:22 +09:00
hecomi
3567182a4d add dpi warning. 2016-11-13 11:12:45 +09:00
hecomi
e466aa65db add offset angle of roundly layouter. 2016-11-13 11:09:39 +09:00
hecomi
a0edc1a439 use system cursor position for zoom when cursor is invisible (e.g. dragging). 2016-11-12 16:28:33 +09:00
hecomi
1eb821b34d add unknown error. 2016-11-12 16:04:37 +09:00
hecomi
212d8ccb9b check zoom values. 2016-11-12 15:22:53 +09:00
hecomi
fac8fe1ea7 fix dpi zero bug. 2016-11-12 15:22:39 +09:00
hecomi
f90178f1db use inline. 2016-11-12 14:46:22 +09:00
hecomi
74e25f2bd7 add scene manager. 2016-11-12 14:38:13 +09:00
hecomi
70c126be6c fix monitor reinitialization bug. 2016-11-12 13:16:00 +09:00
hecomi
f74221bf75 update board. 2016-11-12 04:27:28 +09:00
hecomi
3a705732d1 improve bending. 2016-11-12 04:25:12 +09:00
hecomi
804bfb96bd add board-style screen. 2016-11-12 03:56:46 +09:00
hecomi
63d8f6936d use ComPtr for resources instead of standard smart pointers. 2016-11-12 02:44:20 +09:00
hecomi
e4e4917bcb fix manager non-initialization bug. 2016-11-12 02:05:09 +09:00
hecomi
0e205ecef7 fix zoom bug. 2016-11-12 02:00:04 +09:00
hecomi
cda8024b17 fix break in error image. 2016-11-12 00:40:11 +09:00
hecomi
05085f7d24 fix bug caused when releasing duplication output. 2016-11-10 23:33:19 +09:00
hecomi
52eafbe919 change unsupported texture. 2016-11-10 23:21:04 +09:00
hecomi
be1e0c25bb expand aabb to avoid culling. 2016-11-10 23:06:24 +09:00
hecomi
372e44d8c1 output logs. 2016-11-10 22:35:46 +09:00
hecomi
d79eb91333 fix freeze bug caused by masked cursor boundary conditions. 2016-11-10 02:50:59 +09:00
hecomi
f654df7f5b add debug logs and use safer code. 2016-11-09 21:58:00 +09:00
hecomi
620762dba7 add logging and use smart pointers for buffers. 2016-11-09 19:40:05 +09:00
hecomi
43ba445623 Merge branch 'master' of github.com:hecomi/uDesktopDuplication 2016-11-09 02:55:32 +09:00
hecomi
c7c12de730 move dll location. 2016-11-09 02:55:26 +09:00
hecomi
1086595d6b fix bug that did not remove unsupported monitor element in list. 2016-11-09 02:54:49 +09:00
hecomi
f69fb6a7bb remove monitor if unsupported. 2016-11-09 00:50:57 +09:00
hecomi
b661b4a93f modify zoom scene. 2016-11-09 00:23:25 +09:00
hecomi
8d9ef71829 update monitor id of loupe. 2016-11-09 00:18:52 +09:00
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
hecomi
2b108bd4b1 fix available getter bug. 2016-11-05 23:25:22 +09:00
hecomi
f9f8b14f46 show not-available texture when display is not available. 2016-11-05 23:15:57 +09:00
hecomi
7774290e71 fix text orientation. 2016-11-05 22:56:22 +09:00
hecomi
a3a7754fb0 remove unused cursor material and move icon to editor dir. 2016-11-05 22:44:17 +09:00
hecomi
0accebb657 add not-available texture. 2016-11-05 22:42:45 +09:00
hecomi
0a38eda14f update files. 2016-11-05 22:36:08 +09:00
hecomi
720f74e6f6 check unsupported display. 2016-11-05 22:34:11 +09:00
hecomi
80fa39f4eb remove unused debug.log. 2016-11-05 02:14:19 +09:00
hecomi
22b21ae3f4 check texture size before recreating it. 2016-11-05 01:44:26 +09:00
hecomi
43153266a0 rename members named pointer to cursor. 2016-11-05 01:40:20 +09:00
72 changed files with 1988 additions and 640 deletions

1
.gitignore vendored
View File

@@ -27,3 +27,4 @@ sysinfo.txt
.DS_Store
/Assets/AssetStoreTools*
/Assets/Extensions*
/uDesktopDuplication.log

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 022a80d652ef0304e84e9d6ac689e21f
folderAsset: yes
timeCreated: 1478353382
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6e15bc51aada81042a909c808e25c176
folderAsset: yes
timeCreated: 1477555207
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 033e0db89e0ca1d46a399c953629f67d
timeCreated: 1477555367
guid: 42d6b6dbae38a384e882c2c907915139
timeCreated: 1478889784
licenseType: Pro
NativeFormatImporter:
userData:

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ce9467b01f36d647ace156faef9cb9f
timeCreated: 1478927635
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,48 @@
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()
{
CheckVariables();
if (uDesktopDuplication.Manager.cursorMonitorId < 0) return;
uddTexture_.monitorId = uDesktopDuplication.Manager.cursorMonitorId;
// To get other monitor textures, set dirty flag.
foreach (var target in uDesktopDuplication.Manager.monitors) {
target.CreateTexture();
target.shouldBeUpdated = true;
}
var monitor = uddTexture_.monitor;
var cursorX = monitor.isCursorVisible ? monitor.cursorX : monitor.systemCursorX;
var cursorY = monitor.isCursorVisible ? monitor.cursorY : monitor.systemCursorY;
var x = (float)cursorX / monitor.width;
var y = (float)cursorY / monitor.height;
var w = 1f / zoom;
var h = w / aspect * monitor.aspect;
x = Mathf.Clamp(x - w / 2, 0f, 1f - w);
y = Mathf.Clamp(y - h / 2, 0f, 1f - h);
uddTexture_.clipPos = new Vector2(x, y);
uddTexture_.clipScale = new Vector2(w, h);
}
void CheckVariables()
{
if (zoom < 1f) zoom = 1f;
if (aspect < 0.01f) aspect = 0.01f;
}
}

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,57 +1,161 @@
using UnityEngine;
using System.Collections.Generic;
using MeshForwardDirection = uDesktopDuplication.Texture.MeshForwardDirection;
public class MultipleMonitorCreator : MonoBehaviour
{
[SerializeField] GameObject monitorPrefab;
[SerializeField] float width = 0.3f;
[SerializeField] float margin = 1f;
[Tooltip("Create monitors using this prefab.")]
[SerializeField]
GameObject monitorPrefab;
[Tooltip("Use same scale as real using DPI.")]
[SerializeField]
bool useRealScale = true;
[Tooltip("Use this sacle as width if useRealScale is false.")]
[SerializeField]
float scale = 0.5f;
[Tooltip("Remove unsupported monitors automatically after removeWaitDuration.")]
[SerializeField]
bool removeIfUnsupported = true;
[Tooltip("Remove unsupported monitors automatically after removeWaitDuration.")]
[SerializeField]
float removeWaitDuration = 5f;
bool hasMonitorUnsupportStateChecked = false;
float removeWaitTimer_ = 0f;
[Tooltip("Please specify the surface direction of the mesh (e.g. Plane => Y.)")]
public MeshForwardDirection meshForwardDirection = MeshForwardDirection.Z;
public class MonitorInfo
{
public GameObject gameObject { get; set; }
public Quaternion originalRotation { get; set; }
public uDesktopDuplication.Texture uddTexture { get; set; }
public Mesh mesh { get; set; }
}
private List<MonitorInfo> monitors_ = new List<MonitorInfo>();
public List<MonitorInfo> monitors { get { return monitors_; } }
void Start()
{
// Sort monitors in coordinate order
var monitors = uDesktopDuplication.Manager.monitors;
monitors.Sort((a, b) => a.left - b.left);
uDesktopDuplication.Manager.CreateInstance();
Create();
}
void Update()
{
if (removeIfUnsupported) {
RemoveUnsupportedDisplayAfterRemoveTimer();
}
if (uDesktopDuplication.Manager.monitorCount != monitors.Count) {
Recreate();
}
}
void OnEnable()
{
uDesktopDuplication.Manager.onReinitialized += Recreate;
}
void OnDisable()
{
uDesktopDuplication.Manager.onReinitialized -= Recreate;
}
void RemoveUnsupportedDisplayAfterRemoveTimer()
{
if (!hasMonitorUnsupportStateChecked) {
removeWaitTimer_ += Time.deltaTime;
if (removeWaitTimer_ > removeWaitDuration) {
hasMonitorUnsupportStateChecked = true;
foreach (var info in monitors_) {
if (info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported) {
Destroy(info.gameObject);
}
}
monitors_.RemoveAll(info => info.uddTexture.monitor.state == uDesktopDuplication.MonitorState.Unsupported);
}
}
}
void ResetRemoveTimer()
{
hasMonitorUnsupportStateChecked = false;
removeWaitTimer_ = 0f;
}
void Create()
{
ResetRemoveTimer();
// 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;
// Expand AABB
var mesh = go.GetComponent<MeshFilter>().mesh; // clone
var aabbScale = mesh.bounds.size;
aabbScale.y = Mathf.Max(aabbScale.y, aabbScale.x);
aabbScale.z = Mathf.Max(aabbScale.z, aabbScale.x);
mesh.bounds = new Bounds(mesh.bounds.center, aabbScale);
// 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);
float width, height;
if (useRealScale) {
width = monitor.widthMeter;
height = monitor.heightMeter;
} else {
width = scale * (monitor.isHorizontal ? 1f : monitor.aspect);
height = scale * (monitor.isHorizontal ? 1f / monitor.aspect : 1f);
}
if (meshForwardDirection == MeshForwardDirection.Y) {
go.transform.localScale = new Vector3(width, go.transform.localScale.y, height);
} else {
go.transform.localScale = new Vector3(width, height, go.transform.localScale.z);
}
// Set parent as this object
go.transform.SetParent(transform);
// Calc actual size considering mesh size
var scaleX = go.GetComponent<MeshFilter>().sharedMesh.bounds.extents.x * 2f;
totalWidth += w * scaleX;
// Save
var info = new MonitorInfo();
info.gameObject = go;
info.originalRotation = go.transform.rotation;
info.uddTexture = texture;
info.mesh = mesh;
monitors_.Add(info);
}
// 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;
// Sort monitors in coordinate order
monitors_.Sort((a, b) => a.uddTexture.monitor.left - b.uddTexture.monitor.left);
}
void Clear()
{
foreach (var info in monitors_) {
Destroy(info.gameObject);
}
monitors_.Clear();
}
[ContextMenu("Recreate")]
public void Recreate()
{
Clear();
Create();
}
}

View File

@@ -0,0 +1,54 @@
using UnityEngine;
[RequireComponent(typeof(MultipleMonitorCreator))]
public class MultipleMonitorLayouter : MonoBehaviour
{
protected MultipleMonitorCreator creator_;
[SerializeField] bool updateEveryFrame = true;
[SerializeField] protected float margin = 0.1f;
[SerializeField][Range(0f, 10f)] protected float thickness = 1f;
void Start()
{
creator_ = GetComponent<MultipleMonitorCreator>();
Layout();
}
protected virtual void Update()
{
margin = Mathf.Max(margin, 0f);
if (updateEveryFrame) {
Layout();
}
}
protected virtual void Layout()
{
var monitors = creator_.monitors;
var n = monitors.Count;
var totalWidth = 0f;
foreach (var info in monitors) {
var width = info.gameObject.transform.localEulerAngles.x * (info.mesh.bounds.extents.x * 2f);
totalWidth += width;
}
totalWidth += margin * (n - 1);
var x = -totalWidth / 2;
foreach (var info in monitors) {
var width = info.gameObject.transform.localEulerAngles.x;
x += (width * info.mesh.bounds.extents.x);
info.gameObject.transform.localPosition = new Vector3(x, 0f, 0f);
info.gameObject.transform.localRotation = info.originalRotation;
x += (width * info.mesh.bounds.extents.x) + margin;
}
foreach (var info in monitors) {
info.uddTexture.thickness = thickness;
}
}
}

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,68 @@
using UnityEngine;
public class MultipleMonitorRoundLayouter : MultipleMonitorLayouter
{
[SerializeField] float radius = 10f;
[SerializeField] Vector3 offsetAngle = Vector3.zero;
void OnDisable()
{
foreach (var info in creator_.monitors) {
info.uddTexture.bend = false;
}
}
protected override void Layout()
{
var monitors = creator_.monitors;
var n = monitors.Count;
var totalWidth = 0f;
foreach (var info in monitors) {
var width = info.gameObject.transform.localScale.x * (info.mesh.bounds.extents.x * 2f);
totalWidth += width;
}
totalWidth += margin * (n - 1);
radius = Mathf.Max(radius, (totalWidth + margin) / (2 * Mathf.PI));
var totalAngle = totalWidth / radius;
float angle = -totalAngle / 2;
var offsetRot = Quaternion.Euler(offsetAngle);
foreach (var info in monitors) {
var uddTex = info.uddTexture;
var width = info.gameObject.transform.localScale.x * (info.mesh.bounds.extents.x * 2f);
angle += (width / radius) * 0.5f;
var pos = radius * new Vector3(Mathf.Sin(angle), 0f, Mathf.Cos(angle) - 1f);
pos += radius * Vector3.forward;
pos = offsetRot * pos;
pos -= radius * Vector3.forward;
uddTex.transform.localPosition = pos;
uddTex.transform.localRotation = offsetRot * Quaternion.AngleAxis(angle * Mathf.Rad2Deg, Vector3.up) * info.originalRotation;
angle += (width * 0.5f + margin) / radius;
uddTex.bend = true;
uddTex.meshForwardDirection = creator_.meshForwardDirection;
uddTex.radius = radius;
uddTex.thickness = thickness;
uddTex.width = uddTex.transform.localScale.x;
}
}
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

@@ -0,0 +1,50 @@
using UnityEngine;
using UnityEngine.SceneManagement;
public class UddSceneManager : MonoBehaviour
{
public static UddSceneManager instance { get; set; }
[SerializeField] string[] scenes;
[SerializeField] int sceneNo = 0;
void Awake()
{
if (!instance) {
instance = this;
} else {
Destroy(gameObject);
}
}
void Start()
{
DontDestroyOnLoad(gameObject);
Load();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.RightArrow)) {
Next();
} else if (Input.GetKeyDown(KeyCode.LeftArrow)) {
Prev();
}
}
void Next()
{
sceneNo = (sceneNo + 1) % scenes.Length;
Load();
}
void Prev()
{
sceneNo = (sceneNo - 1) % scenes.Length;
Load();
}
void Load()
{
SceneManager.LoadScene(scenes[sceneNo]);
}
}

View File

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

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 75494e992a22ea44d9b614d7fd3dc235
folderAsset: yes
timeCreated: 1478887431
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,78 @@
fileFormatVersion: 2
guid: d6b30b913257fee4d8246bf7a2620fcd
timeCreated: 1478887431
licenseType: Pro
ModelImporter:
serializedVersion: 19
fileIDToRecycleName:
100000: //RootNode
400000: //RootNode
2300000: //RootNode
3300000: //RootNode
4300000: pCube1
4300002: uDD_Board
9500000: //RootNode
materials:
importMaterials: 0
materialName: 0
materialSearch: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 0.1
meshCompression: 0
addColliders: 0
importBlendShapes: 1
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
optimizeMeshForGPU: 1
keepQuads: 0
weldVertices: 1
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVPackMargin: 4
useFileScale: 1
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 2
importAnimation: 0
copyAvatar: 0
humanDescription:
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
rootMotionBoneName:
hasTranslationDoF: 0
lastHumanDescriptionAvatarSource: {instanceID: 0}
animationType: 0
humanoidOversampling: 1
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 99257566ccd0582439a44abad90e65d4
folderAsset: yes
timeCreated: 1478626361
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 6e15bc51aada81042a909c808e25c176
guid: b281589e6b8e27b4fbf0509d620b7871
folderAsset: yes
timeCreated: 1477555207
licenseType: Pro
timeCreated: 1478354860
licenseType: Free
DefaultImporter:
userData:
assetBundleName:

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 48b92326b146fa848beec6f35365b1f4
guid: e36cd526b654d024e875d5110a1b0442
folderAsset: yes
timeCreated: 1477555207
licenseType: Pro
timeCreated: 1478354877
licenseType: Free
DefaultImporter:
userData:
assetBundleName:

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,59 @@
fileFormatVersion: 2
guid: 9855ecfc2b823c94d8a1354715d343a1
timeCreated: 1478353264
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 1
linearTexture: 0
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 7
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: -1
nPOTScale: 1
lightmap: 0
rGBM: 0
compressionQuality: 50
allowsAlphaSplitting: 0
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: -1
buildTargetSettings: []
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using UnityEngine.Assertions;
using System.Collections.Generic;
namespace uDesktopDuplication
@@ -8,14 +9,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,14 +27,14 @@ public class Cursor : MonoBehaviour
if (monitor.isCursorVisible) {
UpdatePosition();
UpdateTexture();
UpdateMaterial();
}
UpdateMaterial();
}
void UpdatePosition()
{
var x = (1f * monitor.pointerX / monitor.width - 0.5f) * modelScale.x;
var y = (1f * monitor.pointerY / monitor.height - 0.5f) * modelScale.y;
var x = (1f * monitor.cursorX / monitor.width - 0.5f) * modelScale.x;
var y = (1f * monitor.cursorY / monitor.height - 0.5f) * modelScale.y;
var iy = uddTexture_.invertY ? -1 : +1;
var localPos = transform.right * x + iy * transform.up * y;
worldPosition = transform.TransformPoint(localPos);
@@ -42,28 +42,29 @@ public class Cursor : MonoBehaviour
void UpdateTexture()
{
var w = monitor.pointerShapeWidth;
var h = monitor.pointerShapeHeight;
var w = monitor.cursorShapeWidth;
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 pointerTexture = textures_[scale];
monitor.UpdateCursorTexture(pointerTexture.GetNativeTexturePtr());
uddTexture_.material.SetTexture("_CursorTex", pointerTexture);
var cursorTexture = textures_[key];
Assert.IsNotNull(cursorTexture);
monitor.GetCursorTexture(cursorTexture.GetNativeTexturePtr());
uddTexture_.material.SetTexture("_CursorTex", cursorTexture);
}
void UpdateMaterial()
{
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;
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,21 +27,57 @@ public enum MonitorRotation
Rotate270 = 4
}
public enum MonitorState
{
NotSet = -1,
Available = 0,
InvalidArg = 1,
AccessDenied = 2,
Unsupported = 3,
CurrentlyNotAvailable = 4,
SessionDisconnected = 5,
AccessLost = 6,
Unknown = 999,
}
public enum DebugMode
{
None = 0,
File = 1,
UnityLog = 2, /* currently has bug when app exits. */
}
public static class Lib
{
public delegate void MessageHandler(Message message);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogDelegate(string str);
[DllImport("uDesktopDuplication")]
public static extern void InitializeUDD();
[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 void EnableDebug();
[DllImport("uDesktopDuplication")]
public static extern void DisableDebug();
[DllImport("uDesktopDuplication")]
public static extern void SetDebugMode(DebugMode mode);
[DllImport("uDesktopDuplication")]
public static extern void SetLogFunc(IntPtr func);
[DllImport("uDesktopDuplication")]
public static extern void SetErrorFunc(IntPtr func);
[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,6 +86,10 @@ public static class Lib
[DllImport("uDesktopDuplication")]
public static extern IntPtr GetRenderEventFunc();
[DllImport("uDesktopDuplication")]
public static extern int GetId(int id);
[DllImport("uDesktopDuplication")]
public static extern MonitorState GetState(int id);
[DllImport("uDesktopDuplication")]
public static extern void GetName(int id, StringBuilder buf, int len);
[DllImport("uDesktopDuplication")]
public static extern int GetLeft(int id);
@@ -64,6 +104,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);
@@ -82,7 +126,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

@@ -1,6 +1,7 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace uDesktopDuplication
{
@@ -10,12 +11,7 @@ public class Manager : MonoBehaviour
private static Manager instance_;
public static Manager instance
{
get
{
if (instance_) return instance_;
var go = new GameObject("uDesktopDuplicationManager");
return go.AddComponent<Manager>();
}
get { return CreateInstance(); }
}
private List<Monitor> monitors_ = new List<Monitor>();
@@ -29,6 +25,11 @@ public class Manager : MonoBehaviour
get { return Lib.GetMonitorCount(); }
}
static public int cursorMonitorId
{
get { return Lib.GetCursorMonitorId(); }
}
static public Monitor primary
{
get
@@ -37,13 +38,45 @@ public class Manager : MonoBehaviour
}
}
[SerializeField, Tooltip("Set Desktop Duplication API timeout (milliseconds).")]
int timeout = 0;
[SerializeField] DebugMode debugMode = DebugMode.File;
[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;
public static Manager CreateInstance()
{
if (instance_) {
return instance_;
}
var manager = FindObjectOfType<Manager>();
if (manager) {
manager.Awake();
return manager;
}
var go = new GameObject("uDesktopDuplicationManager");
return go.AddComponent<Manager>();
}
public static Monitor GetMonitor(int id)
{
if (id < 0 || id >= Manager.monitors.Count) {
Debug.LogErrorFormat("[uDD::Error] there is no monitor whose id is {0}.", id);
return Manager.primary;
}
return monitors[Mathf.Clamp(id, 0, Manager.monitorCount - 1)];
}
void Awake()
{
Lib.SetDebugMode(debugMode);
Lib.InitializeUDD();
if (instance_ != null) return;
@@ -51,7 +84,7 @@ public class Manager : MonoBehaviour
CreateMonitors();
Lib.SetTimeout(timeout);
Lib.SetTimeout(desktopDuplicationApiTimeout);
}
void OnApplicationQuit()
@@ -75,13 +108,53 @@ public class Manager : MonoBehaviour
void Update()
{
Lib.Update();
ReinitializeIfNeeded();
UpdateMessage();
}
[ContextMenu("Reinitialize")]
void Reinitialize()
{
Debug.Log("[uDD] Reinitialize");
Lib.Reinitialize();
CreateMonitors();
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;
@@ -106,12 +179,13 @@ public class Manager : MonoBehaviour
void CreateMonitors()
{
monitors.Clear();
for (int i = 0; i < monitorCount; ++i) {
monitors.Add(new Monitor(i));
}
}
void Reinitialize()
void ReinitializeMonitors()
{
for (int i = 0; i < monitorCount; ++i) {
if (i == monitors.Count) {
@@ -120,6 +194,17 @@ public class Manager : MonoBehaviour
monitors[i].Reinitialize();
}
}
void WaitThenDo(System.Action func, float sec)
{
StartCoroutine(_WaitThenDo(func, sec));
}
IEnumerator _WaitThenDo(System.Action func, float sec)
{
yield return new WaitForSeconds(sec);
func();
}
}
}

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using System.Runtime.InteropServices;
namespace uDesktopDuplication
{
@@ -8,6 +9,34 @@ public class Monitor
public Monitor(int id)
{
this.id = id;
switch (state)
{
case MonitorState.Available:
break;
case MonitorState.InvalidArg:
Debug.LogErrorFormat("[uDD] {0}:{1} => Invalid.", id, name);
break;
case MonitorState.AccessDenied:
Debug.LogWarningFormat("[uDD] {0}:{1} => Access Denied.", id, name);
break;
case MonitorState.Unsupported:
Debug.LogWarningFormat("[uDD] {0}:{1} => Unsupported.", id, name);
break;
case MonitorState.SessionDisconnected:
Debug.LogWarningFormat("[uDD] {0}:{1} => Disconnected.", id, name);
break;
case MonitorState.NotSet:
Debug.LogErrorFormat("[uDD] {0}:{1} => Something wrong.", id, name);
break;
default:
Debug.LogErrorFormat("[uDD] {0}:{1} => Unknown error.", id, name);
break;
}
if (dpiX == 0 || dpiY == 0) {
Debug.LogWarningFormat("[uDD] {0}:{1} => Could not get DPI", id, name);
}
}
public int id
@@ -21,6 +50,16 @@ public class Monitor
get { return id < Manager.monitorCount; }
}
public MonitorState state
{
get { return Lib.GetState(id); }
}
public bool available
{
get { return state == MonitorState.Available; }
}
public string name
{
get { return Lib.GetName(id); }
@@ -61,6 +100,36 @@ public class Monitor
get { return Lib.GetHeight(id); }
}
public int dpiX
{
get
{
var dpi = Lib.GetDpiX(id);
if (dpi == 0) dpi = 100; // when monitors are duplicated
return dpi;
}
}
public int dpiY
{
get
{
var dpi = Lib.GetDpiY(id);
if (dpi == 0) dpi = 100; // when monitors are duplicated
return dpi;
}
}
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); }
@@ -86,27 +155,45 @@ public class Monitor
get { return Lib.IsCursorVisible(id); }
}
public int pointerX
public int cursorX
{
get { return Lib.GetCursorX(id); }
}
public int pointerY
public int cursorY
{
get { return Lib.GetCursorY(id); }
}
public int pointerShapeWidth
public int systemCursorX
{
get
{
var p = Utility.GetCursorPos();
return p.x - left;
}
}
public int systemCursorY
{
get
{
var p = Utility.GetCursorPos();
return p.y - top;
}
}
public int cursorShapeWidth
{
get { return Lib.GetCursorShapeWidth(id); }
}
public int pointerShapeHeight
public int cursorShapeHeight
{
get { return Lib.GetCursorShapeHeight(id); }
}
public CursorShapeType pointerShapeType
public CursorShapeType cursorShapeType
{
get { return Lib.GetCursorShapeType(id); }
}
@@ -122,6 +209,9 @@ public class Monitor
{
get
{
if (!available) {
return Resources.Load<Texture2D>("uDesktopDuplication/Textures/NotAvailable");
}
if (texture_ == null) {
CreateTexture();
}
@@ -131,17 +221,21 @@ public class Monitor
public void Render()
{
Lib.SetTexturePtr(id, texture_.GetNativeTexturePtr());
GL.IssuePluginEvent(Lib.GetRenderEventFunc(), id);
if (texture_ && available) {
Lib.SetTexturePtr(id, texture_.GetNativeTexturePtr());
GL.IssuePluginEvent(Lib.GetRenderEventFunc(), id);
}
}
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;
var w = isHorizontal ? width : height;
var h = isHorizontal ? height : width;
bool shouldCreate = true;
@@ -155,6 +249,10 @@ public class Monitor
}
}
if (w <= 0 || h <= 0) {
shouldCreate = false;
}
if (shouldCreate) {
texture_ = new Texture2D(w, h, TextureFormat.BGRA32, false);
}

View File

@@ -13,20 +13,90 @@ public class Texture : MonoBehaviour
set
{
monitor_ = value;
material = GetComponent<Renderer>().material;
material = GetComponent<Renderer>().material; // clone
material.mainTexture = monitor_.texture;
material.SetFloat("_Width", transform.localScale.x);
}
}
public int monitorId
{
get { return monitor.id; }
set { monitor = Manager.monitors[Mathf.Clamp(value, 0, Manager.monitorCount - 1)]; }
set { monitor = Manager.GetMonitor(value); }
}
[Header("Invert UVs")]
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 MeshForwardDirection
{
Y = 0,
Z = 1,
}
public bool bend
{
get
{
return material.GetInt("_Bend") != 0;
}
set
{
if (value) {
material.EnableKeyword("BEND_ON");
} else {
material.DisableKeyword("BEND_ON");
}
}
}
public MeshForwardDirection meshForwardDirection
{
get
{
return (MeshForwardDirection)material.GetInt("_Forward");
}
set
{
switch (value) {
case MeshForwardDirection.Y:
material.SetInt("_Forward", 0);
material.EnableKeyword("_BEND_Y");
material.DisableKeyword("_BEND_Z");
break;
case MeshForwardDirection.Z:
material.SetInt("_Forward", 1);
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 float thickness
{
get { return material.GetFloat("_Thickness"); }
set { material.SetFloat("_Thickness", value); }
}
public Material material
{
get;
@@ -55,6 +125,13 @@ public class Texture : MonoBehaviour
}
void UpdateMaterial()
{
Invert();
Rotate();
Clip();
}
void Invert()
{
if (invertX) {
material.EnableKeyword("INVERT_X");
@@ -67,7 +144,10 @@ public class Texture : MonoBehaviour
} else {
material.DisableKeyword("INVERT_Y");
}
}
void Rotate()
{
switch (monitor.rotation)
{
case MonitorRotation.Identity:
@@ -94,6 +174,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

@@ -0,0 +1,30 @@
using UnityEngine;
using System.Runtime.InteropServices;
namespace uDesktopDuplication
{
public struct MousePoint
{
public int x;
public int y;
}
public static class Utility
{
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPos(out MousePoint point);
public static MousePoint GetCursorPos()
{
MousePoint p;
if (!GetCursorPos(out p)) {
p.x = -1;
p.y = -1;
}
return p;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6c7e8da181b03ce4fb343ffa33cbb929
timeCreated: 1479043365
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 89616e59e1cccb346bd4e959257990ca, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -2,6 +2,7 @@
#define UDD_COMMON_CGINC
#include "UnityCG.cginc"
#include "./uDD_Params.cginc"
struct appdata
{
@@ -17,35 +18,42 @@ struct v2f
struct Input
{
float2 uv_MainTex;
float2 uv_MainTex;
};
float2 uddInvertUV(float2 uv)
inline 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
return uv;
return uv;
}
float2 uddRotateUV(float2 uv)
inline 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;
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;
return uv;
}
inline float2 uddClipUV(float2 uv)
{
uv.x = _ClipX + uv.x * _ClipWidth;
uv.y = _ClipY + uv.y * _ClipHeight;
return uv;
}
inline void uddConvertToLinearIfNeeded(inout fixed3 rgb)
@@ -55,30 +63,56 @@ 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);
return c;
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);
fixed4 color = lerp(screen, cursor, cursor.a);
uddConvertToLinearIfNeeded(color.rgb);
return color;
uv = uddInvertUV(uv);
#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;
}
inline void uddBendVertex(inout float4 v, half radius, half width, half thickness)
{
#ifdef BEND_ON
half angle = width * v.x / radius;
#ifdef _FORWARD_Z
v.y *= thickness;
radius -= v.y;
v.y += radius * (1 - cos(angle));
#elif _FORWARD_Y
v.z *= thickness;
radius -= v.z;
v.z += radius * (1 - cos(angle));
#endif
v.x = radius * sin(angle) / width;
#else
#ifdef _FORWARD_Z
v.y *= thickness;
#elif _FORWARD_Y
v.z *= thickness;
#endif
#endif
}
#endif

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
#define SURFACE_SHADER
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
half _Glossiness;
half _Metallic;
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,11 @@ 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(Y, Z)] _Forward("Mesh Forward Direction", Int) = 0
[Toggle(BEND_ON)] _Bend("Use Bend", Int) = 0
[PowerSlider(10.0)] _Radius("Bend Radius", Range(1, 100)) = 30
[PowerSlider(10.0)] _Thickness("Thickness", Range(0.01, 10)) = 1
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
}
@@ -20,18 +23,15 @@ Cull [_Cull]
CGINCLUDE
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
fixed _Radius;
half _Radius;
half _Width;
half _Thickness;
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
uddBendVertex(v.vertex, _Radius, _Width, _Thickness);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
@@ -39,7 +39,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 +51,10 @@ 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_ON
#pragma multi_compile _FORWARD_Y _FORWARD_Z
ENDCG
}

View File

@@ -6,6 +6,11 @@ Properties
_Color ("Color", Color) = (1, 1, 1, 1)
_MainTex ("Texture", 2D) = "white" {}
_Mask ("Mask", Range(0, 1)) = 0.1
_CursorTex ("Cursor Texture", 2D) = "white" {}
[KeywordEnum(Y, Z)] _Forward("Mesh Forward Direction", Int) = 0
[Toggle(BEND_ON)] _Bend("Use Bend", Int) = 0
[PowerSlider(10.0)] _Radius("Bend Radius", Range(1, 100)) = 30
[PowerSlider(10.0)] _Thickness("Thickness", Range(0.01, 10)) = 1
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
}
@@ -21,13 +26,16 @@ Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
fixed _Mask;
half _Radius;
half _Width;
half _Thickness;
v2f vert(appdata v)
{
v2f o;
uddBendVertex(v.vertex, _Radius, _Width, _Thickness);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
@@ -35,23 +43,25 @@ v2f vert(appdata v)
fixed4 frag(v2f i) : SV_Target
{
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);
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);
}
ENDCG
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ VERTICAL
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile ___ INVERT_X
#pragma multi_compile ___ INVERT_Y
#pragma multi_compile ___ ROTATE90 ROTATE180 ROTATE270
ENDCG
#pragma multi_compile ___ USE_BEND
#pragma multi_compile ___ USE_CLIP
#pragma multi_compile _BEND_OFF _BEND_Y _BEND_Z
ENDCG
}
}

View File

@@ -5,6 +5,11 @@ Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
_MainTex ("Texture", 2D) = "white" {}
_CursorTex ("Cursor Texture", 2D) = "white" {}
[KeywordEnum(Y, Z)] _Forward("Mesh Forward Direction", Int) = 0
[Toggle(BEND_ON)] _Bend("Use Bend", Int) = 0
[PowerSlider(10.0)] _Radius("Bend Radius", Range(1, 100)) = 30
[PowerSlider(10.0)] _Thickness("Thickness", Range(0.01, 10)) = 1
[KeywordEnum(Off, Front, Back)] _Cull("Culling", Int) = 2
}
@@ -20,11 +25,15 @@ Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#include "./uDD_Common.cginc"
#include "./uDD_Params.cginc"
half _Radius;
half _Width;
half _Thickness;
v2f vert(appdata v)
{
v2f o;
uddBendVertex(v.vertex, _Radius, _Width, _Thickness);
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
@@ -32,7 +41,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 +53,10 @@ 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
#pragma multi_compile _BEND_OFF _BEND_Y _BEND_Z
ENDCG
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include <queue>
#include <unordered_map>
#include <iostream>
#include <d3d11.h>
#include "IUnityInterface.h"
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
extern IUnityInterfaces* g_unity;
extern std::unique_ptr<MonitorManager> g_manager;
extern 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);
}

View File

@@ -1,15 +1,28 @@
#pragma once
#include <memory>
#include "IUnityInterface.h"
#include <string>
#include <functional>
class MonitorManager;
// Unity interface and ID3D11Device getters
struct IUnityInterfaces;
IUnityInterfaces* GetUnity();
struct ID3D11Device;
ID3D11Device* GetDevice();
// Manager getter
class MonitorManager;
const std::unique_ptr<MonitorManager>& GetMonitorManager();
// Message is pooled and fetch from Unity.
enum class Message
{
None = -1,
Reinitialized = 0,
None = -1,
Reinitialized = 0,
};
void SendMessageToUnity(Message message);

View File

@@ -1,9 +1,13 @@
#include <d3d11.h>
#include <wrl/client.h>
#include "Common.h"
#include "Debug.h"
#include "MonitorManager.h"
#include "Monitor.h"
#include "Cursor.h"
using namespace Microsoft::WRL;
Cursor::Cursor(Monitor* monitor)
: monitor_(monitor)
@@ -13,80 +17,128 @@ Cursor::Cursor(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)
void Cursor::UpdateBuffer(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
{
isVisible_ = frameInfo.PointerPosition.Visible != 0;
x_ = frameInfo.PointerPosition.Position.x;
y_ = frameInfo.PointerPosition.Position.y;
if (frameInfo.LastMouseUpdateTime.QuadPart == 0)
{
return;
}
// TODO: see more information to check where the cursor is.
if (isVisible_)
isVisible_ = frameInfo.PointerPosition.Visible != 0;
if (isVisible_)
{
GetMonitorManager()->SetCursorMonitorId(monitor_->GetId());
}
if (GetMonitorManager()->GetCursorMonitorId() != monitor_->GetId()) {
x_ = frameInfo.PointerPosition.Position.x;
y_ = frameInfo.PointerPosition.Position.y;
timestamp_ = frameInfo.LastMouseUpdateTime;
if (!IsCursorOnParentMonitor())
{
return;
}
if (frameInfo.PointerShapeBufferSize == 0)
{
return;
}
// Increase the buffer size if needed
if (frameInfo.PointerShapeBufferSize > apiBufferSize_)
{
if (apiBuffer_) delete[] apiBuffer_;
apiBuffer_ = new BYTE[frameInfo.PointerShapeBufferSize];
apiBufferSize_ = frameInfo.PointerShapeBufferSize;
apiBuffer_ = std::make_unique<BYTE[]>(apiBufferSize_);
}
if (apiBuffer_ == nullptr) return;
if (!apiBuffer_) return;
// Get information about the mouse pointer if needed
if (frameInfo.PointerShapeBufferSize != 0)
// Get mouse pointer information
UINT bufferSize;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
const auto hr = monitor_->GetDeskDupl()->GetFramePointerShape(
apiBufferSize_,
reinterpret_cast<void*>(apiBuffer_.get()),
&bufferSize,
&shapeInfo);
if (FAILED(hr))
{
UINT bufferSize;
monitor_->GetDeskDupl()->GetFramePointerShape(
frameInfo.PointerShapeBufferSize,
reinterpret_cast<void*>(apiBuffer_),
&bufferSize,
&shapeInfo_);
Debug::Error("Cursor::UpdateBuffer() => GetFramePointerShape() failed.");
apiBuffer_.reset();
apiBufferSize_ = 0;
}
shapeInfo_ = shapeInfo;
}
void Cursor::UpdateTexture()
{
if (!IsCursorOnParentMonitor())
{
return;
}
// 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 w0 = GetWidth();
const auto h0 = GetHeight();
const auto p = GetPitch();
auto w = w0;
auto h = h0;
// Convert the buffer given by API into BGRA32
const auto bgraBufferSize = w * h * 4;
const UINT bgraBufferSize = w0 * h0 * 4;
if (bgraBufferSize > bgra32BufferSize_)
{
if (bgra32Buffer_) delete[] bgra32Buffer_;
bgra32Buffer_ = new BYTE[bgraBufferSize];
bgra32BufferSize_ = bgraBufferSize;
bgra32Buffer_ = std::make_unique<BYTE[]>(bgra32BufferSize_);
}
if (bgra32Buffer_ == nullptr) return;
if (!bgra32Buffer_) return;
// If masked, copy the desktop image and merge it with masked image.
if (isMono || isColorMask)
{
HRESULT hr;
const auto mw = monitor_->GetWidth();
const auto mh = monitor_->GetHeight();
auto x = x_;
auto y = y_;
auto colMin = 0;
auto colMax = w0;
auto rowMin = 0;
auto rowMax = h0;
if (x < 0)
{
x = 0;
w = w0 + x_;
colMin = w0 - w;
}
if (x + w >= mw)
{
w = mw - x_;
colMax = w;
}
if (y < 0)
{
y = 0;
h = h0 + y_;
rowMin = h0 - h;
}
if (y + h >= mh)
{
h = mh - y_;
rowMax = h;
}
D3D11_TEXTURE2D_DESC desc;
desc.Width = w;
desc.Height = h;
@@ -100,31 +152,39 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
ID3D11Texture2D* texture = nullptr;
ComPtr<ID3D11Texture2D> texture;
hr = GetDevice()->CreateTexture2D(&desc, nullptr, &texture);
if (FAILED(hr))
{
Debug::Error("Cursor::UpdateTexture() => GetDevice()->CreateTexture2D() failed.");
return;
}
D3D11_BOX box;
box.front = 0;
box.back = 1;
box.left = x_;
box.top = y_;
box.right = x_ + w;
box.bottom = y_ + h;
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();
if (monitor_->GetUnityTexture() == nullptr)
{
Debug::Error("Cursor::UpdateTexture() => Monitor::GetUnityTexture() is null.");
return;
}
IDXGISurface* surface = nullptr;
hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&surface);
texture->Release();
{
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->CopySubresourceRegion(texture.Get(), 0, 0, 0, 0, monitor_->GetUnityTexture(), 0, &box);
}
ComPtr<IDXGISurface> surface;
hr = texture.As<IDXGISurface>(&surface);
if (FAILED(hr))
{
Debug::Error("Cursor::UpdateTexture() => texture->QueryInterface() failed.");
return;
}
@@ -132,7 +192,7 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
hr = surface->Map(&mappedSurface, DXGI_MAP_READ);
if (FAILED(hr))
{
surface->Release();
Debug::Error("Cursor::UpdateTexture() => surface->Map() failed.");
return;
}
@@ -141,40 +201,39 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
const UINT desktopPitch = mappedSurface.Pitch / sizeof(UINT);
// Access RGBA values at the same time
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_);
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
if (isMono)
{
for (UINT row = 0; row < h; ++row)
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
BYTE mask = 0x80;
for (UINT col = 0; col < w; ++col)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = row * w + col;
BYTE mask = 0b10000000 >> (col % 8);
const int i = row * w0 + 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);
const UINT andMask32 = andMask ? 0xFFFFFFFF : 0x00000000;
const UINT xorMask32 = xorMask ? 0xFFFFFFFF : 0x00000000;
output32[i] = (desktop32[y * desktopPitch + x] & andMask32) ^ xorMask32;
}
}
}
else // DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
{
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_);
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
for (UINT row = 0; row < h; ++row)
for (int row = rowMin, y = 0; row < rowMax; ++row, ++y)
{
for (UINT col = 0; col < w; ++col)
for (int col = colMin, x = 0; col < colMax; ++col, ++x)
{
const int i = row * w + col;
const int j = row * p / sizeof(UINT) + col;
const int i = col + row * w0;
const int j = col + row * p / sizeof(UINT);
UINT mask = 0xFF000000 & buffer32[j];
if (mask)
{
output32[i] = (desktop32[row * desktopPitch + col] ^ buffer32[j]) | 0xFF000000;
output32[i] = (desktop32[y * desktopPitch + x] ^ buffer32[j]) | 0xFF000000;
}
else
{
@@ -185,7 +244,6 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
}
hr = surface->Unmap();
surface->Release();
if (FAILED(hr))
{
return;
@@ -193,25 +251,46 @@ void Cursor::Update(const DXGI_OUTDUPL_FRAME_INFO& frameInfo)
}
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)
auto output32 = reinterpret_cast<UINT*>(bgra32Buffer_.get());
const auto buffer32 = reinterpret_cast<UINT*>(apiBuffer_.get());
for (int i = 0; i < w * h; ++i)
{
output32[i] = buffer32[i];
}
}
return;
}
void Cursor::UpdateTexture(ID3D11Texture2D* texture)
void Cursor::GetTexture(ID3D11Texture2D* texture)
{
if (bgra32Buffer_ == nullptr) return;
ID3D11DeviceContext* context;
if (bgra32Buffer_ == nullptr)
{
Debug::Error("Cursor::GetTexture() => bgra32Buffer is null.");
return;
}
if (texture == nullptr)
{
Debug::Error("Cursor::GetTexture() => The given texture is null.");
return;
}
D3D11_TEXTURE2D_DESC desc;
texture->GetDesc(&desc);
if ((int)desc.Width < GetWidth() || (int)desc.Height < GetHeight())
{
char buf[256];
sprintf_s(buf, 256,
"Cursor::GetTexture() => The given texture has smaller width / height.\n"
"Given => (%d, %d) Buffer => (%d, %d)",
desc.Width, desc.Height, GetWidth(), GetHeight());
Debug::Error(buf);
return;
}
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_, shapeInfo_.Width * 4, 0);
context->Release();
context->UpdateSubresource(texture, 0, nullptr, bgra32Buffer_.get(), GetWidth() * 4, 0);
}
@@ -257,3 +336,9 @@ int Cursor::GetType() const
{
return shapeInfo_.Type;
}
bool Cursor::IsCursorOnParentMonitor() const
{
return GetMonitorManager()->GetCursorMonitorId() == monitor_->GetId();
}

View File

@@ -1,3 +1,5 @@
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <memory>
@@ -9,8 +11,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;
@@ -21,13 +24,16 @@ public:
int GetType() const;
private:
bool IsCursorOnParentMonitor() const;
Monitor* monitor_;
bool isVisible_ = false;
int x_ = -1;
int y_ = -1;
BYTE* apiBuffer_ = nullptr;
std::unique_ptr<BYTE[]> apiBuffer_ = nullptr;
UINT apiBufferSize_ = 0;
BYTE* bgra32Buffer_ = nullptr;
std::unique_ptr<BYTE[]> bgra32Buffer_ = nullptr;
UINT bgra32BufferSize_ = 0;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo_;
LARGE_INTEGER timestamp_;
};

View File

@@ -0,0 +1,31 @@
#pragma once
#include <cstdio>
#include "Debug.h"
decltype(Debug::mode_) Debug::mode_ = Debug::Mode::File;
decltype(Debug::logFunc_) Debug::logFunc_ = nullptr;
decltype(Debug::errFunc_) Debug::errFunc_ = nullptr;
decltype(Debug::fs_) Debug::fs_;
decltype(Debug::ss_) Debug::ss_;
void Debug::Initialize()
{
if (mode_ == Mode::File)
{
fs_.open("uDesktopDuplication.log");
Debug::Log("Start");
}
}
void Debug::Finalize()
{
if (mode_ == Mode::File)
{
Debug::Log("Stop");
fs_.close();
}
}

View File

@@ -0,0 +1,110 @@
#pragma once
#include <fstream>
#include <sstream>
#include "IUnityInterface.h"
// Logging
class Debug
{
public:
enum class Mode
{
None = 0,
File = 1,
UnityLog = 2,
};
using DebugLogFuncPtr = void(UNITY_INTERFACE_API *)(const char*);
static void SetMode(Mode mode) { mode_ = mode; }
static void Initialize();
static void Finalize();
static void SetLogFunc(DebugLogFuncPtr func) { logFunc_ = func; }
static void SetErrorFunc(DebugLogFuncPtr func) { errFunc_ = func; }
private:
enum class Level
{
Log,
Error
};
template <class T>
static void Output(T&& arg)
{
if (mode_ == Mode::None) return;
if (ss_.good())
{
ss_ << std::forward<T>(arg);
}
}
static void Flush(Level level)
{
switch (mode_)
{
case Mode::None:
{
return;
}
case Mode::File:
{
if (fs_.good() && ss_.good())
{
const auto str = ss_.str();
fs_ << str << std::endl;
fs_.flush();
}
break;
}
case Mode::UnityLog:
{
if (ss_.good())
{
switch (level)
{
case Level::Log : logFunc_(ss_.str().c_str()); break;
case Level::Error : errFunc_(ss_.str().c_str()); break;
}
}
break;
}
}
ss_.str("");
ss_.clear(std::stringstream::goodbit);
}
template <class Arg, class... RestArgs>
static void _Log(Level level, Arg&& arg, RestArgs&&... restArgs)
{
Output(std::forward<Arg>(arg));
_Log(level, std::forward<RestArgs>(restArgs)...);
}
static void _Log(Level level)
{
Flush(level);
}
public:
template <class Arg, class... RestArgs>
static void Log(Arg&& arg, RestArgs&&... restArgs)
{
Output("[uDD::Log] ");
_Log(Level::Log, std::forward<Arg>(arg), std::forward<RestArgs>(restArgs)...);
}
template <class Arg, class... RestArgs>
static void Error(Arg&& arg, RestArgs&&... restArgs)
{
Output("[uDD::Err] ");
_Log(Level::Error, std::forward<Arg>(arg), std::forward<RestArgs>(restArgs)...);
}
private:
static Mode mode_;
static std::ofstream fs_;
static std::ostringstream ss_;
static DebugLogFuncPtr logFunc_;
static DebugLogFuncPtr errFunc_;
};

View File

@@ -1,95 +1,148 @@
#include <d3d11.h>
#include <ShellScalingAPI.h>
#include "Common.h"
#include "Debug.h"
#include "Cursor.h"
#include "MonitorManager.h"
#include "Monitor.h"
using namespace Microsoft::WRL;
Monitor::Monitor(int id, IDXGIOutput* output)
Monitor::Monitor(int id)
: id_(id)
, cursor_(std::make_unique<Cursor>(this))
{
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)
void Monitor::Initialize(IDXGIOutput* output)
{
if (deskDupl_ == nullptr)
{
GetMonitorManager()->RequireReinitilization();
return 0;
}
output->GetDesc(&outputDesc_);
monitorInfo_.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(outputDesc_.Monitor, &monitorInfo_);
if (unityTexture_ == nullptr) return 0;
GetDpiForMonitor(outputDesc_.Monitor, MDT_RAW_DPI, &dpiX_, &dpiY_);
IDXGIResource* resource = nullptr;
auto output1 = reinterpret_cast<IDXGIOutput1*>(output);
const auto hr = output1->DuplicateOutput(GetDevice(), &deskDupl_);
// TODO: error check
switch (hr)
{
case S_OK:
state_ = State::Available;
Debug::Log("Monitor::Initialize() => OK.");
Debug::Log(" ID : ", GetId());
Debug::Log(" Size : (", GetWidth(), ", ", GetHeight(), ")");
Debug::Log(" DPI : (", GetDpiX(), ", ", GetDpiY(), ")");
break;
case E_INVALIDARG:
state_ = State::InvalidArg;
Debug::Error("Monitor::Initialize() => Invalid arguments.");
break;
case E_ACCESSDENIED:
// For example, when the user presses Ctrl + Alt + Delete and the screen
// switches to admin screen, this error occurs.
state_ = State::AccessDenied;
Debug::Error("Monitor::Initialize() => Access denied.");
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;
Debug::Error("Monitor::Initialize() => Unsupported display.");
break;
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
// When other application use Desktop Duplication API, this error occurs.
state_ = State::CurrentlyNotAvailable;
Debug::Error("Monitor::Initialize() => Currently not available.");
break;
case DXGI_ERROR_SESSION_DISCONNECTED:
state_ = State::SessionDisconnected;
Debug::Error("Monitor::Initialize() => Session disconnected.");
break;
default:
state_ = State::Unknown;
Debug::Error("Monitor::Render() => Unknown Error.");
break;
}
}
void Monitor::Render(UINT timeout)
{
if (!deskDupl_) return;
ComPtr<IDXGIResource> resource;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
HRESULT hr;
const auto hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
hr = deskDupl_->AcquireNextFrame(timeout, &frameInfo, &resource);
if (FAILED(hr))
{
return 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.
Debug::Log("Monitor::Render() => DXGI_ERROR_ACCESS_LOST.");
state_ = State::AccessLost;
break;
case DXGI_ERROR_WAIT_TIMEOUT:
// This often occurs when timeout value is small and it is not problem.
// Debug::Log("Monitor::Render() => DXGI_ERROR_WAIT_TIMEOUT.");
break;
case DXGI_ERROR_INVALID_CALL:
Debug::Error("Monitor::Render() => DXGI_ERROR_INVALID_CALL.");
break;
case E_INVALIDARG:
Debug::Error("Monitor::Render() => E_INVALIDARG.");
break;
default:
state_ = State::Unknown;
Debug::Error("Monitor::Render() => Unknown Error.");
break;
}
return;
}
ID3D11Texture2D* texture;
resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
if (unityTexture_)
{
ComPtr<ID3D11Texture2D> texture;
resource.As<ID3D11Texture2D>(&texture);
ID3D11DeviceContext* context;
GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture);
context->Release();
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
texture->GetDesc(&srcDesc);
texture->GetDesc(&dstDesc);
if (srcDesc.Width != dstDesc.Width ||
srcDesc.Height != dstDesc.Height)
{
Debug::Error("Monitor::Render() => Texture sizes are defferent.");
Debug::Error(" Source : (", srcDesc.Width, ", ", srcDesc.Height, ")");
Debug::Error(" Dest : (", dstDesc.Width, ", ", dstDesc.Height, ")");
}
else
{
ComPtr<ID3D11DeviceContext> context;
GetDevice()->GetImmediateContext(&context);
context->CopyResource(unityTexture_, texture.Get());
}
}
cursor_->Update(frameInfo);
cursor_->UpdateBuffer(frameInfo);
cursor_->UpdateTexture();
resource->Release();
deskDupl_->ReleaseFrame();
return 0;
hr = deskDupl_->ReleaseFrame();
if (FAILED(hr))
{
Debug::Error("Monitor::Render() => ReleaseFrame() failed.");
}
}
@@ -99,6 +152,12 @@ int Monitor::GetId() const
}
MonitorState Monitor::GetState() const
{
return state_;
}
void Monitor::SetUnityTexture(ID3D11Texture2D* texture)
{
unityTexture_ = texture;
@@ -111,7 +170,7 @@ ID3D11Texture2D* Monitor::GetUnityTexture() const
}
IDXGIOutputDuplication* Monitor::GetDeskDupl()
const ComPtr<IDXGIOutputDuplication>& Monitor::GetDeskDupl()
{
return deskDupl_;
}
@@ -123,9 +182,9 @@ const std::unique_ptr<Cursor>& Monitor::GetCursor()
}
void Monitor::UpdateCursorTexture(ID3D11Texture2D* texture)
void Monitor::GetCursorTexture(ID3D11Texture2D* texture)
{
cursor_->UpdateTexture(texture);
cursor_->GetTexture(texture);
}
@@ -143,31 +202,43 @@ bool Monitor::IsPrimary() const
int Monitor::GetLeft() const
{
return outputDesc_.DesktopCoordinates.left;
return static_cast<int>(outputDesc_.DesktopCoordinates.left);
}
int Monitor::GetRight() const
{
return outputDesc_.DesktopCoordinates.right;
return static_cast<int>(outputDesc_.DesktopCoordinates.right);
}
int Monitor::GetTop() const
{
return outputDesc_.DesktopCoordinates.top;
return static_cast<int>(outputDesc_.DesktopCoordinates.top);
}
int Monitor::GetBottom() const
{
return outputDesc_.DesktopCoordinates.bottom;
return static_cast<int>(outputDesc_.DesktopCoordinates.bottom);
}
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

@@ -1,37 +1,61 @@
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <wrl/client.h>
#include <memory>
class Cursor;
enum class MonitorState
{
NotSet = -1,
Available = 0,
InvalidArg = 1,
AccessDenied = 2,
Unsupported = 3,
CurrentlyNotAvailable = 4,
SessionDisconnected = 5,
AccessLost = 6,
Unknown = 999,
};
class Monitor
{
public:
Monitor(int id, IDXGIOutput* output);
using State = MonitorState;
explicit Monitor(int id);
~Monitor();
HRESULT Render(UINT timeout = 0);
void UpdateCursorTexture(ID3D11Texture2D* texture);
void Initialize(IDXGIOutput* output);
void Render(UINT timeout = 0);
void GetCursorTexture(ID3D11Texture2D* texture);
public:
int GetId() 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;
IDXGIOutputDuplication* GetDeskDupl();
int GetRotation() const;
int GetDpiX() const;
int GetDpiY() const;
const Microsoft::WRL::ComPtr<IDXGIOutputDuplication>& GetDeskDupl();
const std::unique_ptr<Cursor>& GetCursor();
private:
int id_ = -1;
UINT dpiX_ = -1, dpiY_ = -1;
State state_ = State::NotSet;
std::unique_ptr<Cursor> cursor_;
IDXGIOutputDuplication* deskDupl_ = nullptr;
Microsoft::WRL::ComPtr<IDXGIOutputDuplication> deskDupl_;
ID3D11Texture2D* unityTexture_ = nullptr;
DXGI_OUTPUT_DESC outputDesc_;
MONITORINFOEX monitorInfo_;

View File

@@ -1,5 +1,6 @@
#include <d3d11.h>
#include <dxgi1_2.h>
#include <wrl/client.h>
#include <vector>
#include <string>
#include <algorithm>
@@ -8,10 +9,13 @@
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
#include "Debug.h"
#include "Monitor.h"
#include "Cursor.h"
#include "MonitorManager.h"
using namespace Microsoft::WRL;
MonitorManager::MonitorManager()
{
@@ -30,25 +34,23 @@ void MonitorManager::Initialize()
Finalize();
// Get factory
IDXGIFactory1* factory;
CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));
ComPtr<IDXGIFactory1> factory;
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
// Check all display adapters
int id = 0;
IDXGIAdapter1* adapter;
ComPtr<IDXGIAdapter1> adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
// Search the main monitor from all outputs
IDXGIOutput* output;
ComPtr<IDXGIOutput> output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{
auto monitor = std::make_shared<Monitor>(id++, output);
auto monitor = std::make_shared<Monitor>(id++);
monitor->Initialize(output.Get());
monitors_.push_back(monitor);
output->Release();
}
adapter->Release();
}
factory->Release();
}
@@ -58,10 +60,41 @@ void MonitorManager::Finalize()
}
void MonitorManager::RequireReinitilization()
{
isReinitializationRequired_ = true;
}
void MonitorManager::Reinitialize()
{
Initialize();
SendMessageToUnity(Message::Reinitialized);
Debug::Log("MonitorManager::Reinitialize()");
Initialize();
SendMessageToUnity(Message::Reinitialized);
}
void MonitorManager::CheckMonitorNumbers()
{
ComPtr<IDXGIFactory1> factory;
CreateDXGIFactory1(IID_PPV_ARGS(&factory));
int id = 0;
ComPtr<IDXGIAdapter1> adapter;
for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
{
ComPtr<IDXGIOutput> output;
for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); ++j)
{
id++;
}
}
if (GetMonitorCount() != id)
{
Debug::Log("Monitor number changed: ", GetMonitorCount(), " => ", id);
RequireReinitilization();
}
}
@@ -77,34 +110,12 @@ std::shared_ptr<Monitor> MonitorManager::GetMonitor(int id) const
void MonitorManager::Update()
{
if (isReinitializationRequired_)
{
Reinitialize();
isReinitializationRequired_ = false;
}
}
CheckMonitorNumbers();
void MonitorManager::OnRender(int id)
{
if (auto monitor = GetMonitor(id))
if (isReinitializationRequired_)
{
// 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);
Reinitialize();
isReinitializationRequired_ = false;
}
}
@@ -115,13 +126,9 @@ void MonitorManager::SetTimeout(int timeout)
}
void MonitorManager::SetTexturePtr(int id, void* texture)
int MonitorManager::GetTimeout() const
{
if (auto monitor = GetMonitor(id))
{
auto d3d11Texture = reinterpret_cast<ID3D11Texture2D*>(texture);
monitor->SetUnityTexture(d3d11Texture);
}
return timeout_;
}
@@ -132,185 +139,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;
}
void MonitorManager::GetName(int id, char* buf, int len) const
{
if (auto monitor = GetMonitor(id))
std::vector<int> tops, bottoms;
for (const auto& monitor : monitors_)
{
monitor->GetName(buf, len);
tops.push_back(monitor->GetTop());
bottoms.push_back(monitor->GetBottom());
}
}
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;
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

@@ -1,3 +1,5 @@
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <vector>
@@ -13,9 +15,9 @@ class MonitorManager
public:
explicit MonitorManager();
~MonitorManager();
void RequireReinitilization() { isReinitializationRequired_ = true; }
void Reinitialize();
void CheckMonitorNumbers();
void RequireReinitilization();
void SetCursorMonitorId(int id) { cursorMonitorId_ = id; }
int GetCursorMonitorId() const { return cursorMonitorId_; }
std::shared_ptr<Monitor> GetMonitor(int id) const;
@@ -23,42 +25,23 @@ public:
private:
void Initialize();
void Finalize();
void Reinitialize();
// Setters from Unity
public:
void OnRender(int id);
void Update();
void UpdateCursorTexture(int id, ID3D11Texture2D* ptr);
void Update();
void SetTimeout(int timeout);
void SetTexturePtr(int id, void* texture);
int GetTimeout() const;
// 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;
bool isReinitializationRequired_ = false;
};

View File

@@ -7,77 +7,67 @@
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
#include "IUnityGraphicsD3D11.h"
#include "Common.h"
#include "Debug.h"
#include "Monitor.h"
#include "Cursor.h"
#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;
}
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);
}
IUnityInterfaces* g_unity = nullptr;
std::unique_ptr<MonitorManager> g_manager;
std::queue<Message> g_messages;
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)
{
Debug::Initialize();
g_manager = std::make_unique<MonitorManager>();
}
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API FinalizeUDD()
{
g_manager.reset();
if (g_manager)
{
g_manager.reset();
std::queue<Message> empty;
g_messages.swap(empty);
Debug::SetLogFunc(nullptr);
Debug::SetErrorFunc(nullptr);
Debug::Finalize();
}
}
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();
FinalizeUDD();
g_unity = nullptr;
}
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()
@@ -85,150 +75,286 @@ 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 UNITY_INTERFACE_API PopMessage()
{
if (g_messages.empty()) return Message::None;
const auto message = g_messages.front();
g_messages.pop();
return message;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetDebugMode(Debug::Mode mode)
{
Debug::SetMode(mode);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetLogFunc(Debug::DebugLogFuncPtr func)
{
Debug::SetLogFunc(func);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetErrorFunc(Debug::DebugLogFuncPtr func)
{
Debug::SetErrorFunc(func);
}
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 void UNITY_INTERFACE_API GetId(int id)
{
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
monitor->GetId();
}
}
UNITY_INTERFACE_EXPORT MonitorState UNITY_INTERFACE_API GetState(int id)
{
if (!g_manager) return MonitorState::NotSet;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetState();
}
return MonitorState::NotSet;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetName(int id, char* buf, int len)
{
if (!g_manager) return;
g_manager->GetName(id, buf, len);
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
monitor->GetName(buf, len);
}
}
UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsPrimary(int id)
{
if (!g_manager) return false;
return g_manager->IsPrimary(id);
if (!g_manager) return false;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->IsPrimary();
}
return false;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetLeft(int id)
{
if (!g_manager) return -1;
return g_manager->GetLeft(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetLeft();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetRight(int id)
{
if (!g_manager) return -1;
return g_manager->GetRight(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetRight();
}
return 0;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetTop(int id)
{
if (!g_manager) return -1;
return g_manager->GetTop(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetTop();
}
return 0;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetBottom(int id)
{
if (!g_manager) return -1;
return g_manager->GetBottom(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetBottom();
}
return 0;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetWidth(int id)
{
if (!g_manager) return -1;
return g_manager->GetWidth(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetWidth();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetHeight(int id)
{
if (!g_manager) return -1;
return g_manager->GetHeight(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetHeight();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetRotation(int id)
{
if (!g_manager) return -1;
return g_manager->GetRotation(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetRotation();
}
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;
return g_manager->IsCursorVisible(id);
if (!g_manager) return false;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->IsVisible();
}
return false;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorX(int id)
{
if (!g_manager) return -1;
return g_manager->GetCursorX(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->GetX();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorY(int id)
{
if (!g_manager) return -1;
return g_manager->GetCursorY(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->GetY();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeWidth(int id)
{
if (!g_manager) return -1;
return g_manager->GetCursorShapeWidth(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->GetWidth();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeHeight(int id)
{
if (!g_manager) return -1;
return g_manager->GetCursorShapeHeight(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->GetHeight();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapePitch(int id)
{
if (!g_manager) return -1;
return g_manager->GetCursorShapePitch(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->GetPitch();
}
return -1;
}
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API GetCursorShapeType(int id)
{
if (!g_manager) return -1;
return g_manager->GetCursorShapeType(id);
if (!g_manager) return -1;
if (auto monitor = g_manager->GetMonitor(id))
{
return monitor->GetCursor()->GetType();
}
return -1;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API UpdateCursorTexture(int id, ID3D11Texture2D* ptr)
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API GetCursorTexture(int id, ID3D11Texture2D* texture)
{
if (!g_manager) return;
g_manager->UpdateCursorTexture(id, ptr);
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
monitor->GetCursorTexture(texture);
}
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetTexturePtr(int id, void* texture)
{
if (!g_manager) return;
g_manager->SetTexturePtr(id, texture);
if (!g_manager) return;
if (auto monitor = g_manager->GetMonitor(id))
{
auto d3d11Texture = reinterpret_cast<ID3D11Texture2D*>(texture);
monitor->SetUnityTexture(d3d11Texture);
}
}
}

View File

@@ -89,7 +89,7 @@
<SDLCheck>true</SDLCheck>
</ClCompile>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins"</Command>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -122,10 +122,12 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins"</Command>
<Command>copy /Y "$(SolutionDir)$(Platform)\$(Configuration)\$(TargetFileName)" "$(SolutionDir)..\..\Assets\$(ProjectName)\Plugins\x86_64"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Common.cpp" />
<ClCompile Include="Debug.cpp" />
<ClCompile Include="MonitorManager.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Monitor.cpp" />
@@ -133,6 +135,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="Common.h" />
<ClInclude Include="Debug.h" />
<ClInclude Include="MonitorManager.h" />
<ClInclude Include="include\IUnityGraphics.h" />
<ClInclude Include="include\IUnityGraphicsD3D11.h" />

View File

@@ -19,11 +19,14 @@
<ClInclude Include="Cursor.h" />
<ClInclude Include="Common.h" />
<ClInclude Include="MonitorManager.h" />
<ClInclude Include="Debug.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Monitor.cpp" />
<ClCompile Include="Cursor.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MonitorManager.cpp" />
<ClCompile Include="Common.cpp" />
<ClCompile Include="Debug.cpp" />
</ItemGroup>
</Project>