- TargetFrameworks net48;net40. net48 keeps x64 + ViGEm + System.IO.Ports package; net40 adds Microsoft.Bcl.Async + System.ValueTuple and uses the in-box SerialPort. - Compat/TaskCompat bridges Task.Run/Delay/WhenAny/WhenAll (TaskEx on net40) and SemaphoreSlim.WaitAsync (net40 blocks briefly - trivial at 9600 baud). - IReadOnlyList/IReadOnlyDictionary -> IList/IDictionary throughout (net40 predates the IReadOnly* interfaces and the Bcl backport cannot make arrays implement them). - HashCode.Combine replaced with a manual combine (Bcl.HashCode has no net40 build); Marshal.SizeOf<T> -> typeof form; ViGEmJoystickSink gated #if !NET40. HidFeederJoystickSink stays on both flavors - it will drive RioGamepadXP.sys on XP via the same contract. Both TFMs build; 275 tests green on net48. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
57 lines
2.4 KiB
C#
57 lines
2.4 KiB
C#
using RioJoy.Core.Overlay;
|
|
using SkiaSharp;
|
|
|
|
namespace RioJoy.Overlay;
|
|
|
|
/// <summary>
|
|
/// Generates a profile's cockpit wallpaper: renders a label set onto the overlay
|
|
/// template's base image and writes a PNG. Resolves the template's
|
|
/// <see cref="OverlayTemplate.BaseImagePath"/> relative to the template file's
|
|
/// directory (so a <c>regions.json</c> + sibling <c>riojoy.png</c> work as a unit).
|
|
/// The runtime calls this on profile activation; an editor can call it for preview.
|
|
/// </summary>
|
|
public sealed class ProfileWallpaperGenerator
|
|
{
|
|
private readonly SkiaOverlayRenderer _renderer;
|
|
|
|
public ProfileWallpaperGenerator(SkiaOverlayRenderer? renderer = null) =>
|
|
_renderer = renderer ?? new SkiaOverlayRenderer();
|
|
|
|
/// <summary>
|
|
/// Render <paramref name="labels"/> onto the template's base image and write a
|
|
/// PNG to <paramref name="outputPath"/>; returns the output path.
|
|
/// </summary>
|
|
/// <param name="templateDirectory">
|
|
/// Directory the template's relative <see cref="OverlayTemplate.BaseImagePath"/>
|
|
/// is resolved against (normally the folder holding the regions.json).
|
|
/// </param>
|
|
public string Generate(
|
|
OverlayTemplate template,
|
|
string templateDirectory,
|
|
IDictionary<string, string> labels,
|
|
string outputPath,
|
|
OverlayLayoutOptions? options = null)
|
|
{
|
|
if (template is null) throw new ArgumentNullException(nameof(template));
|
|
if (labels is null) throw new ArgumentNullException(nameof(labels));
|
|
if (string.IsNullOrWhiteSpace(outputPath)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(outputPath));
|
|
if (string.IsNullOrWhiteSpace(template.BaseImagePath))
|
|
throw new InvalidOperationException("OverlayTemplate.BaseImagePath is not set.");
|
|
|
|
string basePath = Path.IsPathRooted(template.BaseImagePath)
|
|
? template.BaseImagePath
|
|
: Path.Combine(templateDirectory, template.BaseImagePath);
|
|
|
|
using SKBitmap baseImage = SKBitmap.Decode(basePath)
|
|
?? throw new InvalidOperationException($"Could not decode base image: {basePath}");
|
|
|
|
byte[] png = _renderer.RenderToPng(template, labels, baseImage, options);
|
|
|
|
string? dir = Path.GetDirectoryName(Path.GetFullPath(outputPath));
|
|
if (!string.IsNullOrEmpty(dir))
|
|
Directory.CreateDirectory(dir);
|
|
File.WriteAllBytes(outputPath, png);
|
|
return outputPath;
|
|
}
|
|
}
|