You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
7.2 KiB

  1. using RenderHookAPI.Hook.Common;
  2. using SharpDX;
  3. using SharpDX.Direct3D9;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IO;
  8. namespace RenderHookAPI.Hook.DX9
  9. {
  10. internal class DXOverlayEngine : Component
  11. {
  12. public List<IOverlay> Overlays { get; set; }
  13. bool _initialised = false;
  14. bool _initialising = false;
  15. Device _device;
  16. Sprite _sprite;
  17. Dictionary<string, Font> _fontCache = new Dictionary<string, Font>();
  18. Dictionary<Element, Texture> _imageCache = new Dictionary<Element, Texture>();
  19. public Device Device { get { return _device; } }
  20. public DXOverlayEngine()
  21. {
  22. Overlays = new List<IOverlay>();
  23. }
  24. private void EnsureInitiliased()
  25. {
  26. Debug.Assert(_initialised);
  27. }
  28. public bool Initialise(Device device)
  29. {
  30. Debug.Assert(!_initialised);
  31. if (_initialising)
  32. return false;
  33. _initialising = true;
  34. try
  35. {
  36. _device = device;
  37. _sprite = ToDispose(new Sprite(_device));
  38. // Initialise any resources required for overlay elements
  39. IntialiseElementResources();
  40. _initialised = true;
  41. return true;
  42. }
  43. finally
  44. {
  45. _initialising = false;
  46. }
  47. }
  48. private void IntialiseElementResources()
  49. {
  50. foreach (var overlay in Overlays)
  51. {
  52. foreach (var element in overlay.Elements)
  53. {
  54. var textElement = element as TextElement;
  55. var imageElement = element as ImageElement;
  56. if (textElement != null)
  57. {
  58. GetFontForTextElement(textElement);
  59. }
  60. else if (imageElement != null)
  61. {
  62. GetImageForImageElement(imageElement);
  63. }
  64. }
  65. }
  66. }
  67. private void Begin()
  68. {
  69. _sprite.Begin(SpriteFlags.AlphaBlend);
  70. }
  71. /// <summary>
  72. /// Draw the overlay(s)
  73. /// </summary>
  74. public void Draw()
  75. {
  76. EnsureInitiliased();
  77. Begin();
  78. foreach (var overlay in Overlays)
  79. {
  80. foreach (var element in overlay.Elements)
  81. {
  82. if (element.Hidden)
  83. continue;
  84. var textElement = element as TextElement;
  85. var imageElement = element as ImageElement;
  86. if (textElement != null)
  87. {
  88. Font font = GetFontForTextElement(textElement);
  89. if (font != null && !String.IsNullOrEmpty(textElement.Text))
  90. font.DrawText(_sprite, textElement.Text, textElement.Location.X, textElement.Location.Y, new SharpDX.ColorBGRA(textElement.Color.R, textElement.Color.G, textElement.Color.B, textElement.Color.A));
  91. }
  92. else if (imageElement != null)
  93. {
  94. //Apply the scaling of the imageElement
  95. var rotation = Matrix.RotationZ(imageElement.Angle);
  96. var scaling = Matrix.Scaling(imageElement.Scale);
  97. _sprite.Transform = rotation * scaling;
  98. Texture image = GetImageForImageElement(imageElement);
  99. if (image != null)
  100. _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));
  101. //Reset the transform for other elements
  102. _sprite.Transform = Matrix.Identity;
  103. }
  104. }
  105. }
  106. End();
  107. }
  108. private void End()
  109. {
  110. _sprite.End();
  111. }
  112. /// <summary>
  113. /// In Direct3D9 it is necessary to call OnLostDevice before any call to device.Reset(...) for certain interfaces found in D3DX (e.g. ID3DXSprite, ID3DXFont, ID3DXLine) - https://msdn.microsoft.com/en-us/library/windows/desktop/bb172979(v=vs.85).aspx
  114. /// </summary>
  115. public void BeforeDeviceReset()
  116. {
  117. try
  118. {
  119. foreach (var item in _fontCache)
  120. item.Value.OnLostDevice();
  121. if (_sprite != null)
  122. _sprite.OnLostDevice();
  123. }
  124. catch { }
  125. }
  126. Font GetFontForTextElement(TextElement element)
  127. {
  128. Font result = null;
  129. string fontKey = String.Format("{0}{1}{2}{3}", element.Font.Name, element.Font.Size, element.Font.Style, element.AntiAliased);
  130. if (!_fontCache.TryGetValue(fontKey, out result))
  131. {
  132. result = ToDispose(new Font(_device, new FontDescription {
  133. FaceName = element.Font.Name,
  134. Italic = (element.Font.Style & System.Drawing.FontStyle.Italic) == System.Drawing.FontStyle.Italic,
  135. Quality = (element.AntiAliased ? FontQuality.Antialiased : FontQuality.Default),
  136. Weight = ((element.Font.Style & System.Drawing.FontStyle.Bold) == System.Drawing.FontStyle.Bold) ? FontWeight.Bold : FontWeight.Normal,
  137. Height = (int)element.Font.SizeInPoints
  138. }));
  139. _fontCache[fontKey] = result;
  140. }
  141. return result;
  142. }
  143. Texture GetImageForImageElement(ImageElement element)
  144. {
  145. Texture result = null;
  146. if (!String.IsNullOrEmpty(element.Filename))
  147. {
  148. if (!_imageCache.TryGetValue(element, out result))
  149. {
  150. result = ToDispose(SharpDX.Direct3D9.Texture.FromFile(_device, element.Filename));
  151. _imageCache[element] = result;
  152. }
  153. }
  154. else if (!_imageCache.TryGetValue(element, out result) && element.Bitmap != null)
  155. {
  156. using (var ms = new MemoryStream())
  157. {
  158. element.Bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
  159. ms.Seek(0, SeekOrigin.Begin);
  160. result = ToDispose(Texture.FromStream(Device, ms));
  161. }
  162. _imageCache[element] = result;
  163. }
  164. return result;
  165. }
  166. /// <summary>
  167. /// Releases unmanaged and optionally managed resources
  168. /// </summary>
  169. /// <param name="disposing">true if disposing both unmanaged and managed</param>
  170. protected override void Dispose(bool disposing)
  171. {
  172. if (true)
  173. {
  174. _device = null;
  175. }
  176. base.Dispose(disposing);
  177. }
  178. void SafeDispose(DisposeBase disposableObj)
  179. {
  180. if (disposableObj != null)
  181. disposableObj.Dispose();
  182. }
  183. }
  184. }