Skip to content

Commit

Permalink
Ability to specify overlay via interface API
Browse files Browse the repository at this point in the history
 * CaptureInterface.DrawOverlay added
 * D3D9 image supports scale and rotation
 * D3D9 image load from memory support added

Fixes #36, #10
  • Loading branch information
justinstenning committed Feb 21, 2018
1 parent a09f39e commit 3250f25
Show file tree
Hide file tree
Showing 16 changed files with 284 additions and 169 deletions.
1 change: 1 addition & 0 deletions Capture/Capture.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<Compile Include="Hook\Hook.cs" />
<Compile Include="Hook\HookManager.cs" />
<Compile Include="Hook\TextDisplay.cs" />
<Compile Include="Interface\DrawOverlayEventArgs.cs" />
<Compile Include="Interface\ScreenshotExtensions.cs" />
<Compile Include="Interface\CaptureConfig.cs" />
<Compile Include="EntryPoint.cs" />
Expand Down
16 changes: 16 additions & 0 deletions Capture/Hook/BaseDXHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ public BaseDXHook(CaptureInterface ssInterface)

Interface.ScreenshotRequested += InterfaceEventProxy.ScreenshotRequestedProxyHandler;
Interface.DisplayText += InterfaceEventProxy.DisplayTextProxyHandler;
Interface.DrawOverlay += InterfaceEventProxy.DrawOverlayProxyHandler;
InterfaceEventProxy.ScreenshotRequested += new ScreenshotRequestedEvent(InterfaceEventProxy_ScreenshotRequested);
InterfaceEventProxy.DisplayText += new DisplayTextEvent(InterfaceEventProxy_DisplayText);
InterfaceEventProxy.DrawOverlay += InterfaceEventProxy_DrawOverlay;
}

~BaseDXHook()
{
Dispose(false);
Expand All @@ -50,6 +53,14 @@ protected virtual void InterfaceEventProxy_ScreenshotRequested(ScreenshotRequest
this.Request = request;
}

private void InterfaceEventProxy_DrawOverlay(DrawOverlayEventArgs args)
{
Overlays = new List<Common.IOverlay>();
if (args.Overlay != null)
Overlays.Add(args.Overlay);
IsOverlayUpdatePending = true;
}

protected Stopwatch Timer { get; set; }

/// <summary>
Expand All @@ -59,6 +70,10 @@ protected virtual void InterfaceEventProxy_ScreenshotRequested(ScreenshotRequest

protected TextDisplay TextDisplay { get; set; }

protected List<Common.IOverlay> Overlays { get; set; }

protected bool IsOverlayUpdatePending { get; set; }

int _processId = 0;
protected int ProcessId
{
Expand Down Expand Up @@ -394,6 +409,7 @@ protected override void Dispose(bool disposeManagedResources)
// Remove the event handlers
Interface.ScreenshotRequested -= InterfaceEventProxy.ScreenshotRequestedProxyHandler;
Interface.DisplayText -= InterfaceEventProxy.DisplayTextProxyHandler;
Interface.DrawOverlay -= InterfaceEventProxy_DrawOverlay;
}
catch (RemotingException) { } // Ignore remoting exceptions (host process may have been closed)
}
Expand Down
20 changes: 1 addition & 19 deletions Capture/Hook/Common/Element.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Capture.Hook.Common
{
[Serializable]
public abstract class Element: MarshalByRefObject, IOverlayElement, IDisposable
public abstract class Element: IOverlayElement, IDisposable
{
public virtual bool Hidden { get; set; }

Expand Down Expand Up @@ -41,7 +41,6 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Disconnect();
}
}

Expand All @@ -50,22 +49,5 @@ protected void SafeDispose(IDisposable disposableObj)
if (disposableObj != null)
disposableObj.Dispose();
}

/// <summary>
/// Disconnects the remoting channel(s) of this object and all nested objects.
/// </summary>
private void Disconnect()
{
RemotingServices.Disconnect(this);
}

