Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/BizHawk.Client.Common/Api/ApiManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ static ApiManager()

public static void AddApiType(Type type)
{
if (type == typeof(GuiApi)) return; // using `GuiApiShim` instead
var interfaceType = type.GetInterfaces().FirstOrDefault(t => typeof(IExternalApi).IsAssignableFrom(t) && t != typeof(IExternalApi));
if (interfaceType == null) return; // if we couldn't determine what it's implementing, then it's not an api impl. type
var ctor = type.GetConstructors().Single();
Expand Down
81 changes: 10 additions & 71 deletions src/BizHawk.Client.Common/Api/Classes/GuiApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Linq;
Expand All @@ -28,8 +27,8 @@ private static Bitmap NullGraphicsBitmap

private readonly IDialogController _dialogController;

[RequiredService]
private IEmulator Emulator { get; set; }
// [RequiredService]
internal IEmulator Emulator { get; set; }

private readonly Action<string> LogCallback;

Expand All @@ -47,12 +46,9 @@ private static Bitmap NullGraphicsBitmap

private Color _defaultTextBackground = Color.FromArgb(128, 0, 0, 0);

private (int Left, int Top, int Right, int Bottom) _padding = (0, 0, 0, 0);

private FontFamily[]/*?*/ _pixelFonts = null;

private DisplaySurfaceID? _usingSurfaceID;
public bool HasGUISurface => true;
internal DisplaySurfaceID? SurfaceID { get; set; } = null;

public GuiApi(
IDialogController dialogController,
Expand All @@ -73,70 +69,23 @@ private IReadOnlyList<FontFamily> PixelFonts

private I2DRenderer Get2DRenderer(DisplaySurfaceID? surfaceID)
{
var nnID = surfaceID ?? _usingSurfaceID ?? throw new Exception();
if (surfaceID is not null && surfaceID != SurfaceID) throw new InvalidOperationException($"Mixed drawing surfaces! (Draw call targeting {surfaceID} within {nameof(WithSurface)}({SurfaceID}) scope)");
var nnID = surfaceID ?? SurfaceID ?? throw new Exception();
return _displayManager.GetApiHawk2DRenderer(nnID);
}

public void ToggleCompositingMode()
=> _compositingMode = (CompositingMode) (1 - (int) _compositingMode); // enum has two members, 0 and 1

public ImageAttributes GetAttributes() => null;

public void SetAttributes(ImageAttributes a)
{
}

public void WithSurface(DisplaySurfaceID surfaceID, Action<IGuiApi> drawingCallsFunc)
{
_usingSurfaceID = surfaceID;
try
{
drawingCallsFunc(this);
}
finally
{
_usingSurfaceID = null;
}
const string ERR_MSG_NESTED = $"Nested call to {nameof(IGuiApi)}.{nameof(WithSurface)} (or reference stored out of scope)!";
if (surfaceID != SurfaceID) throw new InvalidOperationException(ERR_MSG_NESTED);
// else it should be fine, but warn anyway
LogCallback(ERR_MSG_NESTED);
drawingCallsFunc(this);
}

public void WithSurface(DisplaySurfaceID surfaceID, Action drawingCallsFunc)
{
_usingSurfaceID = surfaceID;
try
{
drawingCallsFunc();
}
finally
{
_usingSurfaceID = null;
}
}

public void DrawNew(string name, bool clear)
{
switch (name)
{
case null:
case "emu":
LogCallback("the `DrawNew(\"emu\")` function has been deprecated");
return;
case "native":
throw new InvalidOperationException("the ability to draw in the margins with `DrawNew(\"native\")` has been removed");
default:
throw new InvalidOperationException("invalid surface name");
}
}

public void DrawFinish() => LogCallback("the `DrawFinish()` function has been deprecated");

public void SetPadding(int all) => _padding = (all, all, all, all);

public void SetPadding(int x, int y) => _padding = (x / 2, y / 2, x / 2 + x & 1, y / 2 + y & 1);

public void SetPadding(int l, int t, int r, int b) => _padding = (l, t, r, b);

public (int Left, int Top, int Right, int Bottom) GetPadding() => _padding;

public void AddMessage(string message, [LiteralExpected] int? duration = null)
=> _dialogController.AddOnScreenMessage(message, duration);

Expand Down Expand Up @@ -490,16 +439,6 @@ public void DrawString(int x, int y, string message, Color? forecolor = null, Co
}
}

public void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null, DisplaySurfaceID? surfaceID = null)
=> PixelText(
x: x,
y: y,
message: message,
forecolor: forecolor,
backcolor: backcolor,
fontfamily: fontfamily,
surfaceID: surfaceID);

