429 lines
11 KiB
C#
429 lines
11 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using Decal.Adapter.Support;
|
|
using Decal.Interop.Core;
|
|
using Decal.Interop.Render;
|
|
|
|
namespace Decal.Adapter.Wrappers;
|
|
|
|
[CLSCompliant(true)]
|
|
public class HudRenderTarget : MarshalByRefObject, IDisposable
|
|
{
|
|
private IRenderTarget myTarget;
|
|
|
|
private bool isDisposed;
|
|
|
|
private Rectangle areaRect;
|
|
|
|
private bool inRender;
|
|
|
|
private bool inText;
|
|
|
|
public bool Lost => myTarget.Lost;
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public Rectangle Constraint
|
|
{
|
|
get
|
|
{
|
|
Rectangle region = Region;
|
|
return new Rectangle(0, 0, region.Width, region.Height);
|
|
}
|
|
}
|
|
|
|
public Rectangle Region
|
|
{
|
|
get
|
|
{
|
|
return Util.toRectangle(myTarget.Region);
|
|
}
|
|
set
|
|
{
|
|
tagRECT pVal = Util.toTagRECT(value);
|
|
myTarget.Region = ref pVal;
|
|
areaRect.Width = value.Width;
|
|
areaRect.Height = value.Height;
|
|
}
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public object UnsafeSurface => myTarget.GetSurface();
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public tagRECT UnsafeRegion
|
|
{
|
|
get
|
|
{
|
|
return myTarget.Region;
|
|
}
|
|
set
|
|
{
|
|
myTarget.Region = ref value;
|
|
}
|
|
}
|
|
|
|
protected bool IsDisposed => isDisposed;
|
|
|
|
[CLSCompliant(false)]
|
|
protected HudRenderTarget(IRenderTarget newTarget)
|
|
{
|
|
if (newTarget == null)
|
|
{
|
|
throw new ArgumentNullException("newTarget");
|
|
}
|
|
myTarget = newTarget;
|
|
tagRECT region = myTarget.Region;
|
|
areaRect = new Rectangle(0, 0, region.right - region.left, region.bottom - region.top);
|
|
}
|
|
|
|
~HudRenderTarget()
|
|
{
|
|
Dispose(disposing: false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Begin rendering to this object, must be paired with EndRender
|
|
/// </summary>
|
|
public void BeginRender()
|
|
{
|
|
BeginRender(enableTextureFilter: false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Begin rendering to this object, must be paired with EndRender
|
|
/// </summary>
|
|
/// <param name="enableTextureFilter">True to enable texture filtering during rendering</param>
|
|
public void BeginRender(bool enableTextureFilter)
|
|
{
|
|
if (!inRender)
|
|
{
|
|
myTarget.BeginRender(enableTextureFilter);
|
|
inRender = true;
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'BeginRender' when already rendering");
|
|
}
|
|
|
|
/// <summary>
|
|
/// End rendering to this object, must be paired with BeginRender
|
|
/// </summary>
|
|
public void EndRender()
|
|
{
|
|
if (inRender)
|
|
{
|
|
myTarget.EndRender();
|
|
inRender = false;
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'EndRender' without a previous call to 'BeginRender'");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Begin writing text
|
|
/// </summary>
|
|
/// <param name="fontName">Name of the font to use for writing text</param>
|
|
/// <param name="pixelHeight">Height in pixels to use when writing text</param>
|
|
public void BeginText(string fontName, int pixelHeight)
|
|
{
|
|
BeginText(fontName, pixelHeight, FontWeight.Normal, italic: false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Begin writing text
|
|
/// </summary>
|
|
/// <param name="fontName">Name of the font to use for writing text</param>
|
|
/// <param name="pixelHeight">Height in pixels to use when writing text</param>
|
|
/// <param name="weight">Bold, Strong, etc, indicator for text to be written</param>
|
|
/// <param name="italic">Write text in italics?</param>
|
|
public void BeginText(string fontName, int pixelHeight, FontWeight weight, bool italic)
|
|
{
|
|
UnsafeBeginText(fontName, pixelHeight, (int)weight, italic);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Display text,using the full rectangle of the render target as the area.
|
|
/// This overload will draw the text in black.
|
|
/// </summary>
|
|
/// <param name="text">Text to display</param>
|
|
public void WriteText(string text)
|
|
{
|
|
WriteText(text, Color.Black, WriteTextFormats.None, areaRect);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Display text,using the full rectangle of the render target as the area.
|
|
/// </summary>
|
|
/// <param name="text">Text to display</param>
|
|
/// <param name="color">Color to use to display the text. (Including alpha channel)</param>
|
|
public void WriteText(string text, Color color)
|
|
{
|
|
WriteText(text, color, WriteTextFormats.None, areaRect);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Display text,using the full rectangle of the render target as the area.
|
|
/// </summary>
|
|
/// <param name="text">Text to display</param>
|
|
/// <param name="color">Color to use to display the text. (Including alpha channel)</param>
|
|
/// <param name="format">Format specifiers, including centered, etc.</param>
|
|
/// <param name="region">Rectangle relative to this object to use to bound the text</param>
|
|
public void WriteText(string text, Color color, WriteTextFormats format, Rectangle region)
|
|
{
|
|
UnsafeWriteText(Util.toTagRECT(region), color.ToArgb(), (int)format, text);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Display text,using the full rectangle of the render target as the area.
|
|
/// </summary>
|
|
/// <param name="text">Text to display</param>
|
|
/// <param name="color">Color to use to display the text. (Including alpha channel)</param>
|
|
/// <param name="format">Format specifiers, including centered, etc.</param>
|
|
/// <param name="region">Rectangle relative to this object to use to bound the text</param>
|
|
public void WriteText(string text, int color, WriteTextFormats format, Rectangle region)
|
|
{
|
|
UnsafeWriteText(Util.toTagRECT(region), color, (int)format, text);
|
|
}
|
|
|
|
/// <summary>
|
|
/// End drawing of text.
|
|
/// </summary>
|
|
public void EndText()
|
|
{
|
|
if (inRender && inText)
|
|
{
|
|
myTarget.EndText();
|
|
inText = false;
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'EndText' without a previous call to 'BeginText'");
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
Clear(areaRect);
|
|
}
|
|
|
|
public void Clear(Rectangle clearArea)
|
|
{
|
|
UnsafeClear(Util.toTagRECT(clearArea));
|
|
}
|
|
|
|
public void DrawPortalImage(int portalFile, Rectangle destinationArea)
|
|
{
|
|
UnsafeDrawPortalImage(portalFile, Util.toTagRECT(destinationArea));
|
|
}
|
|
|
|
public void DrawPortalImage(int portalFile, int alpha, Rectangle srcArea, Rectangle destinationArea)
|
|
{
|
|
UnsafeDrawPortalImage(portalFile, alpha, Util.toTagRECT(srcArea), Util.toTagRECT(destinationArea));
|
|
}
|
|
|
|
public void DrawPortalImage(int portalFile, Rectangle srcArea, Rectangle destinationArea)
|
|
{
|
|
UnsafeDrawPortalImage(portalFile, 255, Util.toTagRECT(srcArea), Util.toTagRECT(destinationArea));
|
|
}
|
|
|
|
public void TilePortalImage(int portalFile, Rectangle destinationArea)
|
|
{
|
|
UnsafeTilePortalImage(portalFile, Util.toTagRECT(destinationArea));
|
|
}
|
|
|
|
public void TilePortalImage(int portalFile, Rectangle srcArea, Rectangle destinationArea)
|
|
{
|
|
UnsafeTilePortalImage(portalFile, Util.toTagRECT(srcArea), Util.toTagRECT(destinationArea));
|
|
}
|
|
|
|
public void DrawImage(Image image, Rectangle destinationRegion)
|
|
{
|
|
DrawImage(image, destinationRegion, Color.Cyan.ToArgb());
|
|
}
|
|
|
|
public void DrawImage(Image image, Rectangle destinationRegion, Color colorKey)
|
|
{
|
|
DrawImage(image, destinationRegion, colorKey.ToArgb());
|
|
}
|
|
|
|
public void DrawImage(Image image, Rectangle destinationRegion, int colorKey)
|
|
{
|
|
if (image == null)
|
|
{
|
|
throw new ArgumentNullException("image");
|
|
}
|
|
MemoryStream memoryStream = new MemoryStream();
|
|
image.Save(memoryStream, ImageFormat.Bmp);
|
|
byte[] buffer = memoryStream.GetBuffer();
|
|
IntPtr zero = IntPtr.Zero;
|
|
int num = buffer.Length;
|
|
zero = Marshal.AllocCoTaskMem(num);
|
|
try
|
|
{
|
|
Marshal.Copy(buffer, 0, zero, num);
|
|
if (zero != IntPtr.Zero)
|
|
{
|
|
UnsafeDrawImage(zero, num, Util.toTagRECT(destinationRegion), colorKey);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FreeCoTaskMem(zero);
|
|
memoryStream.Dispose();
|
|
}
|
|
}
|
|
|
|
public void Fill(Color color)
|
|
{
|
|
Fill(areaRect, color);
|
|
}
|
|
|
|
public void Fill(Rectangle fillArea, Color color)
|
|
{
|
|
Fill(fillArea, color.ToArgb());
|
|
}
|
|
|
|
public void Fill(Rectangle fillArea, int color)
|
|
{
|
|
UnsafeFill(Util.toTagRECT(fillArea), color);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeBeginText(string fontName, int pixelHeight, int weight, bool italic)
|
|
{
|
|
if (inRender && !inText)
|
|
{
|
|
myTarget.BeginText(fontName, pixelHeight, weight, italic);
|
|
inText = true;
|
|
return;
|
|
}
|
|
if (inRender && inText)
|
|
{
|
|
throw new RenderViolationException("Cannot call 'BeginText' when already rendering text");
|
|
}
|
|
throw new RenderViolationException("Cannot call 'BeginText' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeWriteText(tagRECT region, int color, int format, string text)
|
|
{
|
|
if (inRender && inText)
|
|
{
|
|
myTarget.WriteText(ref region, color, format, text);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'WriteText' outside of a BeginText/EndText block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeClear(tagRECT clearArea)
|
|
{
|
|
if (!inRender)
|
|
{
|
|
myTarget.Clear(ref clearArea);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("MUST call 'Clear' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeDrawPortalImage(int portalFile, tagRECT destinationArea)
|
|
{
|
|
if (inRender)
|
|
{
|
|
myTarget.DrawPortalImage(portalFile, ref destinationArea);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'DrawPortalImage' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeDrawPortalImage(int portalFile, int alpha, tagRECT srcArea, tagRECT destinationArea)
|
|
{
|
|
if (inRender)
|
|
{
|
|
myTarget.DrawPortalImageEx(portalFile, alpha, ref srcArea, ref destinationArea);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'DrawPortalImageEx' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeTilePortalImage(int portalFile, tagRECT destinationArea)
|
|
{
|
|
if (inRender)
|
|
{
|
|
myTarget.TilePortalImage(portalFile, ref destinationArea);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'TilePortalImage' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeTilePortalImage(int portalFile, tagRECT srcArea, tagRECT destinationArea)
|
|
{
|
|
if (inRender)
|
|
{
|
|
myTarget.TilePortalImageEx(portalFile, ref srcArea, ref destinationArea);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'TilePortalImageEx' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeDrawImage(IntPtr buffer, int size, tagRECT destinationRegion, int colorKey)
|
|
{
|
|
if (inRender)
|
|
{
|
|
myTarget.DrawImage((int)buffer, size, ref destinationRegion, colorKey);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("Cannot call 'DrawImage' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeFill(tagRECT fillArea, int color)
|
|
{
|
|
if (!inRender)
|
|
{
|
|
myTarget.Fill(ref fillArea, color);
|
|
return;
|
|
}
|
|
throw new RenderViolationException("MUST call 'Fill' outside of a BeginRender/EndRender block");
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void UnsafeSetSurface(object pSurface)
|
|
{
|
|
myTarget.SetSurface(pSurface);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!isDisposed)
|
|
{
|
|
}
|
|
if (myTarget != null)
|
|
{
|
|
Marshal.ReleaseComObject(myTarget);
|
|
}
|
|
myTarget = null;
|
|
isDisposed = true;
|
|
}
|
|
}
|