[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
// Returning null designates an infinite non-expiring lease.
// We must therefore ensure that RemotingServices.Disconnect() is called when
// it's no longer needed otherwise there will be a memory leak.
return null;
}
}
}
1 change: 1 addition & 0 deletions Capture/Hook/Common/FramesPerSecond.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace Capture.Hook.Common
{
[Serializable]
public class FramesPerSecond: TextElement
{
string _fpsFormat = "{0:N0} fps";
Expand Down
2 changes: 1 addition & 1 deletion Capture/Hook/Common/IOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Capture.Hook.Common
{
internal interface IOverlay: IOverlayElement
public interface IOverlay: IOverlayElement
{
List<IOverlayElement> Elements { get; set; }
}
Expand Down
32 changes: 27 additions & 5 deletions Capture/Hook/Common/ImageElement.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
using System;
using Capture.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Capture.Hook.Common
{
[Serializable]
public class ImageElement: Element
{
public virtual System.Drawing.Bitmap Bitmap { get; set; }

/// <summary>
/// The image file bytes
/// </summary>
public virtual byte[] Image { get; set; }

System.Drawing.Bitmap _bitmap = null;
internal virtual System.Drawing.Bitmap Bitmap {
get
{
if (_bitmap == null && Image != null)
{
_bitmap = Image.ToBitmap();
_ownsBitmap = true;
}

return _bitmap;
}
set { _bitmap = value; }
}

/// <summary>
/// This value is multiplied with the source color (e.g. White will result in same color as source image)
/// </summary>
/// <remarks>
/// Defaults to <see cref="System.Drawing.Color.White"/>.
/// </remarks>
public virtual System.Drawing.Color Tint { get; set; }
public virtual System.Drawing.Color Tint { get; set; } = System.Drawing.Color.White;

/// <summary>
/// The location of where to render this image element
Expand All @@ -24,12 +44,14 @@ public class ImageElement: Element

public float Angle { get; set; }

public float Scale { get; set; }
public float Scale { get; set; } = 1.0f;

public string Filename { get; set; }

bool _ownsBitmap = false;

public ImageElement() { }

public ImageElement(string filename):
this(new System.Drawing.Bitmap(filename), true)
{
Expand Down
1 change: 1 addition & 0 deletions Capture/Hook/Common/Overlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace Capture.Hook.Common
{
[Serializable]
public class Overlay: IOverlay
{
List<IOverlayElement> _elements = new List<IOverlayElement>();
Expand Down
9 changes: 6 additions & 3 deletions Capture/Hook/Common/TextElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@

namespace Capture.Hook.Common
{
[Serializable]
public class TextElement: Element
{
public virtual string Text { get; set; }
public virtual System.Drawing.Font Font { get; set; }
public virtual System.Drawing.Color Color { get; set; }
public virtual System.Drawing.Font Font { get; set; } = System.Drawing.SystemFonts.DefaultFont;
public virtual System.Drawing.Color Color { get; set; } = System.Drawing.Color.Black;
public virtual System.Drawing.Point Location { get; set; }
public virtual bool AntiAliased { get; set; }
public virtual bool AntiAliased { get; set; } = false;

public TextElement() { }

public TextElement(System.Drawing.Font font)
{
Expand Down
13 changes: 8 additions & 5 deletions Capture/Hook/DX11/DXOverlayEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public DXOverlayEngine()

private void EnsureInitiliased()
{
Debug.Assert(_initialised);
if (!_initialised)
throw new InvalidOperationException("DXOverlayEngine must be initialised.");
}

public bool Initialise(SharpDX.DXGI.SwapChain swapChain)
Expand All @@ -48,7 +49,6 @@ public bool Initialise(SharpDX.DXGI.SwapChain swapChain)

public bool Initialise(Device device, Texture2D renderTarget)
{
Debug.Assert(!_initialised);
if (_initialising)
return false;

Expand Down Expand Up @@ -82,7 +82,7 @@ public bool Initialise(Device device, Texture2D renderTarget)
return false;

// Initialise any resources required for overlay elements
IntialiseElementResources();
InitialiseElementResources();

_initialised = true;
return true;
Expand All @@ -93,7 +93,7 @@ public bool Initialise(Device device, Texture2D renderTarget)
}
}

private void IntialiseElementResources()
void InitialiseElementResources()
{
foreach (var overlay in Overlays)
{
Expand Down Expand Up @@ -135,6 +135,9 @@ public void Draw()

foreach (var overlay in Overlays)
{
if (overlay.Hidden)
continue;

foreach (var element in overlay.Elements)
{
if (element.Hidden)
Expand Down Expand Up @@ -175,7 +178,7 @@ DXFont GetFontForTextElement(TextElement element)
{
DXFont result = null;

string fontKey = String.Format("{0}{1}{2}", element.Font.Name, element.Font.Size, element.Font.Style, element.AntiAliased);
string fontKey = String.Format("{0}{1}{2}{3}", element.Font.Name, element.Font.Size, element.Font.Style, element.AntiAliased);

if (!_fontCache.TryGetValue(fontKey, out result))
{
Expand Down
22 changes: 21 additions & 1 deletion Capture/Hook/DX9/DXOverlayEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
Expand Down Expand Up @@ -114,9 +115,17 @@ public void Draw()
}
else if (imageElement != null)
{
//Apply the scaling of the imageElement
var rotation = Matrix.RotationZ(imageElement.Angle);
var scaling = Matrix.Scaling(imageElement.Scale);
_sprite.Transform = rotation * scaling;

Texture image = GetImageForImageElement(imageElement);
if (image != null)
_sprite.Draw(image, new SharpDX.ColorBGRA(imageElement.Tint.R, imageElement.Tint.G, imageElement.Tint.B, imageElement.Tint.A), null, null, new Vector3(imageElement.Location.X, imageElement.Location.Y, 0));

//Reset the transform for other elements
_sprite.Transform = Matrix.Identity;
}
}
}
Expand Down Expand Up @@ -149,7 +158,7 @@ Font GetFontForTextElement(TextElement element)
{
Font result = null;

string fontKey = String.Format("{0}{1}{2}", element.Font.Name, element.Font.Size, element.Font.Style, element.AntiAliased);
string fontKey = String.Format("{0}{1}{2}{3}", element.Font.Name, element.Font.Size, element.Font.Style, element.AntiAliased);

if (!_fontCache.TryGetValue(fontKey, out result))
{
Expand Down Expand Up @@ -178,6 +187,17 @@ Texture GetImageForImageElement(ImageElement element)
_imageCache[element] = result;
}
}
else if (!_imageCache.TryGetValue(element, out result) && element.Bitmap != null)
{
using (var ms = new MemoryStream())
{
element.Bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
result = ToDispose(Texture.FromStream(Device, ms));
}

_imageCache[element] = result;
}
return result;
}

Expand Down
21 changes: 9 additions & 12 deletions Capture/Hook/DXHookD3D11.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.IO;
using Capture.Interface;
using SharpDX.Direct3D;
using Capture.Hook.Common;

namespace Capture.Hook
{
Expand Down Expand Up @@ -508,30 +509,26 @@ int PresentHook(IntPtr swapChainPtr, int syncInterval, SharpDX.DXGI.PresentFlags
#endregion

#region Draw overlay (after screenshot so we don't capture overlay as well)
if (this.Config.ShowOverlay)
var displayOverlays = Overlays;
if (this.Config.ShowOverlay && displayOverlays != null)
{
// Initialise Overlay Engine
if (_swapChainPointer != swapChain.NativePointer || _overlayEngine == null)
if (_swapChainPointer != swapChain.NativePointer || _overlayEngine == null
|| IsOverlayUpdatePending)
{
if (_overlayEngine != null)
_overlayEngine.Dispose();

_overlayEngine = new DX11.DXOverlayEngine();
_overlayEngine.Overlays.Add(new Capture.Hook.Common.Overlay
{
Elements =
{
//new Capture.Hook.Common.TextElement(new System.Drawing.Font("Times New Roman", 22)) { Text = "Test", Location = new System.Drawing.Point(200, 200), Color = System.Drawing.Color.Yellow, AntiAliased = false},
new Capture.Hook.Common.FramesPerSecond(new System.Drawing.Font("Arial", 16)) { Location = new System.Drawing.Point(5,5), Color = System.Drawing.Color.Red, AntiAliased = true },
//new Capture.Hook.Common.ImageElement(@"C:\Temp\test.bmp") { Location = new System.Drawing.Point(20, 20) }
}
});
_overlayEngine.Overlays.AddRange((IEnumerable<IOverlay>)displayOverlays);
_overlayEngine.Initialise(swapChain);

_swapChainPointer = swapChain.NativePointer;

IsOverlayUpdatePending = false;
}
// Draw Overlay(s)
else if (_overlayEngine != null)
if (_overlayEngine != null)
{
foreach (var overlay in _overlayEngine.Overlays)
overlay.Frame();
Expand Down
Loading

0 comments on commit 3250f25

Please sign in to comment.