public void PixelText(
int x,
int y,
Expand Down
241 changes: 241 additions & 0 deletions src/BizHawk.Client.Common/Api/Classes/GuiApiShim.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Runtime.CompilerServices;

using BizHawk.Emulation.Common;

namespace BizHawk.Client.Common
{
public sealed class GuiApiShim : IGuiApi
{
private static InvalidOperationException CantDrawOutsideBatch
=> new($"Can't make draw calls outside {nameof(WithSurface)}! Check you're calling this method on the instance passed to the lambda.");

private readonly GuiApi _realImpl;

[RequiredService]
private IEmulator Emulator
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _realImpl.Emulator;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _realImpl.Emulator = value;
}

public GuiApiShim(
IDialogController dialogController,
DisplayManagerBase displayManager,
Action<string> logCallback)
=> _realImpl = new(dialogController, displayManager, logCallback);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddMessage(string message, [LiteralExpected] int? duration = null)
=> _realImpl.AddMessage(message, duration: duration);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ClearGraphics(DisplaySurfaceID? surfaceID = null)
=> _realImpl.ClearGraphics(surfaceID);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ClearImageCache()
=> _realImpl.ClearImageCache();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ClearText()
=> _realImpl.ClearText();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
=> _realImpl.Dispose();

public void DrawAxis(int x, int y, int size, Color? color = null, DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawBezier(
Point p1,
Point p2,
Point p3,
Point p4,
Color? color = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawBeziers(Point[] points, Color? color = null, DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawBox(
int x,
int y,
int x2,
int y2,
Color? line = null,
Color? background = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawEllipse(
int x,
int y,
int width,
int height,
Color? line = null,
Color? background = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawIcon(
string path,
int x,
int y,
int? width = null,
int? height = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawImage(
Image img,
int x,
int y,
int? width = null,
int? height = null,
bool cache = true,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawImage(
string path,
int x,
int y,
int? width = null,
int? height = null,
bool cache = true,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawImageRegion(
Image img,
int source_x,
int source_y,
int source_width,
int source_height,
int dest_x,
int dest_y,
int? dest_width = null,
int? dest_height = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawImageRegion(
string path,
int source_x,
int source_y,
int source_width,
int source_height,
int dest_x,
int dest_y,
int? dest_width = null,
int? dest_height = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawLine(int x1, int y1, int x2, int y2, Color? color = null, DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawPie(
int x,
int y,
int width,
int height,
int startangle,
int sweepangle,
Color? line = null,
Color? background = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawPixel(int x, int y, Color? color = null, DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawPolygon(
Point[] points,
Color? line = null,
Color? background = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawRectangle(
int x,
int y,
int width,
int height,
Color? line = null,
Color? background = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

public void DrawString(
int x,
int y,
string message,
Color? forecolor = null,
Color? backcolor = null,
int? fontsize = null,
string fontfamily = null,
string fontstyle = null,
string horizalign = null,
string vertalign = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color GetDefaultTextBackground()
=> _realImpl.GetDefaultTextBackground();

public void PixelText(
int x,
int y,
string message,
Color? forecolor = null,
Color? backcolor = null,
string fontfamily = null,
DisplaySurfaceID? surfaceID = null)
=> throw CantDrawOutsideBatch;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDefaultBackgroundColor(Color color)
=> _realImpl.SetDefaultBackgroundColor(color);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDefaultForegroundColor(Color color)
=> _realImpl.SetDefaultForegroundColor(color);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDefaultPixelFont(string fontfamily)
=> _realImpl.SetDefaultPixelFont(fontfamily);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDefaultTextBackground(Color color)
=> _realImpl.SetDefaultTextBackground(color);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Text(int x, int y, string message, Color? forecolor = null, string anchor = null)
=> _realImpl.Text(x: x, y: y, message: message, forecolor, anchor: anchor);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToggleCompositingMode()
=> _realImpl.ToggleCompositingMode();

public void WithSurface(DisplaySurfaceID surfaceID, Action<IGuiApi> drawingCallsFunc)
{
_realImpl.SurfaceID = surfaceID;
try
{
drawingCallsFunc(_realImpl);
}
finally
{
_realImpl.SurfaceID = null;
}
}
}
}
Loading
Loading