mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-04-10 03:10:06 +03:00
Get rid of DisposableGCHandle.
Use Span functionality instead. This introduces some copies for .NET Standard 2.0 builds.
This commit is contained in:
parent
b4cf309156
commit
57815e9072
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.Worms.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a disposable <see cref="GCHandle"/>.
|
||||
/// </summary>
|
||||
internal class DisposableGCHandle : IDisposable
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private readonly GCHandle _handle;
|
||||
private bool _disposed;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
public DisposableGCHandle(object value, GCHandleType type) => _handle = GCHandle.Alloc(value, type);
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
public IntPtr AddrOfPinnedObject => _handle.AddrOfPinnedObject();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
public void Dispose() => Dispose(true);
|
||||
|
||||
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (_handle.IsAllocated)
|
||||
_handle.Free();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.Worms.Core.Graphics
|
||||
{
|
||||
@ -20,16 +20,15 @@ namespace Syroot.Worms.Core.Graphics
|
||||
/// <param name="palette">The palette as a <see cref="Color"/> array.</param>
|
||||
/// <param name="data">The data array storing bytes indexing the palette color array.</param>
|
||||
/// <returns>The <see cref="Bitmap"/> instance.</returns>
|
||||
public static Bitmap CreateIndexed(Size size, IList<Color> palette, byte[] data)
|
||||
public static unsafe Bitmap CreateIndexed(Size size, IList<Color> palette, byte[] data)
|
||||
{
|
||||
using DisposableGCHandle dataPin = new DisposableGCHandle(data, GCHandleType.Pinned);
|
||||
|
||||
// Transfer the pixel data, respecting power-of-2 strides.
|
||||
Bitmap bitmap = new Bitmap(size.Width, size.Height, PixelFormat.Format8bppIndexed);
|
||||
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, size.Width, size.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
Span<byte> bitmapSpan = new Span<byte>(bitmapData.Scan0.ToPointer(), bitmapData.Stride * bitmapData.Height);
|
||||
for (int y = 0; y < size.Height; y++)
|
||||
Marshal.Copy(data, y * size.Width, bitmapData.Scan0 + y * bitmapData.Stride, size.Width);
|
||||
data.AsSpan(y * size.Width, size.Width).CopyTo(bitmapSpan.Slice(y * bitmapData.Stride));
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
|
||||
// Transfer the palette.
|
||||
|
@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using Syroot.Worms.Core;
|
||||
|
||||
namespace Syroot.Worms
|
||||
{
|
||||
@ -39,16 +38,15 @@ namespace Syroot.Worms
|
||||
/// Creates a <see cref="Bitmap"/> from the raw data.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="Bitmap"/> created from the raw data.</returns>
|
||||
public Bitmap ToBitmap()
|
||||
public unsafe Bitmap ToBitmap()
|
||||
{
|
||||
using DisposableGCHandle dataPin = new DisposableGCHandle(Data, GCHandleType.Pinned);
|
||||
|
||||
// Transfer the pixel data, respecting power-of-2 strides.
|
||||
Bitmap bitmap = new Bitmap(Size.Width, Size.Height, PixelFormat.Format8bppIndexed);
|
||||
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
Span<byte> bitmapSpan = new Span<byte>(bitmapData.Scan0.ToPointer(), bitmapData.Stride * bitmapData.Height);
|
||||
for (int y = 0; y < Size.Height; y++)
|
||||
Marshal.Copy(Data, y * Size.Width, bitmapData.Scan0 + y * bitmapData.Stride, Size.Width);
|
||||
Data.AsSpan(y * Size.Width, Size.Width).CopyTo(bitmapSpan.Slice(y * bitmapData.Stride));
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
|
||||
// Transfer the palette.
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Syroot.BinaryData;
|
||||
|
||||
@ -84,12 +86,17 @@ namespace Syroot.Worms.Core.IO
|
||||
public static T ReadStruct<T>(this BinaryStream self) where T : struct
|
||||
{
|
||||
// Read the raw bytes of the structure.
|
||||
byte[] bytes = self.ReadBytes(Marshal.SizeOf<T>());
|
||||
#if NETSTANDARD2_0
|
||||
byte[] bytes = new byte[Unsafe.SizeOf<T>()];
|
||||
self.Read(bytes, 0, bytes.Length);
|
||||
#else
|
||||
Span<byte> bytes = stackalloc byte[Unsafe.SizeOf<T>()];
|
||||
self.Read(bytes);
|
||||
#endif
|
||||
|
||||
// Convert them to a structure instance and return it.
|
||||
using DisposableGCHandle handle = new DisposableGCHandle(bytes, GCHandleType.Pinned);
|
||||
T instance = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject);
|
||||
return instance;
|
||||
ReadOnlySpan<T> span = MemoryMarshal.Cast<byte, T>(bytes);
|
||||
return span[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -101,10 +108,18 @@ namespace Syroot.Worms.Core.IO
|
||||
/// <returns>The structures of type <typeparamref name="T"/>.</returns>
|
||||
public static T[] ReadStructs<T>(this BinaryStream self, int count) where T : struct
|
||||
{
|
||||
T[] values = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
values[i] = ReadStruct<T>(self);
|
||||
return values;
|
||||
// Read the raw bytes of the structures.
|
||||
#if NETSTANDARD2_0
|
||||
byte[] bytes = new byte[Unsafe.SizeOf<T>()];
|
||||
self.Read(bytes, 0, bytes.Length);
|
||||
#else
|
||||
Span<byte> bytes = stackalloc byte[Unsafe.SizeOf<T>() * count];
|
||||
self.Read(bytes);
|
||||
#endif
|
||||
|
||||
// Convert them to a structure array and return it.
|
||||
ReadOnlySpan<T> span = MemoryMarshal.Cast<byte, T>(bytes);
|
||||
return span.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -186,14 +201,13 @@ namespace Syroot.Worms.Core.IO
|
||||
/// <param name="value">The structure to write.</param>
|
||||
public static void WriteStruct<T>(this BinaryStream self, T value) where T : struct
|
||||
{
|
||||
// Get the raw bytes of the structure instance.
|
||||
byte[] bytes = new byte[Marshal.SizeOf<T>()];
|
||||
|
||||
using (DisposableGCHandle handle = new DisposableGCHandle(bytes, GCHandleType.Pinned))
|
||||
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject, false);
|
||||
|
||||
// Write the bytes to the stream.
|
||||
self.WriteStructs(bytes);
|
||||
ReadOnlySpan<byte> bytes;
|
||||
unsafe { bytes = new ReadOnlySpan<byte>(Unsafe.AsPointer(ref value), Unsafe.SizeOf<T>()); }
|
||||
#if NETSTANDARD2_0
|
||||
self.Write(bytes.ToArray()); // cannot prevent copy in .NET Standard 2.0
|
||||
#else
|
||||
self.Write(bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -202,10 +216,10 @@ namespace Syroot.Worms.Core.IO
|
||||
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="values">The structures to write.</param>
|
||||
public static void WriteStructs<T>(this BinaryStream self, IList<T> values) where T : struct
|
||||
public static void WriteStructs<T>(this BinaryStream self, IEnumerable<T> values) where T : struct
|
||||
{
|
||||
foreach (T value in values)
|
||||
WriteStruct(self, value);
|
||||
self.WriteStruct(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)build.xml" />
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>Syroot.Worms</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Team17 Worms games.</Description>
|
||||
<PackageReleaseNotes>Split into game-related packages.</PackageReleaseNotes>
|
||||
|
Loading…
x
Reference in New Issue
Block a user