Refactor core APIs, fix bugs, and improve safety
- Make image result/info structs readonly; improve error handling and memory safety in image library - Introduce IJobScheduler interface; move job scheduling docs to interface - Remove "index 0 invalid" convention from slot/sparse maps; fix Count logic - Add Owner<T> for disposable value types in low-level utilities - Improve ObjectPool<T> thread safety and logic - Change List<T>.RemoveAndSwapBack to return bool - Remove unsafe methods from generated math types; add debug range checks - Update benchmarks and enable collection checks in tests - Improve documentation, comments, and error messages - Bump assembly versions across all projects
This commit is contained in:
@@ -1,9 +1,14 @@
|
|||||||
namespace Misaki.HighPerformance.Image;
|
namespace Misaki.HighPerformance.Image;
|
||||||
|
|
||||||
public class AnimatedFrameResult : ImageResult
|
public readonly struct AnimatedFrameResult
|
||||||
{
|
{
|
||||||
|
public required ImageResult Image
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
public int DelayInMs
|
public int DelayInMs
|
||||||
{
|
{
|
||||||
get; set;
|
get; init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,12 +15,16 @@ internal class AnimatedGifEnumerator : IEnumerator<AnimatedFrameResult>
|
|||||||
public AnimatedGifEnumerator(Stream input, ColorComponents colorComponents)
|
public AnimatedGifEnumerator(Stream input, ColorComponents colorComponents)
|
||||||
{
|
{
|
||||||
if (input == null)
|
if (input == null)
|
||||||
|
{
|
||||||
throw new ArgumentNullException("input");
|
throw new ArgumentNullException("input");
|
||||||
|
}
|
||||||
|
|
||||||
_context = new StbImage.stbi__context(input);
|
_context = new StbImage.stbi__context(input);
|
||||||
|
|
||||||
if (StbImage.stbi__gif_test(_context) == 0)
|
if (StbImage.stbi__gif_test(_context) == 0)
|
||||||
|
{
|
||||||
throw new Exception("Input stream is not GIF file.");
|
throw new Exception("Input stream is not GIF file.");
|
||||||
|
}
|
||||||
|
|
||||||
_gif = new StbImage.stbi__gif();
|
_gif = new StbImage.stbi__gif();
|
||||||
_colorComponents = colorComponents;
|
_colorComponents = colorComponents;
|
||||||
@@ -60,18 +64,25 @@ internal class AnimatedGifEnumerator : IEnumerator<AnimatedFrameResult>
|
|||||||
byte two_back;
|
byte two_back;
|
||||||
var result = StbImage.stbi__gif_load_next(_context, _gif, &ccomp, (int)ColorComponents, &two_back);
|
var result = StbImage.stbi__gif_load_next(_context, _gif, &ccomp, (int)ColorComponents, &two_back);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
return false;
|
|
||||||
|
|
||||||
Current ??= new AnimatedFrameResult
|
|
||||||
{
|
{
|
||||||
Data = result,
|
return false;
|
||||||
Width = (uint)_gif.w,
|
}
|
||||||
Height = (uint)_gif.h,
|
|
||||||
SourceComp = (ColorComponents)ccomp,
|
|
||||||
Comp = ColorComponents == ColorComponents.Default ? (ColorComponents)ccomp : ColorComponents
|
|
||||||
};
|
|
||||||
|
|
||||||
Current.DelayInMs = _gif.delay;
|
if (Current.Image.Data == null)
|
||||||
|
{
|
||||||
|
Current = new AnimatedFrameResult
|
||||||
|
{
|
||||||
|
Image = new ImageResult
|
||||||
|
{
|
||||||
|
Data = result,
|
||||||
|
Width = (uint)_gif.w,
|
||||||
|
Height = (uint)_gif.h,
|
||||||
|
SourceComp = (ColorComponents)ccomp,
|
||||||
|
Comp = ColorComponents == ColorComponents.Default ? (ColorComponents)ccomp : ColorComponents,
|
||||||
|
},
|
||||||
|
DelayInMs = _gif.delay
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,30 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Image;
|
namespace Misaki.HighPerformance.Image;
|
||||||
|
|
||||||
public struct ImageInfo
|
public readonly struct ImageInfo
|
||||||
{
|
{
|
||||||
public int Width;
|
public int Width
|
||||||
public int Height;
|
{
|
||||||
public ColorComponents ColorComponents;
|
get; init;
|
||||||
public int BitsPerChannel;
|
}
|
||||||
|
|
||||||
public static unsafe ImageInfo? FromStream(Stream stream)
|
public int Height
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorComponents ColorComponents
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int BitsPerChannel
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe ImageInfo FromStream(Stream stream)
|
||||||
{
|
{
|
||||||
int width, height, comp;
|
int width, height, comp;
|
||||||
var context = new StbImage.stbi__context(stream);
|
var context = new StbImage.stbi__context(stream);
|
||||||
@@ -21,7 +36,9 @@ public struct ImageInfo
|
|||||||
StbImage.stbi__rewind(context);
|
StbImage.stbi__rewind(context);
|
||||||
|
|
||||||
if (infoResult == 0)
|
if (infoResult == 0)
|
||||||
return null;
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
return new ImageInfo
|
return new ImageInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ using System.IO;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.Image;
|
namespace Misaki.HighPerformance.Image;
|
||||||
|
|
||||||
public unsafe class ImageResult : IDisposable
|
/// <summary>
|
||||||
|
/// Represents the result of loading an image, including pixel data and image metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The image data is stored as a contiguous block of unmanaged memory and must be released by calling
|
||||||
|
/// <see cref="Dispose"/> when no longer needed. Be careful that this struct won't stop your double free if you copy it.
|
||||||
|
/// Ensure to have proper ownership management when using this struct.</remarks>
|
||||||
|
public unsafe readonly struct ImageResult : IDisposable
|
||||||
{
|
{
|
||||||
public byte* Data
|
public byte* Data
|
||||||
{
|
{
|
||||||
@@ -45,10 +51,12 @@ public unsafe class ImageResult : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static unsafe ImageResult FromResult(byte* result, uint width, uint height, ColorComponents comp, ColorComponents req_comp)
|
internal static ImageResult FromResult(byte* result, uint width, uint height, ColorComponents comp, ColorComponents req_comp)
|
||||||
{
|
{
|
||||||
if (result == null)
|
if (result == null)
|
||||||
|
{
|
||||||
throw new InvalidOperationException(StbImage.stbi__g_failure_reason);
|
throw new InvalidOperationException(StbImage.stbi__g_failure_reason);
|
||||||
|
}
|
||||||
|
|
||||||
var image = new ImageResult
|
var image = new ImageResult
|
||||||
{
|
{
|
||||||
@@ -62,13 +70,11 @@ public unsafe class ImageResult : IDisposable
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe ImageResult FromStream(Stream stream,
|
public static ImageResult FromStream(Stream stream,
|
||||||
ColorComponents requiredComponents = ColorComponents.Default)
|
ColorComponents requiredComponents = ColorComponents.Default)
|
||||||
{
|
{
|
||||||
int x, y, comp;
|
int x, y, comp;
|
||||||
|
|
||||||
var context = new StbImage.stbi__context(stream);
|
var context = new StbImage.stbi__context(stream);
|
||||||
|
|
||||||
var result = StbImage.stbi__load_and_postprocess_8bit(context, &x, &y, &comp, (int)requiredComponents);
|
var result = StbImage.stbi__load_and_postprocess_8bit(context, &x, &y, &comp, (int)requiredComponents);
|
||||||
|
|
||||||
return FromResult(result, (uint)x, (uint)y, (ColorComponents)comp, requiredComponents);
|
return FromResult(result, (uint)x, (uint)y, (ColorComponents)comp, requiredComponents);
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
using Misaki.HighPerformance.Image.Runtime;
|
using Misaki.HighPerformance.Image.Runtime;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Image;
|
namespace Misaki.HighPerformance.Image;
|
||||||
|
|
||||||
public unsafe class ImageResultFloat : IDisposable
|
/// <summary>
|
||||||
|
/// Represents a decoded image with pixel data stored as floating-point values, including image dimensions and color
|
||||||
|
/// component information.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The image data is stored as a contiguous block of unmanaged memory and must be released by calling
|
||||||
|
/// <see cref="Dispose"/> when no longer needed. Be careful that this struct won't stop your double free if you copy it.
|
||||||
|
/// Ensure to have proper ownership management when using this struct.</remarks>
|
||||||
|
public unsafe readonly struct ImageResultFloat : IDisposable
|
||||||
{
|
{
|
||||||
public float* Data
|
public float* Data
|
||||||
{
|
{
|
||||||
@@ -44,7 +51,7 @@ public unsafe class ImageResultFloat : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static unsafe ImageResultFloat FromResult(float* result, uint width, uint height, ColorComponents comp,
|
internal static ImageResultFloat FromResult(float* result, uint width, uint height, ColorComponents comp,
|
||||||
ColorComponents req_comp)
|
ColorComponents req_comp)
|
||||||
{
|
{
|
||||||
if (result == null)
|
if (result == null)
|
||||||
@@ -64,13 +71,11 @@ public unsafe class ImageResultFloat : IDisposable
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe ImageResultFloat FromStream(Stream stream,
|
public static ImageResultFloat FromStream(Stream stream,
|
||||||
ColorComponents requiredComponents = ColorComponents.Default)
|
ColorComponents requiredComponents = ColorComponents.Default)
|
||||||
{
|
{
|
||||||
int x, y, comp;
|
int x, y, comp;
|
||||||
|
|
||||||
var context = new StbImage.stbi__context(stream);
|
var context = new StbImage.stbi__context(stream);
|
||||||
|
|
||||||
var result = StbImage.stbi__loadf_main(context, &x, &y, &comp, (int)requiredComponents);
|
var result = StbImage.stbi__loadf_main(context, &x, &y, &comp, (int)requiredComponents);
|
||||||
|
|
||||||
return FromResult(result, (uint)x, (uint)y, (ColorComponents)comp, requiredComponents);
|
return FromResult(result, (uint)x, (uint)y, (ColorComponents)comp, requiredComponents);
|
||||||
@@ -79,10 +84,8 @@ public unsafe class ImageResultFloat : IDisposable
|
|||||||
public static ImageResultFloat FromMemory(byte[] data,
|
public static ImageResultFloat FromMemory(byte[] data,
|
||||||
ColorComponents requiredComponents = ColorComponents.Default)
|
ColorComponents requiredComponents = ColorComponents.Default)
|
||||||
{
|
{
|
||||||
using (var stream = new MemoryStream(data))
|
using var stream = new MemoryStream(data);
|
||||||
{
|
return FromStream(stream, requiredComponents);
|
||||||
return FromStream(stream, requiredComponents);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Span<byte> AsSpan()
|
public Span<byte> AsSpan()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Authors>Misaki</Authors>
|
<Authors>Misaki</Authors>
|
||||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
<AssemblyVersion>1.1.0</AssemblyVersion>
|
||||||
<Version>$(AssemblyVersion)</Version>
|
<Version>$(AssemblyVersion)</Version>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ internal static unsafe class CRuntime
|
|||||||
public static void free(void* ptr)
|
public static void free(void* ptr)
|
||||||
{
|
{
|
||||||
if (ptr == null)
|
if (ptr == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NativeMemory.Free(ptr);
|
NativeMemory.Free(ptr);
|
||||||
MemoryStats.Freed();
|
MemoryStats.Freed();
|
||||||
@@ -54,7 +56,9 @@ internal static unsafe class CRuntime
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (temp != null)
|
if (temp != null)
|
||||||
|
{
|
||||||
free(temp);
|
free(temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +70,9 @@ internal static unsafe class CRuntime
|
|||||||
for (long i = 0; i < size; ++i)
|
for (long i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
if (*ap != *bp)
|
if (*ap != *bp)
|
||||||
|
{
|
||||||
result += 1;
|
result += 1;
|
||||||
|
}
|
||||||
|
|
||||||
ap++;
|
ap++;
|
||||||
bp++;
|
bp++;
|
||||||
@@ -80,7 +86,9 @@ internal static unsafe class CRuntime
|
|||||||
var bptr = (byte*)ptr;
|
var bptr = (byte*)ptr;
|
||||||
var bval = (byte)value;
|
var bval = (byte)value;
|
||||||
for (long i = 0; i < size; ++i)
|
for (long i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
*bptr++ = bval;
|
*bptr++ = bval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void memset(void* ptr, int value, ulong size)
|
public static void memset(void* ptr, int value, ulong size)
|
||||||
@@ -96,7 +104,9 @@ internal static unsafe class CRuntime
|
|||||||
public static void* realloc(void* ptr, long newSize)
|
public static void* realloc(void* ptr, long newSize)
|
||||||
{
|
{
|
||||||
if (ptr == null)
|
if (ptr == null)
|
||||||
|
{
|
||||||
return malloc(newSize);
|
return malloc(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
var result = NativeMemory.Realloc(ptr, (nuint)newSize);
|
var result = NativeMemory.Realloc(ptr, (nuint)newSize);
|
||||||
|
|
||||||
|
|||||||
@@ -2,26 +2,26 @@ using System.Threading;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.Image.Runtime
|
namespace Misaki.HighPerformance.Image.Runtime
|
||||||
{
|
{
|
||||||
internal static unsafe class MemoryStats
|
internal static class MemoryStats
|
||||||
{
|
{
|
||||||
private static int _allocations;
|
private static int s_allocations;
|
||||||
|
|
||||||
public static int Allocations
|
public static int Allocations
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _allocations;
|
return s_allocations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Allocated()
|
internal static void Allocated()
|
||||||
{
|
{
|
||||||
Interlocked.Increment(ref _allocations);
|
Interlocked.Increment(ref s_allocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Freed()
|
internal static void Freed()
|
||||||
{
|
{
|
||||||
Interlocked.Decrement(ref _allocations);
|
Interlocked.Decrement(ref s_allocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,13 +34,22 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var info = new stbi__bmp_data();
|
var info = new stbi__bmp_data();
|
||||||
info.all_a = 255;
|
info.all_a = 255;
|
||||||
if (stbi__bmp_parse_header(s, &info) == null)
|
if (stbi__bmp_parse_header(s, &info) == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
flip_vertically = (int)s.img_y > 0 ? 1 : 0;
|
flip_vertically = (int)s.img_y > 0 ? 1 : 0;
|
||||||
s.img_y = (uint)CRuntime.abs((int)s.img_y);
|
s.img_y = (uint)CRuntime.abs((int)s.img_y);
|
||||||
if (s.img_y > 1 << 24)
|
if (s.img_y > 1 << 24)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (s.img_x > 1 << 24)
|
if (s.img_x > 1 << 24)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
mr = info.mr;
|
mr = info.mr;
|
||||||
mg = info.mg;
|
mg = info.mg;
|
||||||
mb = info.mb;
|
mb = info.mb;
|
||||||
@@ -49,12 +58,16 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if (info.hsz == 12)
|
if (info.hsz == 12)
|
||||||
{
|
{
|
||||||
if (info.bpp < 24)
|
if (info.bpp < 24)
|
||||||
|
{
|
||||||
psize = (info.offset - info.extra_read - 24) / 3;
|
psize = (info.offset - info.extra_read - 24) / 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (info.bpp < 16)
|
if (info.bpp < 16)
|
||||||
|
{
|
||||||
psize = (info.offset - info.extra_read - info.hsz) >> 2;
|
psize = (info.offset - info.extra_read - info.hsz) >> 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (psize == 0)
|
if (psize == 0)
|
||||||
@@ -63,26 +76,47 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var header_limit = 1024;
|
var header_limit = 1024;
|
||||||
var extra_data_limit = 256 * 4;
|
var extra_data_limit = 256 * 4;
|
||||||
if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit)
|
if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad header") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad header") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit)
|
if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad offset") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad offset") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, info.offset - bytes_read_so_far);
|
stbi__skip(s, info.offset - bytes_read_so_far);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.bpp == 24 && ma == 0xff000000)
|
if (info.bpp == 24 && ma == 0xff000000)
|
||||||
|
{
|
||||||
s.img_n = 3;
|
s.img_n = 3;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
s.img_n = ma != 0 ? 4 : 3;
|
s.img_n = ma != 0 ? 4 : 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (req_comp != 0 && req_comp >= 3)
|
if (req_comp != 0 && req_comp >= 3)
|
||||||
|
{
|
||||||
target = req_comp;
|
target = req_comp;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
target = s.img_n;
|
target = s.img_n;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__mad3sizes_valid(target, (int)s.img_x, (int)s.img_y, 0) == 0)
|
if (stbi__mad3sizes_valid(target, (int)s.img_x, (int)s.img_y, 0) == 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
_out_ = (byte*)stbi__malloc_mad3(target, (int)s.img_x, (int)s.img_y, 0);
|
_out_ = (byte*)stbi__malloc_mad3(target, (int)s.img_x, (int)s.img_y, 0);
|
||||||
if (_out_ == null)
|
if (_out_ == null)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (info.bpp < 16)
|
if (info.bpp < 16)
|
||||||
{
|
{
|
||||||
var z = 0;
|
var z = 0;
|
||||||
@@ -98,7 +132,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
pal[i][1] = stbi__get8(s);
|
pal[i][1] = stbi__get8(s);
|
||||||
pal[i][0] = stbi__get8(s);
|
pal[i][0] = stbi__get8(s);
|
||||||
if (info.hsz != 12)
|
if (info.hsz != 12)
|
||||||
|
{
|
||||||
stbi__get8(s);
|
stbi__get8(s);
|
||||||
|
}
|
||||||
|
|
||||||
pal[i][3] = 255;
|
pal[i][3] = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +160,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
|
|
||||||
pad = -width & 3;
|
pad = -width & 3;
|
||||||
if (info.bpp == 1)
|
if (info.bpp == 1)
|
||||||
|
{
|
||||||
for (j = 0; j < (int)s.img_y; ++j)
|
for (j = 0; j < (int)s.img_y; ++j)
|
||||||
{
|
{
|
||||||
var bit_offset = 7;
|
var bit_offset = 7;
|
||||||
@@ -134,9 +172,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
_out_[z++] = pal[color][1];
|
_out_[z++] = pal[color][1];
|
||||||
_out_[z++] = pal[color][2];
|
_out_[z++] = pal[color][2];
|
||||||
if (target == 4)
|
if (target == 4)
|
||||||
|
{
|
||||||
_out_[z++] = 255;
|
_out_[z++] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
if (i + 1 == (int)s.img_x)
|
if (i + 1 == (int)s.img_x)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (--bit_offset < 0)
|
if (--bit_offset < 0)
|
||||||
{
|
{
|
||||||
bit_offset = 7;
|
bit_offset = 7;
|
||||||
@@ -146,7 +190,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
|
|
||||||
stbi__skip(s, pad);
|
stbi__skip(s, pad);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (j = 0; j < (int)s.img_y; ++j)
|
for (j = 0; j < (int)s.img_y; ++j)
|
||||||
{
|
{
|
||||||
for (i = 0; i < (int)s.img_x; i += 2)
|
for (i = 0; i < (int)s.img_x; i += 2)
|
||||||
@@ -163,19 +209,28 @@ namespace Misaki.HighPerformance.Image
|
|||||||
_out_[z++] = pal[v][1];
|
_out_[z++] = pal[v][1];
|
||||||
_out_[z++] = pal[v][2];
|
_out_[z++] = pal[v][2];
|
||||||
if (target == 4)
|
if (target == 4)
|
||||||
|
{
|
||||||
_out_[z++] = 255;
|
_out_[z++] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
if (i + 1 == (int)s.img_x)
|
if (i + 1 == (int)s.img_x)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
v = info.bpp == 8 ? stbi__get8(s) : v2;
|
v = info.bpp == 8 ? stbi__get8(s) : v2;
|
||||||
_out_[z++] = pal[v][0];
|
_out_[z++] = pal[v][0];
|
||||||
_out_[z++] = pal[v][1];
|
_out_[z++] = pal[v][1];
|
||||||
_out_[z++] = pal[v][2];
|
_out_[z++] = pal[v][2];
|
||||||
if (target == 4)
|
if (target == 4)
|
||||||
|
{
|
||||||
_out_[z++] = 255;
|
_out_[z++] = 255;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stbi__skip(s, pad);
|
stbi__skip(s, pad);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -191,17 +246,30 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var easy = 0;
|
var easy = 0;
|
||||||
stbi__skip(s, info.offset - info.extra_read - info.hsz);
|
stbi__skip(s, info.offset - info.extra_read - info.hsz);
|
||||||
if (info.bpp == 24)
|
if (info.bpp == 24)
|
||||||
|
{
|
||||||
width = (int)(3 * s.img_x);
|
width = (int)(3 * s.img_x);
|
||||||
|
}
|
||||||
else if (info.bpp == 16)
|
else if (info.bpp == 16)
|
||||||
|
{
|
||||||
width = (int)(2 * s.img_x);
|
width = (int)(2 * s.img_x);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
width = 0;
|
width = 0;
|
||||||
|
}
|
||||||
|
|
||||||
pad = -width & 3;
|
pad = -width & 3;
|
||||||
if (info.bpp == 24)
|
if (info.bpp == 24)
|
||||||
|
{
|
||||||
easy = 1;
|
easy = 1;
|
||||||
|
}
|
||||||
else if (info.bpp == 32)
|
else if (info.bpp == 32)
|
||||||
|
{
|
||||||
if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
|
if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
|
||||||
|
{
|
||||||
easy = 2;
|
easy = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (easy == 0)
|
if (easy == 0)
|
||||||
{
|
{
|
||||||
@@ -240,7 +308,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
a = (byte)(easy == 2 ? stbi__get8(s) : 255);
|
a = (byte)(easy == 2 ? stbi__get8(s) : 255);
|
||||||
all_a |= a;
|
all_a |= a;
|
||||||
if (target == 4)
|
if (target == 4)
|
||||||
|
{
|
||||||
_out_[z++] = a;
|
_out_[z++] = a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -256,7 +326,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
a = (uint)(ma != 0 ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
|
a = (uint)(ma != 0 ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
|
||||||
all_a |= a;
|
all_a |= a;
|
||||||
if (target == 4)
|
if (target == 4)
|
||||||
|
{
|
||||||
_out_[z++] = (byte)(a & 255);
|
_out_[z++] = (byte)(a & 255);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,8 +337,12 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (target == 4 && all_a == 0)
|
if (target == 4 && all_a == 0)
|
||||||
|
{
|
||||||
for (i = (int)(4 * s.img_x * s.img_y - 1); i >= 0; i -= 4)
|
for (i = (int)(4 * s.img_x * s.img_y - 1); i >= 0; i -= 4)
|
||||||
|
{
|
||||||
_out_[i] = 255;
|
_out_[i] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flip_vertically != 0)
|
if (flip_vertically != 0)
|
||||||
{
|
{
|
||||||
@@ -288,13 +364,18 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
_out_ = stbi__convert_format(_out_, target, req_comp, s.img_x, s.img_y);
|
_out_ = stbi__convert_format(_out_, target, req_comp, s.img_x, s.img_y);
|
||||||
if (_out_ == null)
|
if (_out_ == null)
|
||||||
|
{
|
||||||
return _out_;
|
return _out_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*x = (int)s.img_x;
|
*x = (int)s.img_x;
|
||||||
*y = (int)s.img_y;
|
*y = (int)s.img_y;
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = s.img_n;
|
*comp = s.img_n;
|
||||||
|
}
|
||||||
|
|
||||||
return _out_;
|
return _out_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,15 +392,25 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x != null)
|
if (x != null)
|
||||||
|
{
|
||||||
*x = (int)s.img_x;
|
*x = (int)s.img_x;
|
||||||
|
}
|
||||||
|
|
||||||
if (y != null)
|
if (y != null)
|
||||||
|
{
|
||||||
*y = (int)s.img_y;
|
*y = (int)s.img_y;
|
||||||
|
}
|
||||||
|
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
{
|
{
|
||||||
if (info.bpp == 24 && info.ma == 0xff000000)
|
if (info.bpp == 24 && info.ma == 0xff000000)
|
||||||
|
{
|
||||||
*comp = 3;
|
*comp = 3;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
*comp = info.ma != 0 ? 4 : 3;
|
*comp = info.ma != 0 ? 4 : 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -330,9 +421,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var r = 0;
|
var r = 0;
|
||||||
var sz = 0;
|
var sz = 0;
|
||||||
if (stbi__get8(s) != 66)
|
if (stbi__get8(s) != 66)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get8(s) != 77)
|
if (stbi__get8(s) != 77)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
stbi__get16le(s);
|
stbi__get16le(s);
|
||||||
stbi__get16le(s);
|
stbi__get16le(s);
|
||||||
@@ -345,7 +442,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
public static int stbi__bmp_set_mask_defaults(stbi__bmp_data* info, int compress)
|
public static int stbi__bmp_set_mask_defaults(stbi__bmp_data* info, int compress)
|
||||||
{
|
{
|
||||||
if (compress == 3)
|
if (compress == 3)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (compress == 0)
|
if (compress == 0)
|
||||||
{
|
{
|
||||||
if (info->bpp == 16)
|
if (info->bpp == 16)
|
||||||
@@ -377,7 +477,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var hsz = 0;
|
var hsz = 0;
|
||||||
if (stbi__get8(s) != 66 || stbi__get8(s) != 77)
|
if (stbi__get8(s) != 66 || stbi__get8(s) != 77)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("not BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("not BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
stbi__get16le(s);
|
stbi__get16le(s);
|
||||||
stbi__get16le(s);
|
stbi__get16le(s);
|
||||||
@@ -386,9 +489,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
info->mr = info->mg = info->mb = info->ma = 0;
|
info->mr = info->mg = info->mb = info->ma = 0;
|
||||||
info->extra_read = 14;
|
info->extra_read = 14;
|
||||||
if (info->offset < 0)
|
if (info->offset < 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
|
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("unknown BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("unknown BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (hsz == 12)
|
if (hsz == 12)
|
||||||
{
|
{
|
||||||
s.img_x = (uint)stbi__get16le(s);
|
s.img_x = (uint)stbi__get16le(s);
|
||||||
@@ -401,17 +510,29 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stbi__get16le(s) != 1)
|
if (stbi__get16le(s) != 1)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
info->bpp = stbi__get16le(s);
|
info->bpp = stbi__get16le(s);
|
||||||
if (hsz != 12)
|
if (hsz != 12)
|
||||||
{
|
{
|
||||||
var compress = (int)stbi__get32le(s);
|
var compress = (int)stbi__get32le(s);
|
||||||
if (compress == 1 || compress == 2)
|
if (compress == 1 || compress == 2)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("BMP RLE") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("BMP RLE") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (compress >= 4)
|
if (compress >= 4)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("BMP JPEG/PNG") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("BMP JPEG/PNG") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (compress == 3 && info->bpp != 16 && info->bpp != 32)
|
if (compress == 3 && info->bpp != 16 && info->bpp != 32)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
@@ -440,7 +561,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
info->mb = stbi__get32le(s);
|
info->mb = stbi__get32le(s);
|
||||||
info->extra_read += 12;
|
info->extra_read += 12;
|
||||||
if (info->mr == info->mg && info->mg == info->mb)
|
if (info->mr == info->mg && info->mg == info->mb)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -452,16 +575,24 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var i = 0;
|
var i = 0;
|
||||||
if (hsz != 108 && hsz != 124)
|
if (hsz != 108 && hsz != 124)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
info->mr = stbi__get32le(s);
|
info->mr = stbi__get32le(s);
|
||||||
info->mg = stbi__get32le(s);
|
info->mg = stbi__get32le(s);
|
||||||
info->mb = stbi__get32le(s);
|
info->mb = stbi__get32le(s);
|
||||||
info->ma = stbi__get32le(s);
|
info->ma = stbi__get32le(s);
|
||||||
if (compress != 3)
|
if (compress != 3)
|
||||||
|
{
|
||||||
stbi__bmp_set_mask_defaults(info, compress);
|
stbi__bmp_set_mask_defaults(info, compress);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
for (i = 0; i < 12; ++i)
|
for (i = 0; i < 12; ++i)
|
||||||
|
{
|
||||||
stbi__get32le(s);
|
stbi__get32le(s);
|
||||||
|
}
|
||||||
|
|
||||||
if (hsz == 124)
|
if (hsz == 124)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -100,16 +100,25 @@ namespace Misaki.HighPerformance.Image
|
|||||||
public static int stbi__addsizes_valid(int a, int b)
|
public static int stbi__addsizes_valid(int a, int b)
|
||||||
{
|
{
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return a <= 2147483647 - b ? 1 : 0;
|
return a <= 2147483647 - b ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int stbi__mul2sizes_valid(int a, int b)
|
public static int stbi__mul2sizes_valid(int a, int b)
|
||||||
{
|
{
|
||||||
if (a < 0 || b < 0)
|
if (a < 0 || b < 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (b == 0)
|
if (b == 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return a <= 2147483647 / b ? 1 : 0;
|
return a <= 2147483647 / b ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,41 +146,65 @@ namespace Misaki.HighPerformance.Image
|
|||||||
public static void* stbi__malloc_mad2(int a, int b, int add)
|
public static void* stbi__malloc_mad2(int a, int b, int add)
|
||||||
{
|
{
|
||||||
if (stbi__mad2sizes_valid(a, b, add) == 0)
|
if (stbi__mad2sizes_valid(a, b, add) == 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return stbi__malloc((ulong)(a * b + add));
|
return stbi__malloc((ulong)(a * b + add));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void* stbi__malloc_mad3(int a, int b, int c, int add)
|
public static void* stbi__malloc_mad3(int a, int b, int c, int add)
|
||||||
{
|
{
|
||||||
if (stbi__mad3sizes_valid(a, b, c, add) == 0)
|
if (stbi__mad3sizes_valid(a, b, c, add) == 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return stbi__malloc((ulong)(a * b * c + add));
|
return stbi__malloc((ulong)(a * b * c + add));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void* stbi__malloc_mad4(int a, int b, int c, int d, int add)
|
public static void* stbi__malloc_mad4(int a, int b, int c, int d, int add)
|
||||||
{
|
{
|
||||||
if (stbi__mad4sizes_valid(a, b, c, d, add) == 0)
|
if (stbi__mad4sizes_valid(a, b, c, d, add) == 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return stbi__malloc((ulong)(a * b * c * d + add));
|
return stbi__malloc((ulong)(a * b * c * d + add));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int stbi__addints_valid(int a, int b)
|
public static int stbi__addints_valid(int a, int b)
|
||||||
{
|
{
|
||||||
if (a >= 0 != b >= 0)
|
if (a >= 0 != b >= 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (a < 0 && b < 0)
|
if (a < 0 && b < 0)
|
||||||
|
{
|
||||||
return a >= -2147483647 - 1 - b ? 1 : 0;
|
return a >= -2147483647 - 1 - b ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
return a <= 2147483647 - b ? 1 : 0;
|
return a <= 2147483647 - b ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int stbi__mul2shorts_valid(int a, int b)
|
public static int stbi__mul2shorts_valid(int a, int b)
|
||||||
{
|
{
|
||||||
if (b == 0 || b == -1)
|
if (b == 0 || b == -1)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (a >= 0 == b >= 0)
|
if (a >= 0 == b >= 0)
|
||||||
|
{
|
||||||
return a <= 32767 / b ? 1 : 0;
|
return a <= 32767 / b ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
|
{
|
||||||
return a <= -32768 / b ? 1 : 0;
|
return a <= -32768 / b ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
return a >= -32768 / b ? 1 : 0;
|
return a >= -32768 / b ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +215,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var n = 0;
|
var n = 0;
|
||||||
float* output;
|
float* output;
|
||||||
if (data == null)
|
if (data == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
output = (float*)stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
|
output = (float*)stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
|
||||||
if (output == null)
|
if (output == null)
|
||||||
{
|
{
|
||||||
@@ -191,17 +227,30 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((comp & 1) != 0)
|
if ((comp & 1) != 0)
|
||||||
|
{
|
||||||
n = comp;
|
n = comp;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
n = comp - 1;
|
n = comp - 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < x * y; ++i)
|
for (i = 0; i < x * y; ++i)
|
||||||
|
{
|
||||||
for (k = 0; k < n; ++k)
|
for (k = 0; k < n; ++k)
|
||||||
|
{
|
||||||
output[i * comp + k] =
|
output[i * comp + k] =
|
||||||
(float)(CRuntime.pow(data[i * comp + k] / 255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
|
(float)(CRuntime.pow(data[i * comp + k] / 255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (n < comp)
|
if (n < comp)
|
||||||
|
{
|
||||||
for (i = 0; i < x * y; ++i)
|
for (i = 0; i < x * y; ++i)
|
||||||
|
{
|
||||||
output[i * comp + n] = data[i * comp + n] / 255.0f;
|
output[i * comp + n] = data[i * comp + n] / 255.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.free(data);
|
CRuntime.free(data);
|
||||||
return output;
|
return output;
|
||||||
@@ -215,15 +264,30 @@ namespace Misaki.HighPerformance.Image
|
|||||||
ri->channel_order = STBI_ORDER_RGB;
|
ri->channel_order = STBI_ORDER_RGB;
|
||||||
ri->num_channels = 0;
|
ri->num_channels = 0;
|
||||||
if (stbi__png_test(s) != 0)
|
if (stbi__png_test(s) != 0)
|
||||||
|
{
|
||||||
return stbi__png_load(s, x, y, comp, req_comp, ri);
|
return stbi__png_load(s, x, y, comp, req_comp, ri);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__bmp_test(s) != 0)
|
if (stbi__bmp_test(s) != 0)
|
||||||
|
{
|
||||||
return stbi__bmp_load(s, x, y, comp, req_comp, ri);
|
return stbi__bmp_load(s, x, y, comp, req_comp, ri);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__gif_test(s) != 0)
|
if (stbi__gif_test(s) != 0)
|
||||||
|
{
|
||||||
return stbi__gif_load(s, x, y, comp, req_comp, ri);
|
return stbi__gif_load(s, x, y, comp, req_comp, ri);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__psd_test(s) != 0)
|
if (stbi__psd_test(s) != 0)
|
||||||
|
{
|
||||||
return stbi__psd_load(s, x, y, comp, req_comp, ri, bpc);
|
return stbi__psd_load(s, x, y, comp, req_comp, ri, bpc);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__jpeg_test(s) != 0)
|
if (stbi__jpeg_test(s) != 0)
|
||||||
|
{
|
||||||
return stbi__jpeg_load(s, x, y, comp, req_comp, ri);
|
return stbi__jpeg_load(s, x, y, comp, req_comp, ri);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__hdr_test(s) != 0)
|
if (stbi__hdr_test(s) != 0)
|
||||||
{
|
{
|
||||||
var hdr = stbi__hdr_load(s, x, y, comp, req_comp, ri);
|
var hdr = stbi__hdr_load(s, x, y, comp, req_comp, ri);
|
||||||
@@ -231,7 +295,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stbi__tga_test(s) != 0)
|
if (stbi__tga_test(s) != 0)
|
||||||
|
{
|
||||||
return stbi__tga_load(s, x, y, comp, req_comp, ri);
|
return stbi__tga_load(s, x, y, comp, req_comp, ri);
|
||||||
|
}
|
||||||
|
|
||||||
return (byte*)(ulong)(stbi__err("unknown image type") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("unknown image type") != 0 ? 0 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,9 +309,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
byte* reduced;
|
byte* reduced;
|
||||||
reduced = (byte*)stbi__malloc((ulong)img_len);
|
reduced = (byte*)stbi__malloc((ulong)img_len);
|
||||||
if (reduced == null)
|
if (reduced == null)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < img_len; ++i)
|
for (i = 0; i < img_len; ++i)
|
||||||
|
{
|
||||||
reduced[i] = (byte)((orig[i] >> 8) & 0xFF);
|
reduced[i] = (byte)((orig[i] >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.free(orig);
|
CRuntime.free(orig);
|
||||||
return reduced;
|
return reduced;
|
||||||
@@ -257,9 +329,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
ushort* enlarged;
|
ushort* enlarged;
|
||||||
enlarged = (ushort*)stbi__malloc((ulong)(img_len * 2));
|
enlarged = (ushort*)stbi__malloc((ulong)(img_len * 2));
|
||||||
if (enlarged == null)
|
if (enlarged == null)
|
||||||
|
{
|
||||||
return (ushort*)(byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (ushort*)(byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < img_len; ++i)
|
for (i = 0; i < img_len; ++i)
|
||||||
|
{
|
||||||
enlarged[i] = (ushort)((orig[i] << 8) + orig[i]);
|
enlarged[i] = (ushort)((orig[i] << 8) + orig[i]);
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.free(orig);
|
CRuntime.free(orig);
|
||||||
return enlarged;
|
return enlarged;
|
||||||
@@ -306,7 +383,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var ri = new stbi__result_info();
|
var ri = new stbi__result_info();
|
||||||
var result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
|
var result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (ri.bits_per_channel != 8)
|
if (ri.bits_per_channel != 8)
|
||||||
{
|
{
|
||||||
result = stbi__convert_16_to_8((ushort*)result, *x, *y, req_comp == 0 ? *comp : req_comp);
|
result = stbi__convert_16_to_8((ushort*)result, *x, *y, req_comp == 0 ? *comp : req_comp);
|
||||||
@@ -329,7 +409,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var ri = new stbi__result_info();
|
var ri = new stbi__result_info();
|
||||||
var result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
|
var result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (ri.bits_per_channel != 16)
|
if (ri.bits_per_channel != 16)
|
||||||
{
|
{
|
||||||
result = stbi__convert_8_to_16((byte*)result, *x, *y, req_comp == 0 ? *comp : req_comp);
|
result = stbi__convert_8_to_16((byte*)result, *x, *y, req_comp == 0 ? *comp : req_comp);
|
||||||
@@ -366,13 +449,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var ri = new stbi__result_info();
|
var ri = new stbi__result_info();
|
||||||
var hdr_data = stbi__hdr_load(s, x, y, comp, req_comp, &ri);
|
var hdr_data = stbi__hdr_load(s, x, y, comp, req_comp, &ri);
|
||||||
if (hdr_data != null)
|
if (hdr_data != null)
|
||||||
|
{
|
||||||
stbi__float_postprocess(hdr_data, x, y, comp, req_comp);
|
stbi__float_postprocess(hdr_data, x, y, comp, req_comp);
|
||||||
|
}
|
||||||
|
|
||||||
return hdr_data;
|
return hdr_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
|
data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
|
||||||
if (data != null)
|
if (data != null)
|
||||||
|
{
|
||||||
return stbi__ldr_to_hdr(data, *x, *y, req_comp != 0 ? req_comp : *comp);
|
return stbi__ldr_to_hdr(data, *x, *y, req_comp != 0 ? req_comp : *comp);
|
||||||
|
}
|
||||||
|
|
||||||
return (float*)(ulong)(stbi__err("unknown image type") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("unknown image type") != 0 ? 0 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +501,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var j = 0;
|
var j = 0;
|
||||||
byte* good;
|
byte* good;
|
||||||
if (req_comp == img_n)
|
if (req_comp == img_n)
|
||||||
|
{
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
good = (byte*)stbi__malloc_mad3(req_comp, (int)x, (int)y, 0);
|
good = (byte*)stbi__malloc_mad3(req_comp, (int)x, (int)y, 0);
|
||||||
if (good == null)
|
if (good == null)
|
||||||
{
|
{
|
||||||
@@ -436,7 +528,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 1 * 8 + 3:
|
case 1 * 8 + 3:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 1, dest += 3)
|
for (i = (int)(x - 1); i >= 0; --i, src += 1, dest += 3)
|
||||||
|
{
|
||||||
dest[0] = dest[1] = dest[2] = src[0];
|
dest[0] = dest[1] = dest[2] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 1 * 8 + 4:
|
case 1 * 8 + 4:
|
||||||
@@ -449,12 +543,16 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 2 * 8 + 1:
|
case 2 * 8 + 1:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 1)
|
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 1)
|
||||||
|
{
|
||||||
dest[0] = src[0];
|
dest[0] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 2 * 8 + 3:
|
case 2 * 8 + 3:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 3)
|
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 3)
|
||||||
|
{
|
||||||
dest[0] = dest[1] = dest[2] = src[0];
|
dest[0] = dest[1] = dest[2] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 2 * 8 + 4:
|
case 2 * 8 + 4:
|
||||||
@@ -477,7 +575,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 3 * 8 + 1:
|
case 3 * 8 + 1:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 3, dest += 1)
|
for (i = (int)(x - 1); i >= 0; --i, src += 3, dest += 1)
|
||||||
|
{
|
||||||
dest[0] = stbi__compute_y(src[0], src[1], src[2]);
|
dest[0] = stbi__compute_y(src[0], src[1], src[2]);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3 * 8 + 2:
|
case 3 * 8 + 2:
|
||||||
@@ -490,7 +590,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 4 * 8 + 1:
|
case 4 * 8 + 1:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 4, dest += 1)
|
for (i = (int)(x - 1); i >= 0; --i, src += 4, dest += 1)
|
||||||
|
{
|
||||||
dest[0] = stbi__compute_y(src[0], src[1], src[2]);
|
dest[0] = stbi__compute_y(src[0], src[1], src[2]);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 4 * 8 + 2:
|
case 4 * 8 + 2:
|
||||||
@@ -533,7 +635,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var j = 0;
|
var j = 0;
|
||||||
ushort* good;
|
ushort* good;
|
||||||
if (req_comp == img_n)
|
if (req_comp == img_n)
|
||||||
|
{
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
good = (ushort*)stbi__malloc((ulong)(req_comp * x * y * 2));
|
good = (ushort*)stbi__malloc((ulong)(req_comp * x * y * 2));
|
||||||
if (good == null)
|
if (good == null)
|
||||||
{
|
{
|
||||||
@@ -557,7 +662,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 1 * 8 + 3:
|
case 1 * 8 + 3:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 1, dest += 3)
|
for (i = (int)(x - 1); i >= 0; --i, src += 1, dest += 3)
|
||||||
|
{
|
||||||
dest[0] = dest[1] = dest[2] = src[0];
|
dest[0] = dest[1] = dest[2] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 1 * 8 + 4:
|
case 1 * 8 + 4:
|
||||||
@@ -570,12 +677,16 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 2 * 8 + 1:
|
case 2 * 8 + 1:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 1)
|
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 1)
|
||||||
|
{
|
||||||
dest[0] = src[0];
|
dest[0] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 2 * 8 + 3:
|
case 2 * 8 + 3:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 3)
|
for (i = (int)(x - 1); i >= 0; --i, src += 2, dest += 3)
|
||||||
|
{
|
||||||
dest[0] = dest[1] = dest[2] = src[0];
|
dest[0] = dest[1] = dest[2] = src[0];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 2 * 8 + 4:
|
case 2 * 8 + 4:
|
||||||
@@ -598,7 +709,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 3 * 8 + 1:
|
case 3 * 8 + 1:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 3, dest += 1)
|
for (i = (int)(x - 1); i >= 0; --i, src += 3, dest += 1)
|
||||||
|
{
|
||||||
dest[0] = stbi__compute_y_16(src[0], src[1], src[2]);
|
dest[0] = stbi__compute_y_16(src[0], src[1], src[2]);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3 * 8 + 2:
|
case 3 * 8 + 2:
|
||||||
@@ -611,7 +724,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
break;
|
break;
|
||||||
case 4 * 8 + 1:
|
case 4 * 8 + 1:
|
||||||
for (i = (int)(x - 1); i >= 0; --i, src += 4, dest += 1)
|
for (i = (int)(x - 1); i >= 0; --i, src += 4, dest += 1)
|
||||||
|
{
|
||||||
dest[0] = stbi__compute_y_16(src[0], src[1], src[2]);
|
dest[0] = stbi__compute_y_16(src[0], src[1], src[2]);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 4 * 8 + 2:
|
case 4 * 8 + 2:
|
||||||
@@ -648,9 +763,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if ((uint)x > 255)
|
if ((uint)x > 255)
|
||||||
{
|
{
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (x > 255)
|
if (x > 255)
|
||||||
|
{
|
||||||
return 255;
|
return 255;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte)x;
|
return (byte)x;
|
||||||
@@ -680,7 +800,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var n = 0;
|
var n = 0;
|
||||||
if (z == 0)
|
if (z == 0)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (z >= 0x10000)
|
if (z >= 0x10000)
|
||||||
{
|
{
|
||||||
n += 16;
|
n += 16;
|
||||||
@@ -706,7 +829,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (z >= 0x00002)
|
if (z >= 0x00002)
|
||||||
|
{
|
||||||
n += 1;
|
n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -724,9 +849,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
public static int stbi__shiftsigned(uint v, int shift, int bits)
|
public static int stbi__shiftsigned(uint v, int shift, int bits)
|
||||||
{
|
{
|
||||||
if (shift < 0)
|
if (shift < 0)
|
||||||
|
{
|
||||||
v <<= -shift;
|
v <<= -shift;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
v >>= shift;
|
v >>= shift;
|
||||||
|
}
|
||||||
|
|
||||||
v >>= 8 - bits;
|
v >>= 8 - bits;
|
||||||
return (int)(v * stbi__shiftsigned_mul_table[bits]) >> stbi__shiftsigned_shift_table[bits];
|
return (int)(v * stbi__shiftsigned_mul_table[bits]) >> stbi__shiftsigned_shift_table[bits];
|
||||||
}
|
}
|
||||||
@@ -734,28 +864,55 @@ namespace Misaki.HighPerformance.Image
|
|||||||
public static int stbi__info_main(stbi__context s, int* x, int* y, int* comp)
|
public static int stbi__info_main(stbi__context s, int* x, int* y, int* comp)
|
||||||
{
|
{
|
||||||
if (stbi__jpeg_info(s, x, y, comp) != 0)
|
if (stbi__jpeg_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__png_info(s, x, y, comp) != 0)
|
if (stbi__png_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__gif_info(s, x, y, comp) != 0)
|
if (stbi__gif_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__bmp_info(s, x, y, comp) != 0)
|
if (stbi__bmp_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__psd_info(s, x, y, comp) != 0)
|
if (stbi__psd_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__hdr_info(s, x, y, comp) != 0)
|
if (stbi__hdr_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__tga_info(s, x, y, comp) != 0)
|
if (stbi__tga_info(s, x, y, comp) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return stbi__err("unknown image type");
|
return stbi__err("unknown image type");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int stbi__is_16_main(stbi__context s)
|
public static int stbi__is_16_main(stbi__context s)
|
||||||
{
|
{
|
||||||
if (stbi__png_is16(s) != 0)
|
if (stbi__png_is16(s) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__psd_is16(s) != 0)
|
if (stbi__psd_is16(s) != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
*x = g.w;
|
*x = g.w;
|
||||||
*y = g.h;
|
*y = g.h;
|
||||||
if (req_comp != 0 && req_comp != 4)
|
if (req_comp != 0 && req_comp != 4)
|
||||||
|
{
|
||||||
u = stbi__convert_format(u, 4, req_comp, (uint)g.w, (uint)g.h);
|
u = stbi__convert_format(u, 4, req_comp, (uint)g.w, (uint)g.h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (g._out_ != null)
|
else if (g._out_ != null)
|
||||||
{
|
{
|
||||||
@@ -51,7 +53,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var out_size = 0;
|
var out_size = 0;
|
||||||
var delays_size = 0;
|
var delays_size = 0;
|
||||||
if (delays != null)
|
if (delays != null)
|
||||||
|
{
|
||||||
*delays = null;
|
*delays = null;
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
u = stbi__gif_load_next(s, g, comp, req_comp, two_back);
|
u = stbi__gif_load_next(s, g, comp, req_comp, two_back);
|
||||||
@@ -65,14 +70,20 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
void* tmp = (byte*)CRuntime.realloc(_out_, (ulong)(layers * stride));
|
void* tmp = (byte*)CRuntime.realloc(_out_, (ulong)(layers * stride));
|
||||||
if (tmp == null)
|
if (tmp == null)
|
||||||
|
{
|
||||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||||
|
}
|
||||||
|
|
||||||
_out_ = (byte*)tmp;
|
_out_ = (byte*)tmp;
|
||||||
out_size = layers * stride;
|
out_size = layers * stride;
|
||||||
if (delays != null)
|
if (delays != null)
|
||||||
{
|
{
|
||||||
var new_delays = (int*)CRuntime.realloc(*delays, (ulong)(sizeof(int) * layers));
|
var new_delays = (int*)CRuntime.realloc(*delays, (ulong)(sizeof(int) * layers));
|
||||||
if (new_delays == null)
|
if (new_delays == null)
|
||||||
|
{
|
||||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||||
|
}
|
||||||
|
|
||||||
*delays = new_delays;
|
*delays = new_delays;
|
||||||
delays_size = layers * sizeof(int);
|
delays_size = layers * sizeof(int);
|
||||||
}
|
}
|
||||||
@@ -81,22 +92,33 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
_out_ = (byte*)stbi__malloc((ulong)(layers * stride));
|
_out_ = (byte*)stbi__malloc((ulong)(layers * stride));
|
||||||
if (_out_ == null)
|
if (_out_ == null)
|
||||||
|
{
|
||||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||||
|
}
|
||||||
|
|
||||||
out_size = layers * stride;
|
out_size = layers * stride;
|
||||||
if (delays != null)
|
if (delays != null)
|
||||||
{
|
{
|
||||||
*delays = (int*)stbi__malloc((ulong)(layers * sizeof(int)));
|
*delays = (int*)stbi__malloc((ulong)(layers * sizeof(int)));
|
||||||
if (*delays == null)
|
if (*delays == null)
|
||||||
|
{
|
||||||
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
return stbi__load_gif_main_outofmem(g, _out_, delays);
|
||||||
|
}
|
||||||
|
|
||||||
delays_size = layers * sizeof(int);
|
delays_size = layers * sizeof(int);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CRuntime.memcpy(_out_ + (layers - 1) * stride, u, (ulong)stride);
|
CRuntime.memcpy(_out_ + (layers - 1) * stride, u, (ulong)stride);
|
||||||
if (layers >= 2)
|
if (layers >= 2)
|
||||||
|
{
|
||||||
two_back = _out_ - 2 * stride;
|
two_back = _out_ - 2 * stride;
|
||||||
|
}
|
||||||
|
|
||||||
if (delays != null)
|
if (delays != null)
|
||||||
|
{
|
||||||
(*delays)[layers - 1U] = g.delay;
|
(*delays)[layers - 1U] = g.delay;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (u != null);
|
} while (u != null);
|
||||||
|
|
||||||
@@ -104,7 +126,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
CRuntime.free(g.history);
|
CRuntime.free(g.history);
|
||||||
CRuntime.free(g.background);
|
CRuntime.free(g.background);
|
||||||
if (req_comp != 0 && req_comp != 4)
|
if (req_comp != 0 && req_comp != 4)
|
||||||
|
{
|
||||||
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)(layers * g.w), (uint)g.h);
|
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)(layers * g.w), (uint)g.h);
|
||||||
|
}
|
||||||
|
|
||||||
*z = layers;
|
*z = layers;
|
||||||
return _out_;
|
return _out_;
|
||||||
}
|
}
|
||||||
@@ -121,12 +146,21 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var sz = 0;
|
var sz = 0;
|
||||||
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
sz = stbi__get8(s);
|
sz = stbi__get8(s);
|
||||||
if (sz != 57 && sz != 55)
|
if (sz != 57 && sz != 55)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get8(s) != 97)
|
if (stbi__get8(s) != 97)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,12 +180,21 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
byte version = 0;
|
byte version = 0;
|
||||||
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
|
||||||
|
{
|
||||||
return stbi__err("not GIF");
|
return stbi__err("not GIF");
|
||||||
|
}
|
||||||
|
|
||||||
version = stbi__get8(s);
|
version = stbi__get8(s);
|
||||||
if (version != 55 && version != 57)
|
if (version != 55 && version != 57)
|
||||||
|
{
|
||||||
return stbi__err("not GIF");
|
return stbi__err("not GIF");
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get8(s) != 97)
|
if (stbi__get8(s) != 97)
|
||||||
|
{
|
||||||
return stbi__err("not GIF");
|
return stbi__err("not GIF");
|
||||||
|
}
|
||||||
|
|
||||||
stbi__g_failure_reason = "";
|
stbi__g_failure_reason = "";
|
||||||
g.w = stbi__get16le(s);
|
g.w = stbi__get16le(s);
|
||||||
g.h = stbi__get16le(s);
|
g.h = stbi__get16le(s);
|
||||||
@@ -160,15 +203,30 @@ namespace Misaki.HighPerformance.Image
|
|||||||
g.ratio = stbi__get8(s);
|
g.ratio = stbi__get8(s);
|
||||||
g.transparent = -1;
|
g.transparent = -1;
|
||||||
if (g.w > 1 << 24)
|
if (g.w > 1 << 24)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
|
|
||||||
if (g.h > 1 << 24)
|
if (g.h > 1 << 24)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
|
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = 4;
|
*comp = 4;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_info != 0)
|
if (is_info != 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((g.flags & 0x80) != 0)
|
if ((g.flags & 0x80) != 0)
|
||||||
|
{
|
||||||
stbi__gif_parse_colortable(s, g.pal, 2 << (g.flags & 7), -1);
|
stbi__gif_parse_colortable(s, g.pal, 2 << (g.flags & 7), -1);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +234,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var g = new stbi__gif();
|
var g = new stbi__gif();
|
||||||
if (g == null)
|
if (g == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__gif_header(s, g, comp, 1) == 0)
|
if (stbi__gif_header(s, g, comp, 1) == 0)
|
||||||
{
|
{
|
||||||
stbi__rewind(s);
|
stbi__rewind(s);
|
||||||
@@ -184,9 +245,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x != null)
|
if (x != null)
|
||||||
|
{
|
||||||
*x = g.w;
|
*x = g.w;
|
||||||
|
}
|
||||||
|
|
||||||
if (y != null)
|
if (y != null)
|
||||||
|
{
|
||||||
*y = g.h;
|
*y = g.h;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,9 +262,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
byte* p;
|
byte* p;
|
||||||
var idx = 0;
|
var idx = 0;
|
||||||
if (g.codes[code].prefix >= 0)
|
if (g.codes[code].prefix >= 0)
|
||||||
|
{
|
||||||
stbi__out_gif_code(g, (ushort)g.codes[code].prefix);
|
stbi__out_gif_code(g, (ushort)g.codes[code].prefix);
|
||||||
|
}
|
||||||
|
|
||||||
if (g.cur_y >= g.max_y)
|
if (g.cur_y >= g.max_y)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
idx = g.cur_x + g.cur_y;
|
idx = g.cur_x + g.cur_y;
|
||||||
p = &g._out_[idx];
|
p = &g._out_[idx];
|
||||||
g.history[idx / 4] = 1;
|
g.history[idx / 4] = 1;
|
||||||
@@ -240,7 +313,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
stbi__gif_lzw* p;
|
stbi__gif_lzw* p;
|
||||||
lzw_cs = stbi__get8(s);
|
lzw_cs = stbi__get8(s);
|
||||||
if (lzw_cs > 12)
|
if (lzw_cs > 12)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
clear = 1 << lzw_cs;
|
clear = 1 << lzw_cs;
|
||||||
first = 1;
|
first = 1;
|
||||||
codesize = lzw_cs + 1;
|
codesize = lzw_cs + 1;
|
||||||
@@ -258,13 +334,16 @@ namespace Misaki.HighPerformance.Image
|
|||||||
oldcode = -1;
|
oldcode = -1;
|
||||||
len = 0;
|
len = 0;
|
||||||
for (; ; )
|
for (; ; )
|
||||||
|
{
|
||||||
if (valid_bits < codesize)
|
if (valid_bits < codesize)
|
||||||
{
|
{
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
len = stbi__get8(s);
|
len = stbi__get8(s);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
|
{
|
||||||
return g._out_;
|
return g._out_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
--len;
|
--len;
|
||||||
@@ -288,20 +367,29 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
stbi__skip(s, len);
|
stbi__skip(s, len);
|
||||||
while ((len = stbi__get8(s)) > 0)
|
while ((len = stbi__get8(s)) > 0)
|
||||||
|
{
|
||||||
stbi__skip(s, len);
|
stbi__skip(s, len);
|
||||||
|
}
|
||||||
|
|
||||||
return g._out_;
|
return g._out_;
|
||||||
}
|
}
|
||||||
else if (code <= avail)
|
else if (code <= avail)
|
||||||
{
|
{
|
||||||
if (first != 0)
|
if (first != 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("no clear code") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("no clear code") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (oldcode >= 0)
|
if (oldcode >= 0)
|
||||||
{
|
{
|
||||||
fixed (stbi__gif_lzw* p2 = &g.codes[avail++])
|
fixed (stbi__gif_lzw* p2 = &g.codes[avail++])
|
||||||
{
|
{
|
||||||
p = p2;
|
p = p2;
|
||||||
if (avail > 8192)
|
if (avail > 8192)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too many codes") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too many codes") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
p->prefix = (short)oldcode;
|
p->prefix = (short)oldcode;
|
||||||
p->first = g.codes[oldcode].first;
|
p->first = g.codes[oldcode].first;
|
||||||
p->suffix = code == avail ? p->first : g.codes[code].first;
|
p->suffix = code == avail ? p->first : g.codes[code].first;
|
||||||
@@ -326,6 +414,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
return (byte*)(ulong)(stbi__err("illegal code in raster") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("illegal code in raster") != 0 ? 0 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte* stbi__gif_load_next(stbi__context s, stbi__gif g, int* comp, int req_comp, byte* two_back)
|
public static byte* stbi__gif_load_next(stbi__context s, stbi__gif g, int* comp, int req_comp, byte* two_back)
|
||||||
@@ -338,15 +427,24 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if (g._out_ == null)
|
if (g._out_ == null)
|
||||||
{
|
{
|
||||||
if (stbi__gif_header(s, g, comp, 0) == 0)
|
if (stbi__gif_header(s, g, comp, 0) == 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__mad3sizes_valid(4, g.w, g.h, 0) == 0)
|
if (stbi__mad3sizes_valid(4, g.w, g.h, 0) == 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
pcount = g.w * g.h;
|
pcount = g.w * g.h;
|
||||||
g._out_ = (byte*)stbi__malloc((ulong)(4 * pcount));
|
g._out_ = (byte*)stbi__malloc((ulong)(4 * pcount));
|
||||||
g.background = (byte*)stbi__malloc((ulong)(4 * pcount));
|
g.background = (byte*)stbi__malloc((ulong)(4 * pcount));
|
||||||
g.history = (byte*)stbi__malloc((ulong)pcount);
|
g.history = (byte*)stbi__malloc((ulong)pcount);
|
||||||
if (g._out_ == null || g.background == null || g.history == null)
|
if (g._out_ == null || g.background == null || g.history == null)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.memset(g._out_, 0x00, (ulong)(4 * pcount));
|
CRuntime.memset(g._out_, 0x00, (ulong)(4 * pcount));
|
||||||
CRuntime.memset(g.background, 0x00, (ulong)(4 * pcount));
|
CRuntime.memset(g.background, 0x00, (ulong)(4 * pcount));
|
||||||
CRuntime.memset(g.history, 0x00, (ulong)pcount);
|
CRuntime.memset(g.history, 0x00, (ulong)pcount);
|
||||||
@@ -357,18 +455,29 @@ namespace Misaki.HighPerformance.Image
|
|||||||
dispose = (g.eflags & 0x1C) >> 2;
|
dispose = (g.eflags & 0x1C) >> 2;
|
||||||
pcount = g.w * g.h;
|
pcount = g.w * g.h;
|
||||||
if (dispose == 3 && two_back == null)
|
if (dispose == 3 && two_back == null)
|
||||||
|
{
|
||||||
dispose = 2;
|
dispose = 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (dispose == 3)
|
if (dispose == 3)
|
||||||
{
|
{
|
||||||
for (pi = 0; pi < pcount; ++pi)
|
for (pi = 0; pi < pcount; ++pi)
|
||||||
|
{
|
||||||
if (g.history[pi] != 0)
|
if (g.history[pi] != 0)
|
||||||
|
{
|
||||||
CRuntime.memcpy(&g._out_[pi * 4], &two_back[pi * 4], (ulong)4);
|
CRuntime.memcpy(&g._out_[pi * 4], &two_back[pi * 4], (ulong)4);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (dispose == 2)
|
else if (dispose == 2)
|
||||||
{
|
{
|
||||||
for (pi = 0; pi < pcount; ++pi)
|
for (pi = 0; pi < pcount; ++pi)
|
||||||
|
{
|
||||||
if (g.history[pi] != 0)
|
if (g.history[pi] != 0)
|
||||||
|
{
|
||||||
CRuntime.memcpy(&g._out_[pi * 4], &g.background[pi * 4], (ulong)4);
|
CRuntime.memcpy(&g._out_[pi * 4], &g.background[pi * 4], (ulong)4);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CRuntime.memcpy(g.background, g._out_, (ulong)(4 * g.w * g.h));
|
CRuntime.memcpy(g.background, g._out_, (ulong)(4 * g.w * g.h));
|
||||||
@@ -392,7 +501,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
w = stbi__get16le(s);
|
w = stbi__get16le(s);
|
||||||
h = stbi__get16le(s);
|
h = stbi__get16le(s);
|
||||||
if (x + w > g.w || y + h > g.h)
|
if (x + w > g.w || y + h > g.h)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad Image Descriptor") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad Image Descriptor") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
g.line_size = g.w * 4;
|
g.line_size = g.w * 4;
|
||||||
g.start_x = x * 4;
|
g.start_x = x * 4;
|
||||||
g.start_y = y * g.line_size;
|
g.start_y = y * g.line_size;
|
||||||
@@ -401,7 +513,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
g.cur_x = g.start_x;
|
g.cur_x = g.start_x;
|
||||||
g.cur_y = g.start_y;
|
g.cur_y = g.start_y;
|
||||||
if (w == 0)
|
if (w == 0)
|
||||||
|
{
|
||||||
g.cur_y = g.max_y;
|
g.cur_y = g.max_y;
|
||||||
|
}
|
||||||
|
|
||||||
g.lflags = stbi__get8(s);
|
g.lflags = stbi__get8(s);
|
||||||
if ((g.lflags & 0x40) != 0)
|
if ((g.lflags & 0x40) != 0)
|
||||||
{
|
{
|
||||||
@@ -431,10 +546,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
|
|
||||||
o = stbi__process_gif_raster(s, g);
|
o = stbi__process_gif_raster(s, g);
|
||||||
if (o == null)
|
if (o == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
pcount = g.w * g.h;
|
pcount = g.w * g.h;
|
||||||
if (first_frame != 0 && g.bgindex > 0)
|
if (first_frame != 0 && g.bgindex > 0)
|
||||||
|
{
|
||||||
for (pi = 0; pi < pcount; ++pi)
|
for (pi = 0; pi < pcount; ++pi)
|
||||||
|
{
|
||||||
if (g.history[pi] == 0)
|
if (g.history[pi] == 0)
|
||||||
{
|
{
|
||||||
g.pal[g.bgindex][3] = 255;
|
g.pal[g.bgindex][3] = 255;
|
||||||
@@ -443,6 +563,8 @@ namespace Misaki.HighPerformance.Image
|
|||||||
CRuntime.memcpy(&g._out_[pi * 4], ptr, (ulong)4);
|
CRuntime.memcpy(&g._out_[pi * 4], ptr, (ulong)4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
@@ -459,12 +581,17 @@ namespace Misaki.HighPerformance.Image
|
|||||||
g.eflags = stbi__get8(s);
|
g.eflags = stbi__get8(s);
|
||||||
g.delay = 10 * stbi__get16le(s);
|
g.delay = 10 * stbi__get16le(s);
|
||||||
if (g.transparent >= 0)
|
if (g.transparent >= 0)
|
||||||
|
{
|
||||||
g.pal[g.transparent][3] = 255;
|
g.pal[g.transparent][3] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
if ((g.eflags & 0x01) != 0)
|
if ((g.eflags & 0x01) != 0)
|
||||||
{
|
{
|
||||||
g.transparent = stbi__get8(s);
|
g.transparent = stbi__get8(s);
|
||||||
if (g.transparent >= 0)
|
if (g.transparent >= 0)
|
||||||
|
{
|
||||||
g.pal[g.transparent][3] = 0;
|
g.pal[g.transparent][3] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -480,7 +607,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((len = stbi__get8(s)) != 0)
|
while ((len = stbi__get8(s)) != 0)
|
||||||
|
{
|
||||||
stbi__skip(s, len);
|
stbi__skip(s, len);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,9 +628,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
CRuntime.free(g.history);
|
CRuntime.free(g.history);
|
||||||
CRuntime.free(g.background);
|
CRuntime.free(g.background);
|
||||||
if (_out_ != null)
|
if (_out_ != null)
|
||||||
|
{
|
||||||
CRuntime.free(_out_);
|
CRuntime.free(_out_);
|
||||||
|
}
|
||||||
|
|
||||||
if (delays != null && *delays != null)
|
if (delays != null && *delays != null)
|
||||||
|
{
|
||||||
CRuntime.free(*delays);
|
CRuntime.free(*delays);
|
||||||
|
}
|
||||||
|
|
||||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,44 +44,81 @@ namespace Misaki.HighPerformance.Image
|
|||||||
sbyte* headerToken;
|
sbyte* headerToken;
|
||||||
headerToken = stbi__hdr_gettoken(s, buffer);
|
headerToken = stbi__hdr_gettoken(s, buffer);
|
||||||
if (CRuntime.strcmp(headerToken, "#?RADIANCE") != 0 && CRuntime.strcmp(headerToken, "#?RGBE") != 0)
|
if (CRuntime.strcmp(headerToken, "#?RADIANCE") != 0 && CRuntime.strcmp(headerToken, "#?RGBE") != 0)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("not HDR") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("not HDR") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
token = stbi__hdr_gettoken(s, buffer);
|
token = stbi__hdr_gettoken(s, buffer);
|
||||||
if (token[0] == 0)
|
if (token[0] == 0)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (CRuntime.strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0)
|
if (CRuntime.strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0)
|
||||||
|
{
|
||||||
valid = 1;
|
valid = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid == 0)
|
if (valid == 0)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("unsupported format") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("unsupported format") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
token = stbi__hdr_gettoken(s, buffer);
|
token = stbi__hdr_gettoken(s, buffer);
|
||||||
if (CRuntime.strncmp(token, "-Y ", 3) != 0)
|
if (CRuntime.strncmp(token, "-Y ", 3) != 0)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("unsupported data layout") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("unsupported data layout") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
token += 3;
|
token += 3;
|
||||||
height = (int)CRuntime.strtol(token, &token, 10);
|
height = (int)CRuntime.strtol(token, &token, 10);
|
||||||
while (*token == 32)
|
while (*token == 32)
|
||||||
|
{
|
||||||
++token;
|
++token;
|
||||||
|
}
|
||||||
|
|
||||||
if (CRuntime.strncmp(token, "+X ", 3) != 0)
|
if (CRuntime.strncmp(token, "+X ", 3) != 0)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("unsupported data layout") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("unsupported data layout") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
token += 3;
|
token += 3;
|
||||||
width = (int)CRuntime.strtol(token, null, 10);
|
width = (int)CRuntime.strtol(token, null, 10);
|
||||||
if (height > 1 << 24)
|
if (height > 1 << 24)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (width > 1 << 24)
|
if (width > 1 << 24)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
*x = width;
|
*x = width;
|
||||||
*y = height;
|
*y = height;
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = 3;
|
*comp = 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (req_comp == 0)
|
if (req_comp == 0)
|
||||||
|
{
|
||||||
req_comp = 3;
|
req_comp = 3;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0) == 0)
|
if (stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0) == 0)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
hdr_data = (float*)stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
|
hdr_data = (float*)stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
|
||||||
if (hdr_data == null)
|
if (hdr_data == null)
|
||||||
|
{
|
||||||
return (float*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (float*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (width < 8 || width >= 32768)
|
if (width < 8 || width >= 32768)
|
||||||
{
|
{
|
||||||
@@ -176,7 +213,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (z = 0; z < count; ++z)
|
for (z = 0; z < count; ++z)
|
||||||
|
{
|
||||||
scanline[i++ * 4 + k] = value;
|
scanline[i++ * 4 + k] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -188,17 +227,23 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (z = 0; z < count; ++z)
|
for (z = 0; z < count; ++z)
|
||||||
|
{
|
||||||
scanline[i++ * 4 + k] = stbi__get8(s);
|
scanline[i++ * 4 + k] = stbi__get8(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < width; ++i)
|
for (i = 0; i < width; ++i)
|
||||||
|
{
|
||||||
stbi__hdr_convert(hdr_data + (j * width + i) * req_comp, scanline + i * 4, req_comp);
|
stbi__hdr_convert(hdr_data + (j * width + i) * req_comp, scanline + i * 4, req_comp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scanline != null)
|
if (scanline != null)
|
||||||
|
{
|
||||||
CRuntime.free(scanline);
|
CRuntime.free(scanline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
@@ -212,11 +257,20 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var valid = 0;
|
var valid = 0;
|
||||||
var dummy = 0;
|
var dummy = 0;
|
||||||
if (x == null)
|
if (x == null)
|
||||||
|
{
|
||||||
x = &dummy;
|
x = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
if (y == null)
|
if (y == null)
|
||||||
|
{
|
||||||
y = &dummy;
|
y = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
if (comp == null)
|
if (comp == null)
|
||||||
|
{
|
||||||
comp = &dummy;
|
comp = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__hdr_test(s) == 0)
|
if (stbi__hdr_test(s) == 0)
|
||||||
{
|
{
|
||||||
stbi__rewind(s);
|
stbi__rewind(s);
|
||||||
@@ -227,9 +281,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
token = stbi__hdr_gettoken(s, buffer);
|
token = stbi__hdr_gettoken(s, buffer);
|
||||||
if (token[0] == 0)
|
if (token[0] == 0)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (CRuntime.strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0)
|
if (CRuntime.strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0)
|
||||||
|
{
|
||||||
valid = 1;
|
valid = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid == 0)
|
if (valid == 0)
|
||||||
@@ -248,7 +307,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
token += 3;
|
token += 3;
|
||||||
*y = (int)CRuntime.strtol(token, &token, 10);
|
*y = (int)CRuntime.strtol(token, &token, 10);
|
||||||
while (*token == 32)
|
while (*token == 32)
|
||||||
|
{
|
||||||
++token;
|
++token;
|
||||||
|
}
|
||||||
|
|
||||||
if (CRuntime.strncmp(token, "+X ", 3) != 0)
|
if (CRuntime.strncmp(token, "+X ", 3) != 0)
|
||||||
{
|
{
|
||||||
stbi__rewind(s);
|
stbi__rewind(s);
|
||||||
@@ -268,7 +330,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var n = 0;
|
var n = 0;
|
||||||
byte* output;
|
byte* output;
|
||||||
if (data == null)
|
if (data == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
output = (byte*)stbi__malloc_mad3(x, y, comp, 0);
|
output = (byte*)stbi__malloc_mad3(x, y, comp, 0);
|
||||||
if (output == null)
|
if (output == null)
|
||||||
{
|
{
|
||||||
@@ -277,9 +342,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((comp & 1) != 0)
|
if ((comp & 1) != 0)
|
||||||
|
{
|
||||||
n = comp;
|
n = comp;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
n = comp - 1;
|
n = comp - 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < x * y; ++i)
|
for (i = 0; i < x * y; ++i)
|
||||||
{
|
{
|
||||||
for (k = 0; k < n; ++k)
|
for (k = 0; k < n; ++k)
|
||||||
@@ -287,9 +357,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var z = (float)CRuntime.pow(data[i * comp + k] * stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 +
|
var z = (float)CRuntime.pow(data[i * comp + k] * stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 +
|
||||||
0.5f;
|
0.5f;
|
||||||
if (z < 0)
|
if (z < 0)
|
||||||
|
{
|
||||||
z = 0;
|
z = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (z > 255)
|
if (z > 255)
|
||||||
|
{
|
||||||
z = 255;
|
z = 255;
|
||||||
|
}
|
||||||
|
|
||||||
output[i * comp + k] = (byte)(int)z;
|
output[i * comp + k] = (byte)(int)z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,9 +373,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var z = data[i * comp + k] * 255 + 0.5f;
|
var z = data[i * comp + k] * 255 + 0.5f;
|
||||||
if (z < 0)
|
if (z < 0)
|
||||||
|
{
|
||||||
z = 0;
|
z = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (z > 255)
|
if (z > 255)
|
||||||
|
{
|
||||||
z = 255;
|
z = 255;
|
||||||
|
}
|
||||||
|
|
||||||
output[i * comp + k] = (byte)(int)z;
|
output[i * comp + k] = (byte)(int)z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -312,8 +394,13 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var i = 0;
|
var i = 0;
|
||||||
for (i = 0; i < signature.Length; ++i)
|
for (i = 0; i < signature.Length; ++i)
|
||||||
|
{
|
||||||
if (stbi__get8(s) != signature[i])
|
if (stbi__get8(s) != signature[i])
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stbi__rewind(s);
|
stbi__rewind(s);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -360,9 +447,14 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req_comp == 2)
|
if (req_comp == 2)
|
||||||
|
{
|
||||||
output[1] = 1;
|
output[1] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (req_comp == 4)
|
if (req_comp == 4)
|
||||||
|
{
|
||||||
output[3] = 1;
|
output[3] = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -371,13 +463,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
case 4:
|
case 4:
|
||||||
case 3:
|
case 3:
|
||||||
if (req_comp == 4)
|
if (req_comp == 4)
|
||||||
|
{
|
||||||
output[3] = 1;
|
output[3] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
output[0] = output[1] = output[2] = 0;
|
output[0] = output[1] = output[2] = 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
case 1:
|
case 1:
|
||||||
if (req_comp == 2)
|
if (req_comp == 2)
|
||||||
|
{
|
||||||
output[1] = 1;
|
output[1] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
output[0] = 0;
|
output[0] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
public const int STBI__F_avg_first = 5;
|
public const int STBI__F_avg_first = 5;
|
||||||
|
|
||||||
public static byte[] first_row_filter =
|
public static byte[] first_row_filter =
|
||||||
{ STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_sub };
|
[STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_sub];
|
||||||
|
|
||||||
public static byte[] stbi__check_png_header_png_sig = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
public static byte[] stbi__check_png_header_png_sig = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||||
public static byte[] stbi__depth_scale_table = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
|
public static byte[] stbi__depth_scale_table = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
|
||||||
@@ -48,7 +48,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var p = new stbi__png();
|
var p = new stbi__png();
|
||||||
p.s = s;
|
p.s = s;
|
||||||
if (stbi__png_info_raw(p, null, null, null) == 0)
|
if (stbi__png_info_raw(p, null, null, null) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (p.depth != 16)
|
if (p.depth != 16)
|
||||||
{
|
{
|
||||||
stbi__rewind(p.s);
|
stbi__rewind(p.s);
|
||||||
@@ -70,8 +72,12 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var i = 0;
|
var i = 0;
|
||||||
for (i = 0; i < 8; ++i)
|
for (i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
if (stbi__get8(s) != stbi__check_png_header_png_sig[i])
|
if (stbi__get8(s) != stbi__check_png_header_png_sig[i])
|
||||||
|
{
|
||||||
return stbi__err("bad png sig");
|
return stbi__err("bad png sig");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -90,12 +96,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var i = 0;
|
var i = 0;
|
||||||
if (img_n == 1)
|
if (img_n == 1)
|
||||||
|
{
|
||||||
for (i = (int)(x - 1); i >= 0; --i)
|
for (i = (int)(x - 1); i >= 0; --i)
|
||||||
{
|
{
|
||||||
dest[i * 2 + 1] = 255;
|
dest[i * 2 + 1] = 255;
|
||||||
dest[i * 2 + 0] = src[i];
|
dest[i * 2 + 0] = src[i];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = (int)(x - 1); i >= 0; --i)
|
for (i = (int)(x - 1); i >= 0; --i)
|
||||||
{
|
{
|
||||||
dest[i * 4 + 3] = 255;
|
dest[i * 4 + 3] = 255;
|
||||||
@@ -103,6 +112,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
dest[i * 4 + 1] = src[i * 3 + 1];
|
dest[i * 4 + 1] = src[i * 3 + 1];
|
||||||
dest[i * 4 + 0] = src[i * 3 + 0];
|
dest[i * 4 + 0] = src[i * 3 + 0];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -123,20 +133,36 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var output_bytes = out_n * bytes;
|
var output_bytes = out_n * bytes;
|
||||||
var filter_bytes = img_n * bytes;
|
var filter_bytes = img_n * bytes;
|
||||||
var width = (int)x;
|
var width = (int)x;
|
||||||
|
|
||||||
a._out_ = (byte*)stbi__malloc_mad3((int)x, (int)y, output_bytes, 0);
|
a._out_ = (byte*)stbi__malloc_mad3((int)x, (int)y, output_bytes, 0);
|
||||||
if (a._out_ == null)
|
if (a._out_ == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__mad3sizes_valid(img_n, (int)x, depth, 7) == 0)
|
if (stbi__mad3sizes_valid(img_n, (int)x, depth, 7) == 0)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
|
|
||||||
img_width_bytes = (uint)((img_n * x * depth + 7) >> 3);
|
img_width_bytes = (uint)((img_n * x * depth + 7) >> 3);
|
||||||
if (stbi__mad2sizes_valid((int)img_width_bytes, (int)y, (int)img_width_bytes) == 0)
|
if (stbi__mad2sizes_valid((int)img_width_bytes, (int)y, (int)img_width_bytes) == 0)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
|
|
||||||
img_len = (img_width_bytes + 1) * y;
|
img_len = (img_width_bytes + 1) * y;
|
||||||
if (raw_len < img_len)
|
if (raw_len < img_len)
|
||||||
|
{
|
||||||
return stbi__err("not enough pixels");
|
return stbi__err("not enough pixels");
|
||||||
|
}
|
||||||
|
|
||||||
filter_buf = (byte*)stbi__malloc_mad2((int)img_width_bytes, 2, 0);
|
filter_buf = (byte*)stbi__malloc_mad2((int)img_width_bytes, 2, 0);
|
||||||
if (filter_buf == null)
|
if (filter_buf == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
if (depth < 8)
|
if (depth < 8)
|
||||||
{
|
{
|
||||||
filter_bytes = 1;
|
filter_bytes = 1;
|
||||||
@@ -157,7 +183,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
|
{
|
||||||
filter = first_row_filter[filter];
|
filter = first_row_filter[filter];
|
||||||
|
}
|
||||||
|
|
||||||
switch (filter)
|
switch (filter)
|
||||||
{
|
{
|
||||||
case STBI__F_none:
|
case STBI__F_none:
|
||||||
@@ -166,35 +195,49 @@ namespace Misaki.HighPerformance.Image
|
|||||||
case STBI__F_sub:
|
case STBI__F_sub:
|
||||||
CRuntime.memcpy(cur, raw, (ulong)filter_bytes);
|
CRuntime.memcpy(cur, raw, (ulong)filter_bytes);
|
||||||
for (k = filter_bytes; k < nk; ++k)
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + cur[k - filter_bytes]) & 255);
|
cur[k] = (byte)((raw[k] + cur[k - filter_bytes]) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STBI__F_up:
|
case STBI__F_up:
|
||||||
for (k = 0; k < nk; ++k)
|
for (k = 0; k < nk; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + prior[k]) & 255);
|
cur[k] = (byte)((raw[k] + prior[k]) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STBI__F_avg:
|
case STBI__F_avg:
|
||||||
for (k = 0; k < filter_bytes; ++k)
|
for (k = 0; k < filter_bytes; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + (prior[k] >> 1)) & 255);
|
cur[k] = (byte)((raw[k] + (prior[k] >> 1)) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
for (k = filter_bytes; k < nk; ++k)
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)) & 255);
|
cur[k] = (byte)((raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STBI__F_paeth:
|
case STBI__F_paeth:
|
||||||
for (k = 0; k < filter_bytes; ++k)
|
for (k = 0; k < filter_bytes; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + prior[k]) & 255);
|
cur[k] = (byte)((raw[k] + prior[k]) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
for (k = filter_bytes; k < nk; ++k)
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k],
|
cur[k] = (byte)((raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k],
|
||||||
prior[k - filter_bytes])) & 255);
|
prior[k - filter_bytes])) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STBI__F_avg_first:
|
case STBI__F_avg_first:
|
||||||
CRuntime.memcpy(cur, raw, (ulong)filter_bytes);
|
CRuntime.memcpy(cur, raw, (ulong)filter_bytes);
|
||||||
for (k = filter_bytes; k < nk; ++k)
|
for (k = filter_bytes; k < nk; ++k)
|
||||||
|
{
|
||||||
cur[k] = (byte)((raw[k] + (cur[k - filter_bytes] >> 1)) & 255);
|
cur[k] = (byte)((raw[k] + (cur[k - filter_bytes] >> 1)) & 255);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -208,39 +251,60 @@ namespace Misaki.HighPerformance.Image
|
|||||||
byte inb = 0;
|
byte inb = 0;
|
||||||
var nsmp = (uint)(x * img_n);
|
var nsmp = (uint)(x * img_n);
|
||||||
if (depth == 4)
|
if (depth == 4)
|
||||||
|
{
|
||||||
for (i = 0; i < nsmp; ++i)
|
for (i = 0; i < nsmp; ++i)
|
||||||
{
|
{
|
||||||
if ((i & 1) == 0)
|
if ((i & 1) == 0)
|
||||||
|
{
|
||||||
inb = *_in_++;
|
inb = *_in_++;
|
||||||
|
}
|
||||||
|
|
||||||
*_out_++ = (byte)(scale * (inb >> 4));
|
*_out_++ = (byte)(scale * (inb >> 4));
|
||||||
inb <<= 4;
|
inb <<= 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (depth == 2)
|
else if (depth == 2)
|
||||||
|
{
|
||||||
for (i = 0; i < nsmp; ++i)
|
for (i = 0; i < nsmp; ++i)
|
||||||
{
|
{
|
||||||
if ((i & 3) == 0)
|
if ((i & 3) == 0)
|
||||||
|
{
|
||||||
inb = *_in_++;
|
inb = *_in_++;
|
||||||
|
}
|
||||||
|
|
||||||
*_out_++ = (byte)(scale * (inb >> 6));
|
*_out_++ = (byte)(scale * (inb >> 6));
|
||||||
inb <<= 2;
|
inb <<= 2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < nsmp; ++i)
|
for (i = 0; i < nsmp; ++i)
|
||||||
{
|
{
|
||||||
if ((i & 7) == 0)
|
if ((i & 7) == 0)
|
||||||
|
{
|
||||||
inb = *_in_++;
|
inb = *_in_++;
|
||||||
|
}
|
||||||
|
|
||||||
*_out_++ = (byte)(scale * (inb >> 7));
|
*_out_++ = (byte)(scale * (inb >> 7));
|
||||||
inb <<= 1;
|
inb <<= 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (img_n != out_n)
|
if (img_n != out_n)
|
||||||
|
{
|
||||||
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
|
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (depth == 8)
|
else if (depth == 8)
|
||||||
{
|
{
|
||||||
if (img_n == out_n)
|
if (img_n == out_n)
|
||||||
|
{
|
||||||
CRuntime.memcpy(dest, cur, (ulong)(x * img_n));
|
CRuntime.memcpy(dest, cur, (ulong)(x * img_n));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
|
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (depth == 16)
|
else if (depth == 16)
|
||||||
{
|
{
|
||||||
@@ -249,17 +313,22 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if (img_n == out_n)
|
if (img_n == out_n)
|
||||||
{
|
{
|
||||||
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
|
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
|
||||||
|
{
|
||||||
*dest16 = (ushort)((cur[0] << 8) | cur[1]);
|
*dest16 = (ushort)((cur[0] << 8) | cur[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (img_n == 1)
|
if (img_n == 1)
|
||||||
|
{
|
||||||
for (i = 0; i < x; ++i, dest16 += 2, cur += 2)
|
for (i = 0; i < x; ++i, dest16 += 2, cur += 2)
|
||||||
{
|
{
|
||||||
dest16[0] = (ushort)((cur[0] << 8) | cur[1]);
|
dest16[0] = (ushort)((cur[0] << 8) | cur[1]);
|
||||||
dest16[1] = 0xffff;
|
dest16[1] = 0xffff;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < x; ++i, dest16 += 4, cur += 6)
|
for (i = 0; i < x; ++i, dest16 += 4, cur += 6)
|
||||||
{
|
{
|
||||||
dest16[0] = (ushort)((cur[0] << 8) | cur[1]);
|
dest16[0] = (ushort)((cur[0] << 8) | cur[1]);
|
||||||
@@ -267,13 +336,17 @@ namespace Misaki.HighPerformance.Image
|
|||||||
dest16[2] = (ushort)((cur[4] << 8) | cur[5]);
|
dest16[2] = (ushort)((cur[4] << 8) | cur[5]);
|
||||||
dest16[3] = 0xffff;
|
dest16[3] = 0xffff;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CRuntime.free(filter_buf);
|
CRuntime.free(filter_buf);
|
||||||
if (all_ok == 0)
|
if (all_ok == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,17 +358,23 @@ namespace Misaki.HighPerformance.Image
|
|||||||
byte* final;
|
byte* final;
|
||||||
var p = 0;
|
var p = 0;
|
||||||
if (interlaced == 0)
|
if (interlaced == 0)
|
||||||
return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a.s.img_x, a.s.img_y, depth,
|
{
|
||||||
color);
|
return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a.s.img_x, a.s.img_y, depth, color);
|
||||||
|
}
|
||||||
final = (byte*)stbi__malloc_mad3((int)a.s.img_x, (int)a.s.img_y, out_bytes, 0);
|
final = (byte*)stbi__malloc_mad3((int)a.s.img_x, (int)a.s.img_y, out_bytes, 0);
|
||||||
|
|
||||||
if (final == null)
|
if (final == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
|
var xorig = stackalloc int[] { 0, 4, 0, 2, 0, 1, 0 };
|
||||||
|
var yorig = stackalloc int[] { 0, 0, 4, 0, 2, 0, 1 };
|
||||||
|
var xspc = stackalloc int[] { 8, 8, 4, 4, 2, 2, 1 };
|
||||||
|
var yspc = stackalloc int[] { 8, 8, 8, 4, 4, 2, 2 };
|
||||||
|
|
||||||
for (p = 0; p < 7; ++p)
|
for (p = 0; p < 7; ++p)
|
||||||
{
|
{
|
||||||
var xorig = stackalloc int[] { 0, 4, 0, 2, 0, 1, 0 };
|
|
||||||
var yorig = stackalloc int[] { 0, 0, 4, 0, 2, 0, 1 };
|
|
||||||
var xspc = stackalloc int[] { 8, 8, 4, 4, 2, 2, 1 };
|
|
||||||
var yspc = stackalloc int[] { 8, 8, 8, 4, 4, 2, 2 };
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var j = 0;
|
var j = 0;
|
||||||
var x = 0;
|
var x = 0;
|
||||||
@@ -313,6 +392,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < y; ++j)
|
for (j = 0; j < y; ++j)
|
||||||
|
{
|
||||||
for (i = 0; i < x; ++i)
|
for (i = 0; i < x; ++i)
|
||||||
{
|
{
|
||||||
var out_y = j * yspc[p] + yorig[p];
|
var out_y = j * yspc[p] + yorig[p];
|
||||||
@@ -320,6 +400,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
CRuntime.memcpy(final + out_y * a.s.img_x * out_bytes + out_x * out_bytes,
|
CRuntime.memcpy(final + out_y * a.s.img_x * out_bytes + out_x * out_bytes,
|
||||||
a._out_ + (j * x + i) * out_bytes, (ulong)out_bytes);
|
a._out_ + (j * x + i) * out_bytes, (ulong)out_bytes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.free(a._out_);
|
CRuntime.free(a._out_);
|
||||||
image_data += img_len;
|
image_data += img_len;
|
||||||
@@ -338,18 +419,25 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var pixel_count = s.img_x * s.img_y;
|
var pixel_count = s.img_x * s.img_y;
|
||||||
var p = z._out_;
|
var p = z._out_;
|
||||||
if (out_n == 2)
|
if (out_n == 2)
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
p[1] = (byte)(p[0] == tc[0] ? 0 : 255);
|
p[1] = (byte)(p[0] == tc[0] ? 0 : 255);
|
||||||
p += 2;
|
p += 2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
|
if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
|
||||||
|
{
|
||||||
p[3] = 0;
|
p[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -361,18 +449,25 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var pixel_count = s.img_x * s.img_y;
|
var pixel_count = s.img_x * s.img_y;
|
||||||
var p = (ushort*)z._out_;
|
var p = (ushort*)z._out_;
|
||||||
if (out_n == 2)
|
if (out_n == 2)
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
p[1] = (ushort)(p[0] == tc[0] ? 0 : 65535);
|
p[1] = (ushort)(p[0] == tc[0] ? 0 : 65535);
|
||||||
p += 2;
|
p += 2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
|
if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
|
||||||
|
{
|
||||||
p[3] = 0;
|
p[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -386,9 +481,12 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var orig = a._out_;
|
var orig = a._out_;
|
||||||
p = (byte*)stbi__malloc_mad2((int)pixel_count, pal_img_n, 0);
|
p = (byte*)stbi__malloc_mad2((int)pixel_count, pal_img_n, 0);
|
||||||
if (p == null)
|
if (p == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
temp_out = p;
|
temp_out = p;
|
||||||
if (pal_img_n == 3)
|
if (pal_img_n == 3)
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
var n = orig[i] * 4;
|
var n = orig[i] * 4;
|
||||||
@@ -397,7 +495,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
p[2] = palette[n + 2];
|
p[2] = palette[n + 2];
|
||||||
p += 3;
|
p += 3;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
var n = orig[i] * 4;
|
var n = orig[i] * 4;
|
||||||
@@ -407,6 +507,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
p[3] = palette[n + 3];
|
p[3] = palette[n + 3];
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.free(a._out_);
|
CRuntime.free(a._out_);
|
||||||
a._out_ = temp_out;
|
a._out_ = temp_out;
|
||||||
@@ -423,9 +524,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
var t = p[0];
|
(p[2], p[0]) = (p[0], p[2]);
|
||||||
p[0] = p[2];
|
|
||||||
p[2] = t;
|
|
||||||
p += 3;
|
p += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -434,6 +533,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if ((stbi__unpremultiply_on_load_set != 0
|
if ((stbi__unpremultiply_on_load_set != 0
|
||||||
? stbi__unpremultiply_on_load_local
|
? stbi__unpremultiply_on_load_local
|
||||||
: stbi__unpremultiply_on_load_global) != 0)
|
: stbi__unpremultiply_on_load_global) != 0)
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
var a = p[3];
|
var a = p[3];
|
||||||
@@ -453,14 +553,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
|
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < pixel_count; ++i)
|
for (i = 0; i < pixel_count; ++i)
|
||||||
{
|
{
|
||||||
var t = p[0];
|
(p[2], p[0]) = (p[0], p[2]);
|
||||||
p[0] = p[2];
|
|
||||||
p[2] = t;
|
|
||||||
p += 4;
|
p += 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,10 +585,17 @@ namespace Misaki.HighPerformance.Image
|
|||||||
z.expanded = null;
|
z.expanded = null;
|
||||||
z.idata = null;
|
z.idata = null;
|
||||||
z._out_ = null;
|
z._out_ = null;
|
||||||
|
|
||||||
if (stbi__check_png_header(s) == 0)
|
if (stbi__check_png_header(s) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (scan == STBI__SCAN_type)
|
if (scan == STBI__SCAN_type)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
var c = stbi__get_chunk_header(s);
|
var c = stbi__get_chunk_header(s);
|
||||||
@@ -502,50 +610,92 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var comp = 0;
|
var comp = 0;
|
||||||
var filter = 0;
|
var filter = 0;
|
||||||
if (first == 0)
|
if (first == 0)
|
||||||
|
{
|
||||||
return stbi__err("multiple IHDR");
|
return stbi__err("multiple IHDR");
|
||||||
|
}
|
||||||
|
|
||||||
first = 0;
|
first = 0;
|
||||||
if (c.length != 13)
|
if (c.length != 13)
|
||||||
|
{
|
||||||
return stbi__err("bad IHDR len");
|
return stbi__err("bad IHDR len");
|
||||||
|
}
|
||||||
|
|
||||||
s.img_x = stbi__get32be(s);
|
s.img_x = stbi__get32be(s);
|
||||||
s.img_y = stbi__get32be(s);
|
s.img_y = stbi__get32be(s);
|
||||||
if (s.img_y > 1 << 24)
|
if (s.img_y > 1 << 24)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
|
|
||||||
if (s.img_x > 1 << 24)
|
if (s.img_x > 1 << 24)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
|
|
||||||
z.depth = stbi__get8(s);
|
z.depth = stbi__get8(s);
|
||||||
if (z.depth != 1 && z.depth != 2 && z.depth != 4 && z.depth != 8 && z.depth != 16)
|
if (z.depth != 1 && z.depth != 2 && z.depth != 4 && z.depth != 8 && z.depth != 16)
|
||||||
|
{
|
||||||
return stbi__err("1/2/4/8/16-bit only");
|
return stbi__err("1/2/4/8/16-bit only");
|
||||||
|
}
|
||||||
|
|
||||||
color = stbi__get8(s);
|
color = stbi__get8(s);
|
||||||
if (color > 6)
|
if (color > 6)
|
||||||
|
{
|
||||||
return stbi__err("bad ctype");
|
return stbi__err("bad ctype");
|
||||||
|
}
|
||||||
|
|
||||||
if (color == 3 && z.depth == 16)
|
if (color == 3 && z.depth == 16)
|
||||||
|
{
|
||||||
return stbi__err("bad ctype");
|
return stbi__err("bad ctype");
|
||||||
|
}
|
||||||
|
|
||||||
if (color == 3)
|
if (color == 3)
|
||||||
|
{
|
||||||
pal_img_n = 3;
|
pal_img_n = 3;
|
||||||
|
}
|
||||||
else if ((color & 1) != 0)
|
else if ((color & 1) != 0)
|
||||||
|
{
|
||||||
return stbi__err("bad ctype");
|
return stbi__err("bad ctype");
|
||||||
|
}
|
||||||
|
|
||||||
comp = stbi__get8(s);
|
comp = stbi__get8(s);
|
||||||
if (comp != 0)
|
if (comp != 0)
|
||||||
|
{
|
||||||
return stbi__err("bad comp method");
|
return stbi__err("bad comp method");
|
||||||
|
}
|
||||||
|
|
||||||
filter = stbi__get8(s);
|
filter = stbi__get8(s);
|
||||||
if (filter != 0)
|
if (filter != 0)
|
||||||
|
{
|
||||||
return stbi__err("bad filter method");
|
return stbi__err("bad filter method");
|
||||||
|
}
|
||||||
|
|
||||||
interlace = stbi__get8(s);
|
interlace = stbi__get8(s);
|
||||||
if (interlace > 1)
|
if (interlace > 1)
|
||||||
|
{
|
||||||
return stbi__err("bad interlace method");
|
return stbi__err("bad interlace method");
|
||||||
|
}
|
||||||
|
|
||||||
if (s.img_x == 0 || s.img_y == 0)
|
if (s.img_x == 0 || s.img_y == 0)
|
||||||
|
{
|
||||||
return stbi__err("0-pixel image");
|
return stbi__err("0-pixel image");
|
||||||
|
}
|
||||||
|
|
||||||
if (pal_img_n == 0)
|
if (pal_img_n == 0)
|
||||||
{
|
{
|
||||||
s.img_n = ((color & 2) != 0 ? 3 : 1) + ((color & 4) != 0 ? 1 : 0);
|
s.img_n = ((color & 2) != 0 ? 3 : 1) + ((color & 4) != 0 ? 1 : 0);
|
||||||
if ((1 << 30) / s.img_x / s.img_n < s.img_y)
|
if ((1 << 30) / s.img_x / s.img_n < s.img_y)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s.img_n = 1;
|
s.img_n = 1;
|
||||||
if ((1 << 30) / s.img_x / 4 < s.img_y)
|
if ((1 << 30) / s.img_x / 4 < s.img_y)
|
||||||
|
{
|
||||||
return stbi__err("too large");
|
return stbi__err("too large");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -554,12 +704,21 @@ namespace Misaki.HighPerformance.Image
|
|||||||
case ((uint)80 << 24) + ((uint)76 << 16) + ((uint)84 << 8) + 69:
|
case ((uint)80 << 24) + ((uint)76 << 16) + ((uint)84 << 8) + 69:
|
||||||
{
|
{
|
||||||
if (first != 0)
|
if (first != 0)
|
||||||
|
{
|
||||||
return stbi__err("first not IHDR");
|
return stbi__err("first not IHDR");
|
||||||
|
}
|
||||||
|
|
||||||
if (c.length > 256 * 3)
|
if (c.length > 256 * 3)
|
||||||
|
{
|
||||||
return stbi__err("invalid PLTE");
|
return stbi__err("invalid PLTE");
|
||||||
|
}
|
||||||
|
|
||||||
pal_len = c.length / 3;
|
pal_len = c.length / 3;
|
||||||
if (pal_len * 3 != c.length)
|
if (pal_len * 3 != c.length)
|
||||||
|
{
|
||||||
return stbi__err("invalid PLTE");
|
return stbi__err("invalid PLTE");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < pal_len; ++i)
|
for (i = 0; i < pal_len; ++i)
|
||||||
{
|
{
|
||||||
palette[i * 4 + 0] = stbi__get8(s);
|
palette[i * 4 + 0] = stbi__get8(s);
|
||||||
@@ -574,9 +733,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
case ((uint)116 << 24) + ((uint)82 << 16) + ((uint)78 << 8) + 83:
|
case ((uint)116 << 24) + ((uint)82 << 16) + ((uint)78 << 8) + 83:
|
||||||
{
|
{
|
||||||
if (first != 0)
|
if (first != 0)
|
||||||
|
{
|
||||||
return stbi__err("first not IHDR");
|
return stbi__err("first not IHDR");
|
||||||
|
}
|
||||||
|
|
||||||
if (z.idata != null)
|
if (z.idata != null)
|
||||||
|
{
|
||||||
return stbi__err("tRNS after IDAT");
|
return stbi__err("tRNS after IDAT");
|
||||||
|
}
|
||||||
|
|
||||||
if (pal_img_n != 0)
|
if (pal_img_n != 0)
|
||||||
{
|
{
|
||||||
if (scan == STBI__SCAN_header)
|
if (scan == STBI__SCAN_header)
|
||||||
@@ -586,19 +751,33 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pal_len == 0)
|
if (pal_len == 0)
|
||||||
|
{
|
||||||
return stbi__err("tRNS before PLTE");
|
return stbi__err("tRNS before PLTE");
|
||||||
|
}
|
||||||
|
|
||||||
if (c.length > pal_len)
|
if (c.length > pal_len)
|
||||||
|
{
|
||||||
return stbi__err("bad tRNS len");
|
return stbi__err("bad tRNS len");
|
||||||
|
}
|
||||||
|
|
||||||
pal_img_n = 4;
|
pal_img_n = 4;
|
||||||
for (i = 0; i < c.length; ++i)
|
for (i = 0; i < c.length; ++i)
|
||||||
|
{
|
||||||
palette[i * 4 + 3] = stbi__get8(s);
|
palette[i * 4 + 3] = stbi__get8(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((s.img_n & 1) == 0)
|
if ((s.img_n & 1) == 0)
|
||||||
|
{
|
||||||
return stbi__err("tRNS with alpha");
|
return stbi__err("tRNS with alpha");
|
||||||
|
}
|
||||||
|
|
||||||
if (c.length != (uint)s.img_n * 2)
|
if (c.length != (uint)s.img_n * 2)
|
||||||
|
{
|
||||||
return stbi__err("bad tRNS len");
|
return stbi__err("bad tRNS len");
|
||||||
|
}
|
||||||
|
|
||||||
has_trans = 1;
|
has_trans = 1;
|
||||||
if (scan == STBI__SCAN_header)
|
if (scan == STBI__SCAN_header)
|
||||||
{
|
{
|
||||||
@@ -607,11 +786,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (z.depth == 16)
|
if (z.depth == 16)
|
||||||
|
{
|
||||||
for (k = 0; k < s.img_n && k < 3; ++k)
|
for (k = 0; k < s.img_n && k < 3; ++k)
|
||||||
|
{
|
||||||
tc16[k] = (ushort)stbi__get16be(s);
|
tc16[k] = (ushort)stbi__get16be(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (k = 0; k < s.img_n && k < 3; ++k)
|
for (k = 0; k < s.img_n && k < 3; ++k)
|
||||||
|
{
|
||||||
tc[k] = (byte)((byte)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z.depth]);
|
tc[k] = (byte)((byte)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z.depth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -620,37 +807,63 @@ namespace Misaki.HighPerformance.Image
|
|||||||
case ((uint)73 << 24) + ((uint)68 << 16) + ((uint)65 << 8) + 84:
|
case ((uint)73 << 24) + ((uint)68 << 16) + ((uint)65 << 8) + 84:
|
||||||
{
|
{
|
||||||
if (first != 0)
|
if (first != 0)
|
||||||
|
{
|
||||||
return stbi__err("first not IHDR");
|
return stbi__err("first not IHDR");
|
||||||
|
}
|
||||||
|
|
||||||
if (pal_img_n != 0 && pal_len == 0)
|
if (pal_img_n != 0 && pal_len == 0)
|
||||||
|
{
|
||||||
return stbi__err("no PLTE");
|
return stbi__err("no PLTE");
|
||||||
|
}
|
||||||
|
|
||||||
if (scan == STBI__SCAN_header)
|
if (scan == STBI__SCAN_header)
|
||||||
{
|
{
|
||||||
if (pal_img_n != 0)
|
if (pal_img_n != 0)
|
||||||
|
{
|
||||||
s.img_n = pal_img_n;
|
s.img_n = pal_img_n;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.length > 1u << 30)
|
if (c.length > 1u << 30)
|
||||||
|
{
|
||||||
return stbi__err("IDAT size limit");
|
return stbi__err("IDAT size limit");
|
||||||
|
}
|
||||||
|
|
||||||
if ((int)(ioff + c.length) < (int)ioff)
|
if ((int)(ioff + c.length) < (int)ioff)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (ioff + c.length > idata_limit)
|
if (ioff + c.length > idata_limit)
|
||||||
{
|
{
|
||||||
var idata_limit_old = idata_limit;
|
var idata_limit_old = idata_limit;
|
||||||
byte* p;
|
byte* p;
|
||||||
if (idata_limit == 0)
|
if (idata_limit == 0)
|
||||||
|
{
|
||||||
idata_limit = c.length > 4096 ? c.length : 4096;
|
idata_limit = c.length > 4096 ? c.length : 4096;
|
||||||
|
}
|
||||||
|
|
||||||
while (ioff + c.length > idata_limit)
|
while (ioff + c.length > idata_limit)
|
||||||
|
{
|
||||||
idata_limit *= 2;
|
idata_limit *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
p = (byte*)CRuntime.realloc(z.idata, (ulong)idata_limit);
|
p = (byte*)CRuntime.realloc(z.idata, (ulong)idata_limit);
|
||||||
if (p == null)
|
if (p == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
z.idata = p;
|
z.idata = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stbi__getn(s, z.idata + ioff, (int)c.length) == 0)
|
if (stbi__getn(s, z.idata + ioff, (int)c.length) == 0)
|
||||||
|
{
|
||||||
return stbi__err("outofdata");
|
return stbi__err("outofdata");
|
||||||
|
}
|
||||||
|
|
||||||
ioff += c.length;
|
ioff += c.length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -660,36 +873,60 @@ namespace Misaki.HighPerformance.Image
|
|||||||
uint raw_len = 0;
|
uint raw_len = 0;
|
||||||
uint bpl = 0;
|
uint bpl = 0;
|
||||||
if (first != 0)
|
if (first != 0)
|
||||||
|
{
|
||||||
return stbi__err("first not IHDR");
|
return stbi__err("first not IHDR");
|
||||||
|
}
|
||||||
|
|
||||||
if (scan != STBI__SCAN_load)
|
if (scan != STBI__SCAN_load)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (z.idata == null)
|
if (z.idata == null)
|
||||||
|
{
|
||||||
return stbi__err("no IDAT");
|
return stbi__err("no IDAT");
|
||||||
|
}
|
||||||
|
|
||||||
bpl = (uint)((s.img_x * z.depth + 7) / 8);
|
bpl = (uint)((s.img_x * z.depth + 7) / 8);
|
||||||
raw_len = (uint)(bpl * s.img_y * s.img_n + s.img_y);
|
raw_len = (uint)(bpl * s.img_y * s.img_n + s.img_y);
|
||||||
z.expanded = (byte*)stbi_zlib_decode_malloc_guesssize_headerflag((sbyte*)z.idata, (int)ioff,
|
z.expanded = (byte*)stbi_zlib_decode_malloc_guesssize_headerflag((sbyte*)z.idata, (int)ioff,
|
||||||
(int)raw_len, (int*)&raw_len, is_iphone == 0 ? 1 : 0);
|
(int)raw_len, (int*)&raw_len, is_iphone == 0 ? 1 : 0);
|
||||||
if (z.expanded == null)
|
if (z.expanded == null)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.free(z.idata);
|
CRuntime.free(z.idata);
|
||||||
z.idata = null;
|
z.idata = null;
|
||||||
if ((req_comp == s.img_n + 1 && req_comp != 3 && pal_img_n == 0) || has_trans != 0)
|
if ((req_comp == s.img_n + 1 && req_comp != 3 && pal_img_n == 0) || has_trans != 0)
|
||||||
|
{
|
||||||
s.img_out_n = s.img_n + 1;
|
s.img_out_n = s.img_n + 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
s.img_out_n = s.img_n;
|
s.img_out_n = s.img_n;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__create_png_image(z, z.expanded, raw_len, s.img_out_n, z.depth, color, interlace) == 0)
|
if (stbi__create_png_image(z, z.expanded, raw_len, s.img_out_n, z.depth, color, interlace) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (has_trans != 0)
|
if (has_trans != 0)
|
||||||
{
|
{
|
||||||
if (z.depth == 16)
|
if (z.depth == 16)
|
||||||
{
|
{
|
||||||
if (stbi__compute_transparency16(z, tc16, s.img_out_n) == 0)
|
if (stbi__compute_transparency16(z, tc16, s.img_out_n) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (stbi__compute_transparency(z, tc, s.img_out_n) == 0)
|
if (stbi__compute_transparency(z, tc, s.img_out_n) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -697,15 +934,23 @@ namespace Misaki.HighPerformance.Image
|
|||||||
(stbi__de_iphone_flag_set != 0
|
(stbi__de_iphone_flag_set != 0
|
||||||
? stbi__de_iphone_flag_local
|
? stbi__de_iphone_flag_local
|
||||||
: stbi__de_iphone_flag_global) != 0 && s.img_out_n > 2)
|
: stbi__de_iphone_flag_global) != 0 && s.img_out_n > 2)
|
||||||
|
{
|
||||||
stbi__de_iphone(z);
|
stbi__de_iphone(z);
|
||||||
|
}
|
||||||
|
|
||||||
if (pal_img_n != 0)
|
if (pal_img_n != 0)
|
||||||
{
|
{
|
||||||
s.img_n = pal_img_n;
|
s.img_n = pal_img_n;
|
||||||
s.img_out_n = pal_img_n;
|
s.img_out_n = pal_img_n;
|
||||||
if (req_comp >= 3)
|
if (req_comp >= 3)
|
||||||
|
{
|
||||||
s.img_out_n = req_comp;
|
s.img_out_n = req_comp;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__expand_png_palette(z, palette, (int)pal_len, s.img_out_n) == 0)
|
if (stbi__expand_png_palette(z, palette, (int)pal_len, s.img_out_n) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (has_trans != 0)
|
else if (has_trans != 0)
|
||||||
{
|
{
|
||||||
@@ -720,7 +965,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (first != 0)
|
if (first != 0)
|
||||||
|
{
|
||||||
return stbi__err("first not IHDR");
|
return stbi__err("first not IHDR");
|
||||||
|
}
|
||||||
|
|
||||||
if ((c.type & (1 << 29)) == 0)
|
if ((c.type & (1 << 29)) == 0)
|
||||||
{
|
{
|
||||||
stbi__parse_png_file_invalid_chunk[0] = (char)((c.type >> 24) & 255);
|
stbi__parse_png_file_invalid_chunk[0] = (char)((c.type >> 24) & 255);
|
||||||
@@ -742,32 +990,51 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
void* result = null;
|
void* result = null;
|
||||||
if (req_comp < 0 || req_comp > 4)
|
if (req_comp < 0 || req_comp > 4)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad req_comp") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad req_comp") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp) != 0)
|
if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp) != 0)
|
||||||
{
|
{
|
||||||
if (p.depth <= 8)
|
if (p.depth <= 8)
|
||||||
|
{
|
||||||
ri->bits_per_channel = 8;
|
ri->bits_per_channel = 8;
|
||||||
|
}
|
||||||
else if (p.depth == 16)
|
else if (p.depth == 16)
|
||||||
|
{
|
||||||
ri->bits_per_channel = 16;
|
ri->bits_per_channel = 16;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad bits_per_channel") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad bits_per_channel") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
result = p._out_;
|
result = p._out_;
|
||||||
p._out_ = null;
|
p._out_ = null;
|
||||||
if (req_comp != 0 && req_comp != p.s.img_out_n)
|
if (req_comp != 0 && req_comp != p.s.img_out_n)
|
||||||
{
|
{
|
||||||
if (ri->bits_per_channel == 8)
|
if (ri->bits_per_channel == 8)
|
||||||
|
{
|
||||||
result = stbi__convert_format((byte*)result, p.s.img_out_n, req_comp, p.s.img_x, p.s.img_y);
|
result = stbi__convert_format((byte*)result, p.s.img_out_n, req_comp, p.s.img_x, p.s.img_y);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
result = stbi__convert_format16((ushort*)result, p.s.img_out_n, req_comp, p.s.img_x, p.s.img_y);
|
result = stbi__convert_format16((ushort*)result, p.s.img_out_n, req_comp, p.s.img_x, p.s.img_y);
|
||||||
|
}
|
||||||
|
|
||||||
p.s.img_out_n = req_comp;
|
p.s.img_out_n = req_comp;
|
||||||
if (result == null)
|
if (result == null)
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*x = (int)p.s.img_x;
|
*x = (int)p.s.img_x;
|
||||||
*y = (int)p.s.img_y;
|
*y = (int)p.s.img_y;
|
||||||
if (n != null)
|
if (n != null)
|
||||||
|
{
|
||||||
*n = p.s.img_n;
|
*n = p.s.img_n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CRuntime.free(p._out_);
|
CRuntime.free(p._out_);
|
||||||
@@ -788,11 +1055,20 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x != null)
|
if (x != null)
|
||||||
|
{
|
||||||
*x = (int)p.s.img_x;
|
*x = (int)p.s.img_x;
|
||||||
|
}
|
||||||
|
|
||||||
if (y != null)
|
if (y != null)
|
||||||
|
{
|
||||||
*y = (int)p.s.img_y;
|
*y = (int)p.s.img_y;
|
||||||
|
}
|
||||||
|
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = p.s.img_n;
|
*comp = p.s.img_n;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,32 +28,59 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var h = 0;
|
var h = 0;
|
||||||
byte* _out_;
|
byte* _out_;
|
||||||
if (stbi__get32be(s) != 0x38425053)
|
if (stbi__get32be(s) != 0x38425053)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("not PSD") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("not PSD") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get16be(s) != 1)
|
if (stbi__get16be(s) != 1)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("wrong version") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("wrong version") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, 6);
|
stbi__skip(s, 6);
|
||||||
channelCount = stbi__get16be(s);
|
channelCount = stbi__get16be(s);
|
||||||
if (channelCount < 0 || channelCount > 16)
|
if (channelCount < 0 || channelCount > 16)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("wrong channel count") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("wrong channel count") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
h = (int)stbi__get32be(s);
|
h = (int)stbi__get32be(s);
|
||||||
w = (int)stbi__get32be(s);
|
w = (int)stbi__get32be(s);
|
||||||
if (h > 1 << 24)
|
if (h > 1 << 24)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (w > 1 << 24)
|
if (w > 1 << 24)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
bitdepth = stbi__get16be(s);
|
bitdepth = stbi__get16be(s);
|
||||||
if (bitdepth != 8 && bitdepth != 16)
|
if (bitdepth != 8 && bitdepth != 16)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("unsupported bit depth") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("unsupported bit depth") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get16be(s) != 3)
|
if (stbi__get16be(s) != 3)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("wrong color format") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("wrong color format") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, (int)stbi__get32be(s));
|
stbi__skip(s, (int)stbi__get32be(s));
|
||||||
stbi__skip(s, (int)stbi__get32be(s));
|
stbi__skip(s, (int)stbi__get32be(s));
|
||||||
stbi__skip(s, (int)stbi__get32be(s));
|
stbi__skip(s, (int)stbi__get32be(s));
|
||||||
compression = stbi__get16be(s);
|
compression = stbi__get16be(s);
|
||||||
if (compression > 1)
|
if (compression > 1)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad compression") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad compression") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__mad3sizes_valid(4, w, h, 0) == 0)
|
if (stbi__mad3sizes_valid(4, w, h, 0) == 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (compression == 0 && bitdepth == 16 && bpc == 16)
|
if (compression == 0 && bitdepth == 16 && bpc == 16)
|
||||||
{
|
{
|
||||||
_out_ = (byte*)stbi__malloc_mad3(8, w, h, 0);
|
_out_ = (byte*)stbi__malloc_mad3(8, w, h, 0);
|
||||||
@@ -65,7 +92,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_out_ == null)
|
if (_out_ == null)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
pixelCount = w * h;
|
pixelCount = w * h;
|
||||||
if (compression != 0)
|
if (compression != 0)
|
||||||
{
|
{
|
||||||
@@ -77,7 +107,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if (channel >= channelCount)
|
if (channel >= channelCount)
|
||||||
{
|
{
|
||||||
for (i = 0; i < pixelCount; i++, p += 4)
|
for (i = 0; i < pixelCount; i++, p += 4)
|
||||||
|
{
|
||||||
*p = (byte)(channel == 3 ? 255 : 0);
|
*p = (byte)(channel == 3 ? 255 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -92,6 +124,7 @@ namespace Misaki.HighPerformance.Image
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (channel = 0; channel < 4; channel++)
|
for (channel = 0; channel < 4; channel++)
|
||||||
|
{
|
||||||
if (channel >= channelCount)
|
if (channel >= channelCount)
|
||||||
{
|
{
|
||||||
if (bitdepth == 16 && bpc == 16)
|
if (bitdepth == 16 && bpc == 16)
|
||||||
@@ -99,14 +132,18 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var q = (ushort*)_out_ + channel;
|
var q = (ushort*)_out_ + channel;
|
||||||
var val = (ushort)(channel == 3 ? 65535 : 0);
|
var val = (ushort)(channel == 3 ? 65535 : 0);
|
||||||
for (i = 0; i < pixelCount; i++, q += 4)
|
for (i = 0; i < pixelCount; i++, q += 4)
|
||||||
|
{
|
||||||
*q = val;
|
*q = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var p = _out_ + channel;
|
var p = _out_ + channel;
|
||||||
var val = (byte)(channel == 3 ? 255 : 0);
|
var val = (byte)(channel == 3 ? 255 : 0);
|
||||||
for (i = 0; i < pixelCount; i++, p += 4)
|
for (i = 0; i < pixelCount; i++, p += 4)
|
||||||
|
{
|
||||||
*p = val;
|
*p = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -115,24 +152,36 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var q = (ushort*)_out_ + channel;
|
var q = (ushort*)_out_ + channel;
|
||||||
for (i = 0; i < pixelCount; i++, q += 4)
|
for (i = 0; i < pixelCount; i++, q += 4)
|
||||||
|
{
|
||||||
*q = (ushort)stbi__get16be(s);
|
*q = (ushort)stbi__get16be(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var p = _out_ + channel;
|
var p = _out_ + channel;
|
||||||
if (bitdepth == 16)
|
if (bitdepth == 16)
|
||||||
|
{
|
||||||
for (i = 0; i < pixelCount; i++, p += 4)
|
for (i = 0; i < pixelCount; i++, p += 4)
|
||||||
|
{
|
||||||
*p = (byte)(stbi__get16be(s) >> 8);
|
*p = (byte)(stbi__get16be(s) >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < pixelCount; i++, p += 4)
|
for (i = 0; i < pixelCount; i++, p += 4)
|
||||||
|
{
|
||||||
*p = stbi__get8(s);
|
*p = stbi__get8(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channelCount >= 4)
|
if (channelCount >= 4)
|
||||||
{
|
{
|
||||||
if (ri->bits_per_channel == 16)
|
if (ri->bits_per_channel == 16)
|
||||||
|
{
|
||||||
for (i = 0; i < w * h; ++i)
|
for (i = 0; i < w * h; ++i)
|
||||||
{
|
{
|
||||||
var pixel = (ushort*)_out_ + 4 * i;
|
var pixel = (ushort*)_out_ + 4 * i;
|
||||||
@@ -146,7 +195,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
pixel[2] = (ushort)(pixel[2] * ra + inv_a);
|
pixel[2] = (ushort)(pixel[2] * ra + inv_a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (i = 0; i < w * h; ++i)
|
for (i = 0; i < w * h; ++i)
|
||||||
{
|
{
|
||||||
var pixel = _out_ + 4 * i;
|
var pixel = _out_ + 4 * i;
|
||||||
@@ -160,20 +211,31 @@ namespace Misaki.HighPerformance.Image
|
|||||||
pixel[2] = (byte)(pixel[2] * ra + inv_a);
|
pixel[2] = (byte)(pixel[2] * ra + inv_a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req_comp != 0 && req_comp != 4)
|
if (req_comp != 0 && req_comp != 4)
|
||||||
{
|
{
|
||||||
if (ri->bits_per_channel == 16)
|
if (ri->bits_per_channel == 16)
|
||||||
|
{
|
||||||
_out_ = (byte*)stbi__convert_format16((ushort*)_out_, 4, req_comp, (uint)w, (uint)h);
|
_out_ = (byte*)stbi__convert_format16((ushort*)_out_, 4, req_comp, (uint)w, (uint)h);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)w, (uint)h);
|
_out_ = stbi__convert_format(_out_, 4, req_comp, (uint)w, (uint)h);
|
||||||
|
}
|
||||||
|
|
||||||
if (_out_ == null)
|
if (_out_ == null)
|
||||||
|
{
|
||||||
return _out_;
|
return _out_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = 4;
|
*comp = 4;
|
||||||
|
}
|
||||||
|
|
||||||
*y = h;
|
*y = h;
|
||||||
*x = w;
|
*x = w;
|
||||||
return _out_;
|
return _out_;
|
||||||
@@ -185,11 +247,20 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var dummy = 0;
|
var dummy = 0;
|
||||||
var depth = 0;
|
var depth = 0;
|
||||||
if (x == null)
|
if (x == null)
|
||||||
|
{
|
||||||
x = &dummy;
|
x = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
if (y == null)
|
if (y == null)
|
||||||
|
{
|
||||||
y = &dummy;
|
y = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
if (comp == null)
|
if (comp == null)
|
||||||
|
{
|
||||||
comp = &dummy;
|
comp = &dummy;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get32be(s) != 0x38425053)
|
if (stbi__get32be(s) != 0x38425053)
|
||||||
{
|
{
|
||||||
stbi__rewind(s);
|
stbi__rewind(s);
|
||||||
@@ -279,7 +350,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
len++;
|
len++;
|
||||||
if (len > nleft)
|
if (len > nleft)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
count += len;
|
count += len;
|
||||||
while (len != 0)
|
while (len != 0)
|
||||||
{
|
{
|
||||||
@@ -293,7 +367,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
byte val = 0;
|
byte val = 0;
|
||||||
len = 257 - len;
|
len = 257 - len;
|
||||||
if (len > nleft)
|
if (len > nleft)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
val = stbi__get8(s);
|
val = stbi__get8(s);
|
||||||
count += len;
|
count += len;
|
||||||
while (len != 0)
|
while (len != 0)
|
||||||
|
|||||||
@@ -16,34 +16,58 @@ namespace Misaki.HighPerformance.Image
|
|||||||
stbi__get8(s);
|
stbi__get8(s);
|
||||||
tga_color_type = stbi__get8(s);
|
tga_color_type = stbi__get8(s);
|
||||||
if (tga_color_type > 1)
|
if (tga_color_type > 1)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
sz = stbi__get8(s);
|
sz = stbi__get8(s);
|
||||||
if (tga_color_type == 1)
|
if (tga_color_type == 1)
|
||||||
{
|
{
|
||||||
if (sz != 1 && sz != 9)
|
if (sz != 1 && sz != 9)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, 4);
|
stbi__skip(s, 4);
|
||||||
sz = stbi__get8(s);
|
sz = stbi__get8(s);
|
||||||
if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32)
|
if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, 4);
|
stbi__skip(s, 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sz != 2 && sz != 3 && sz != 10 && sz != 11)
|
if (sz != 2 && sz != 3 && sz != 10 && sz != 11)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, 9);
|
stbi__skip(s, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stbi__get16le(s) < 1)
|
if (stbi__get16le(s) < 1)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__get16le(s) < 1)
|
if (stbi__get16le(s) < 1)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
sz = stbi__get8(s);
|
sz = stbi__get8(s);
|
||||||
if (tga_color_type == 1 && sz != 8 && sz != 16)
|
if (tga_color_type == 1 && sz != 8 && sz != 16)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32)
|
if (sz != 8 && sz != 15 && sz != 16 && sz != 24 && sz != 32)
|
||||||
|
{
|
||||||
goto errorEnd;
|
goto errorEnd;
|
||||||
|
}
|
||||||
|
|
||||||
res = 1;
|
res = 1;
|
||||||
errorEnd:
|
errorEnd:
|
||||||
;
|
;
|
||||||
@@ -82,9 +106,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var RLE_repeating = 0;
|
var RLE_repeating = 0;
|
||||||
var read_next_pixel = 1;
|
var read_next_pixel = 1;
|
||||||
if (tga_height > 1 << 24)
|
if (tga_height > 1 << 24)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (tga_width > 1 << 24)
|
if (tga_width > 1 << 24)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (tga_image_type >= 8)
|
if (tga_image_type >= 8)
|
||||||
{
|
{
|
||||||
tga_image_type -= 8;
|
tga_image_type -= 8;
|
||||||
@@ -93,20 +123,37 @@ namespace Misaki.HighPerformance.Image
|
|||||||
|
|
||||||
tga_inverted = 1 - ((tga_inverted >> 5) & 1);
|
tga_inverted = 1 - ((tga_inverted >> 5) & 1);
|
||||||
if (tga_indexed != 0)
|
if (tga_indexed != 0)
|
||||||
|
{
|
||||||
tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
|
tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, tga_image_type == 3 ? 1 : 0, &tga_rgb16);
|
tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, tga_image_type == 3 ? 1 : 0, &tga_rgb16);
|
||||||
|
}
|
||||||
|
|
||||||
if (tga_comp == 0)
|
if (tga_comp == 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("bad format") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("bad format") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
*x = tga_width;
|
*x = tga_width;
|
||||||
*y = tga_height;
|
*y = tga_height;
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = tga_comp;
|
*comp = tga_comp;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0) == 0)
|
if (stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0) == 0)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
tga_data = (byte*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
|
tga_data = (byte*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
|
||||||
if (tga_data == null)
|
if (tga_data == null)
|
||||||
|
{
|
||||||
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
stbi__skip(s, tga_offset);
|
stbi__skip(s, tga_offset);
|
||||||
if (tga_indexed == 0 && tga_is_RLE == 0 && tga_rgb16 == 0)
|
if (tga_indexed == 0 && tga_is_RLE == 0 && tga_rgb16 == 0)
|
||||||
{
|
{
|
||||||
@@ -179,10 +226,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var pal_idx = tga_bits_per_pixel == 8 ? stbi__get8(s) : stbi__get16le(s);
|
var pal_idx = tga_bits_per_pixel == 8 ? stbi__get8(s) : stbi__get16le(s);
|
||||||
if (pal_idx >= tga_palette_len)
|
if (pal_idx >= tga_palette_len)
|
||||||
|
{
|
||||||
pal_idx = 0;
|
pal_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
pal_idx *= tga_comp;
|
pal_idx *= tga_comp;
|
||||||
for (j = 0; j < tga_comp; ++j)
|
for (j = 0; j < tga_comp; ++j)
|
||||||
|
{
|
||||||
raw_data[j] = tga_palette[pal_idx + j];
|
raw_data[j] = tga_palette[pal_idx + j];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (tga_rgb16 != 0)
|
else if (tga_rgb16 != 0)
|
||||||
{
|
{
|
||||||
@@ -191,18 +243,24 @@ namespace Misaki.HighPerformance.Image
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (j = 0; j < tga_comp; ++j)
|
for (j = 0; j < tga_comp; ++j)
|
||||||
|
{
|
||||||
raw_data[j] = stbi__get8(s);
|
raw_data[j] = stbi__get8(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
read_next_pixel = 0;
|
read_next_pixel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < tga_comp; ++j)
|
for (j = 0; j < tga_comp; ++j)
|
||||||
|
{
|
||||||
tga_data[i * tga_comp + j] = raw_data[j];
|
tga_data[i * tga_comp + j] = raw_data[j];
|
||||||
|
}
|
||||||
|
|
||||||
--RLE_count;
|
--RLE_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tga_inverted != 0)
|
if (tga_inverted != 0)
|
||||||
|
{
|
||||||
for (j = 0; j * 2 < tga_height; ++j)
|
for (j = 0; j * 2 < tga_height; ++j)
|
||||||
{
|
{
|
||||||
var index1 = j * tga_width * tga_comp;
|
var index1 = j * tga_width * tga_comp;
|
||||||
@@ -216,9 +274,12 @@ namespace Misaki.HighPerformance.Image
|
|||||||
++index2;
|
++index2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tga_palette != null)
|
if (tga_palette != null)
|
||||||
|
{
|
||||||
CRuntime.free(tga_palette);
|
CRuntime.free(tga_palette);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tga_comp >= 3 && tga_rgb16 == 0)
|
if (tga_comp >= 3 && tga_rgb16 == 0)
|
||||||
@@ -234,7 +295,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req_comp != 0 && req_comp != tga_comp)
|
if (req_comp != 0 && req_comp != tga_comp)
|
||||||
|
{
|
||||||
tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, (uint)tga_width, (uint)tga_height);
|
tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, (uint)tga_width, (uint)tga_height);
|
||||||
|
}
|
||||||
|
|
||||||
tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0;
|
tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0;
|
||||||
return tga_data;
|
return tga_data;
|
||||||
}
|
}
|
||||||
@@ -328,18 +392,30 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (x != null)
|
if (x != null)
|
||||||
|
{
|
||||||
*x = tga_w;
|
*x = tga_w;
|
||||||
|
}
|
||||||
|
|
||||||
if (y != null)
|
if (y != null)
|
||||||
|
{
|
||||||
*y = tga_h;
|
*y = tga_h;
|
||||||
|
}
|
||||||
|
|
||||||
if (comp != null)
|
if (comp != null)
|
||||||
|
{
|
||||||
*comp = tga_comp;
|
*comp = tga_comp;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
|
public static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
|
||||||
{
|
{
|
||||||
if (is_rgb16 != null)
|
if (is_rgb16 != null)
|
||||||
|
{
|
||||||
*is_rgb16 = 0;
|
*is_rgb16 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (bits_per_pixel)
|
switch (bits_per_pixel)
|
||||||
{
|
{
|
||||||
case 8:
|
case 8:
|
||||||
@@ -347,9 +423,15 @@ namespace Misaki.HighPerformance.Image
|
|||||||
case 16:
|
case 16:
|
||||||
case 15:
|
case 15:
|
||||||
if (bits_per_pixel == 16 && is_grey != 0)
|
if (bits_per_pixel == 16 && is_grey != 0)
|
||||||
|
{
|
||||||
return STBI_grey_alpha;
|
return STBI_grey_alpha;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_rgb16 != null)
|
if (is_rgb16 != null)
|
||||||
|
{
|
||||||
*is_rgb16 = 1;
|
*is_rgb16 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return STBI_rgb;
|
return STBI_rgb;
|
||||||
case 24:
|
case 24:
|
||||||
case 32:
|
case 32:
|
||||||
|
|||||||
@@ -45,13 +45,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var a = new stbi__zbuf();
|
var a = new stbi__zbuf();
|
||||||
var p = (sbyte*)stbi__malloc((ulong)initial_size);
|
var p = (sbyte*)stbi__malloc((ulong)initial_size);
|
||||||
if (p == null)
|
if (p == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
a.zbuffer = (byte*)buffer;
|
a.zbuffer = (byte*)buffer;
|
||||||
a.zbuffer_end = (byte*)buffer + len;
|
a.zbuffer_end = (byte*)buffer + len;
|
||||||
if (stbi__do_zlib(&a, p, initial_size, 1, 1) != 0)
|
if (stbi__do_zlib(&a, p, initial_size, 1, 1) != 0)
|
||||||
{
|
{
|
||||||
if (outlen != null)
|
if (outlen != null)
|
||||||
|
{
|
||||||
*outlen = (int)(a.zout - a.zout_start);
|
*outlen = (int)(a.zout - a.zout_start);
|
||||||
|
}
|
||||||
|
|
||||||
return a.zout_start;
|
return a.zout_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,13 +71,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var a = new stbi__zbuf();
|
var a = new stbi__zbuf();
|
||||||
var p = (sbyte*)stbi__malloc((ulong)initial_size);
|
var p = (sbyte*)stbi__malloc((ulong)initial_size);
|
||||||
if (p == null)
|
if (p == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
a.zbuffer = (byte*)buffer;
|
a.zbuffer = (byte*)buffer;
|
||||||
a.zbuffer_end = (byte*)buffer + len;
|
a.zbuffer_end = (byte*)buffer + len;
|
||||||
if (stbi__do_zlib(&a, p, initial_size, 1, parse_header) != 0)
|
if (stbi__do_zlib(&a, p, initial_size, 1, parse_header) != 0)
|
||||||
{
|
{
|
||||||
if (outlen != null)
|
if (outlen != null)
|
||||||
|
{
|
||||||
*outlen = (int)(a.zout - a.zout_start);
|
*outlen = (int)(a.zout - a.zout_start);
|
||||||
|
}
|
||||||
|
|
||||||
return a.zout_start;
|
return a.zout_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +102,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
a.zbuffer = (byte*)ibuffer;
|
a.zbuffer = (byte*)ibuffer;
|
||||||
a.zbuffer_end = (byte*)ibuffer + ilen;
|
a.zbuffer_end = (byte*)ibuffer + ilen;
|
||||||
if (stbi__do_zlib(&a, obuffer, olen, 0, 1) != 0)
|
if (stbi__do_zlib(&a, obuffer, olen, 0, 1) != 0)
|
||||||
|
{
|
||||||
return (int)(a.zout - a.zout_start);
|
return (int)(a.zout - a.zout_start);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,13 +114,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var a = new stbi__zbuf();
|
var a = new stbi__zbuf();
|
||||||
var p = (sbyte*)stbi__malloc(16384);
|
var p = (sbyte*)stbi__malloc(16384);
|
||||||
if (p == null)
|
if (p == null)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
a.zbuffer = (byte*)buffer;
|
a.zbuffer = (byte*)buffer;
|
||||||
a.zbuffer_end = (byte*)buffer + len;
|
a.zbuffer_end = (byte*)buffer + len;
|
||||||
if (stbi__do_zlib(&a, p, 16384, 1, 0) != 0)
|
if (stbi__do_zlib(&a, p, 16384, 1, 0) != 0)
|
||||||
{
|
{
|
||||||
if (outlen != null)
|
if (outlen != null)
|
||||||
|
{
|
||||||
*outlen = (int)(a.zout - a.zout_start);
|
*outlen = (int)(a.zout - a.zout_start);
|
||||||
|
}
|
||||||
|
|
||||||
return a.zout_start;
|
return a.zout_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +140,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
a.zbuffer = (byte*)ibuffer;
|
a.zbuffer = (byte*)ibuffer;
|
||||||
a.zbuffer_end = (byte*)ibuffer + ilen;
|
a.zbuffer_end = (byte*)ibuffer + ilen;
|
||||||
if (stbi__do_zlib(&a, obuffer, olen, 0, 0) != 0)
|
if (stbi__do_zlib(&a, obuffer, olen, 0, 0) != 0)
|
||||||
|
{
|
||||||
return (int)(a.zout - a.zout_start);
|
return (int)(a.zout - a.zout_start);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,12 +157,18 @@ namespace Misaki.HighPerformance.Image
|
|||||||
CRuntime.memset(sizes, 0, (ulong)(17 * sizeof(int)));
|
CRuntime.memset(sizes, 0, (ulong)(17 * sizeof(int)));
|
||||||
CRuntime.memset(z->fast, 0, (ulong)(512 * sizeof(ushort)));
|
CRuntime.memset(z->fast, 0, (ulong)(512 * sizeof(ushort)));
|
||||||
for (i = 0; i < num; ++i)
|
for (i = 0; i < num; ++i)
|
||||||
|
{
|
||||||
++sizes[sizelist[i]];
|
++sizes[sizelist[i]];
|
||||||
|
}
|
||||||
|
|
||||||
sizes[0] = 0;
|
sizes[0] = 0;
|
||||||
for (i = 1; i < 16; ++i)
|
for (i = 1; i < 16; ++i)
|
||||||
|
{
|
||||||
if (sizes[i] > 1 << i)
|
if (sizes[i] > 1 << i)
|
||||||
|
{
|
||||||
return stbi__err("bad sizes");
|
return stbi__err("bad sizes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
code = 0;
|
code = 0;
|
||||||
for (i = 1; i < 16; ++i)
|
for (i = 1; i < 16; ++i)
|
||||||
@@ -148,8 +178,13 @@ namespace Misaki.HighPerformance.Image
|
|||||||
z->firstsymbol[i] = (ushort)k;
|
z->firstsymbol[i] = (ushort)k;
|
||||||
code = code + sizes[i];
|
code = code + sizes[i];
|
||||||
if (sizes[i] != 0)
|
if (sizes[i] != 0)
|
||||||
|
{
|
||||||
if (code - 1 >= 1 << i)
|
if (code - 1 >= 1 << i)
|
||||||
|
{
|
||||||
return stbi__err("bad codelengths");
|
return stbi__err("bad codelengths");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
z->maxcode[i] = code << (16 - i);
|
z->maxcode[i] = code << (16 - i);
|
||||||
code <<= 1;
|
code <<= 1;
|
||||||
k += sizes[i];
|
k += sizes[i];
|
||||||
@@ -211,7 +246,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
uint k = 0;
|
uint k = 0;
|
||||||
if (z->num_bits < n)
|
if (z->num_bits < n)
|
||||||
|
{
|
||||||
stbi__fill_bits(z);
|
stbi__fill_bits(z);
|
||||||
|
}
|
||||||
|
|
||||||
k = (uint)(z->code_buffer & ((1 << n) - 1));
|
k = (uint)(z->code_buffer & ((1 << n) - 1));
|
||||||
z->code_buffer >>= n;
|
z->code_buffer >>= n;
|
||||||
z->num_bits -= n;
|
z->num_bits -= n;
|
||||||
@@ -225,16 +263,29 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var k = 0;
|
var k = 0;
|
||||||
k = stbi__bit_reverse((int)a->code_buffer, 16);
|
k = stbi__bit_reverse((int)a->code_buffer, 16);
|
||||||
for (s = 9 + 1; ; ++s)
|
for (s = 9 + 1; ; ++s)
|
||||||
|
{
|
||||||
if (k < z->maxcode[s])
|
if (k < z->maxcode[s])
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s >= 16)
|
if (s >= 16)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
b = (k >> (16 - s)) - z->firstcode[s] + z->firstsymbol[s];
|
b = (k >> (16 - s)) - z->firstcode[s] + z->firstsymbol[s];
|
||||||
if (b >= 288)
|
if (b >= 288)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (z->size[b] != s)
|
if (z->size[b] != s)
|
||||||
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
a->code_buffer >>= s;
|
a->code_buffer >>= s;
|
||||||
a->num_bits -= s;
|
a->num_bits -= s;
|
||||||
return z->value[b];
|
return z->value[b];
|
||||||
@@ -284,21 +335,33 @@ namespace Misaki.HighPerformance.Image
|
|||||||
uint old_limit = 0;
|
uint old_limit = 0;
|
||||||
z->zout = zout;
|
z->zout = zout;
|
||||||
if (z->z_expandable == 0)
|
if (z->z_expandable == 0)
|
||||||
|
{
|
||||||
return stbi__err("output buffer limit");
|
return stbi__err("output buffer limit");
|
||||||
|
}
|
||||||
|
|
||||||
cur = (uint)(z->zout - z->zout_start);
|
cur = (uint)(z->zout - z->zout_start);
|
||||||
limit = old_limit = (uint)(z->zout_end - z->zout_start);
|
limit = old_limit = (uint)(z->zout_end - z->zout_start);
|
||||||
if (0xffffffff - cur < (uint)n)
|
if (0xffffffff - cur < (uint)n)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
while (cur + n > limit)
|
while (cur + n > limit)
|
||||||
{
|
{
|
||||||
if (limit > 0xffffffff / 2)
|
if (limit > 0xffffffff / 2)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
limit *= 2;
|
limit *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
q = (sbyte*)CRuntime.realloc(z->zout_start, (ulong)limit);
|
q = (sbyte*)CRuntime.realloc(z->zout_start, (ulong)limit);
|
||||||
if (q == null)
|
if (q == null)
|
||||||
|
{
|
||||||
return stbi__err("outofmem");
|
return stbi__err("outofmem");
|
||||||
|
}
|
||||||
|
|
||||||
z->zout_start = q;
|
z->zout_start = q;
|
||||||
z->zout = q + cur;
|
z->zout = q + cur;
|
||||||
z->zout_end = q + limit;
|
z->zout_end = q + limit;
|
||||||
@@ -314,11 +377,17 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if (z < 256)
|
if (z < 256)
|
||||||
{
|
{
|
||||||
if (z < 0)
|
if (z < 0)
|
||||||
|
{
|
||||||
return stbi__err("bad huffman code");
|
return stbi__err("bad huffman code");
|
||||||
|
}
|
||||||
|
|
||||||
if (zout >= a->zout_end)
|
if (zout >= a->zout_end)
|
||||||
{
|
{
|
||||||
if (stbi__zexpand(a, zout, 1) == 0)
|
if (stbi__zexpand(a, zout, 1) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
zout = a->zout;
|
zout = a->zout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,29 +402,49 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
a->zout = zout;
|
a->zout = zout;
|
||||||
if (a->hit_zeof_once != 0 && a->num_bits < 16)
|
if (a->hit_zeof_once != 0 && a->num_bits < 16)
|
||||||
|
{
|
||||||
return stbi__err("unexpected end");
|
return stbi__err("unexpected end");
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (z >= 286)
|
if (z >= 286)
|
||||||
|
{
|
||||||
return stbi__err("bad huffman code");
|
return stbi__err("bad huffman code");
|
||||||
|
}
|
||||||
|
|
||||||
z -= 257;
|
z -= 257;
|
||||||
len = stbi__zlength_base[z];
|
len = stbi__zlength_base[z];
|
||||||
if (stbi__zlength_extra[z] != 0)
|
if (stbi__zlength_extra[z] != 0)
|
||||||
|
{
|
||||||
len += (int)stbi__zreceive(a, stbi__zlength_extra[z]);
|
len += (int)stbi__zreceive(a, stbi__zlength_extra[z]);
|
||||||
|
}
|
||||||
|
|
||||||
z = stbi__zhuffman_decode(a, &a->z_distance);
|
z = stbi__zhuffman_decode(a, &a->z_distance);
|
||||||
if (z < 0 || z >= 30)
|
if (z < 0 || z >= 30)
|
||||||
|
{
|
||||||
return stbi__err("bad huffman code");
|
return stbi__err("bad huffman code");
|
||||||
|
}
|
||||||
|
|
||||||
dist = stbi__zdist_base[z];
|
dist = stbi__zdist_base[z];
|
||||||
if (stbi__zdist_extra[z] != 0)
|
if (stbi__zdist_extra[z] != 0)
|
||||||
|
{
|
||||||
dist += (int)stbi__zreceive(a, stbi__zdist_extra[z]);
|
dist += (int)stbi__zreceive(a, stbi__zdist_extra[z]);
|
||||||
|
}
|
||||||
|
|
||||||
if (zout - a->zout_start < dist)
|
if (zout - a->zout_start < dist)
|
||||||
|
{
|
||||||
return stbi__err("bad dist");
|
return stbi__err("bad dist");
|
||||||
|
}
|
||||||
|
|
||||||
if (len > a->zout_end - zout)
|
if (len > a->zout_end - zout)
|
||||||
{
|
{
|
||||||
if (stbi__zexpand(a, zout, len) == 0)
|
if (stbi__zexpand(a, zout, len) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
zout = a->zout;
|
zout = a->zout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,18 +453,22 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
var v = *p;
|
var v = *p;
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*zout++ = (sbyte)v;
|
*zout++ = (sbyte)v;
|
||||||
} while (--len != 0);
|
} while (--len != 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*zout++ = (sbyte)*p++;
|
*zout++ = (sbyte)*p++;
|
||||||
} while (--len != 0);
|
} while (--len != 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,13 +493,19 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19) == 0)
|
if (stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
while (n < ntot)
|
while (n < ntot)
|
||||||
{
|
{
|
||||||
var c = stbi__zhuffman_decode(a, &z_codelength);
|
var c = stbi__zhuffman_decode(a, &z_codelength);
|
||||||
if (c < 0 || c >= 19)
|
if (c < 0 || c >= 19)
|
||||||
|
{
|
||||||
return stbi__err("bad codelengths");
|
return stbi__err("bad codelengths");
|
||||||
|
}
|
||||||
|
|
||||||
if (c < 16)
|
if (c < 16)
|
||||||
{
|
{
|
||||||
lencodes[n++] = (byte)c;
|
lencodes[n++] = (byte)c;
|
||||||
@@ -418,7 +517,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
{
|
{
|
||||||
c = (int)(stbi__zreceive(a, 2) + 3);
|
c = (int)(stbi__zreceive(a, 2) + 3);
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
|
{
|
||||||
return stbi__err("bad codelengths");
|
return stbi__err("bad codelengths");
|
||||||
|
}
|
||||||
|
|
||||||
fill = lencodes[n - 1];
|
fill = lencodes[n - 1];
|
||||||
}
|
}
|
||||||
else if (c == 17)
|
else if (c == 17)
|
||||||
@@ -435,18 +537,30 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ntot - n < c)
|
if (ntot - n < c)
|
||||||
|
{
|
||||||
return stbi__err("bad codelengths");
|
return stbi__err("bad codelengths");
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.memset(lencodes + n, fill, (ulong)c);
|
CRuntime.memset(lencodes + n, fill, (ulong)c);
|
||||||
n += c;
|
n += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n != ntot)
|
if (n != ntot)
|
||||||
|
{
|
||||||
return stbi__err("bad codelengths");
|
return stbi__err("bad codelengths");
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__zbuild_huffman(&a->z_length, lencodes, hlit) == 0)
|
if (stbi__zbuild_huffman(&a->z_length, lencodes, hlit) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist) == 0)
|
if (stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +571,10 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var nlen = 0;
|
var nlen = 0;
|
||||||
var k = 0;
|
var k = 0;
|
||||||
if ((a->num_bits & 7) != 0)
|
if ((a->num_bits & 7) != 0)
|
||||||
|
{
|
||||||
stbi__zreceive(a, a->num_bits & 7);
|
stbi__zreceive(a, a->num_bits & 7);
|
||||||
|
}
|
||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
while (a->num_bits > 0)
|
while (a->num_bits > 0)
|
||||||
{
|
{
|
||||||
@@ -467,19 +584,35 @@ namespace Misaki.HighPerformance.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (a->num_bits < 0)
|
if (a->num_bits < 0)
|
||||||
|
{
|
||||||
return stbi__err("zlib corrupt");
|
return stbi__err("zlib corrupt");
|
||||||
|
}
|
||||||
|
|
||||||
while (k < 4)
|
while (k < 4)
|
||||||
|
{
|
||||||
header[k++] = stbi__zget8(a);
|
header[k++] = stbi__zget8(a);
|
||||||
|
}
|
||||||
|
|
||||||
len = header[1] * 256 + header[0];
|
len = header[1] * 256 + header[0];
|
||||||
nlen = header[3] * 256 + header[2];
|
nlen = header[3] * 256 + header[2];
|
||||||
if (nlen != (len ^ 0xffff))
|
if (nlen != (len ^ 0xffff))
|
||||||
|
{
|
||||||
return stbi__err("zlib corrupt");
|
return stbi__err("zlib corrupt");
|
||||||
|
}
|
||||||
|
|
||||||
if (a->zbuffer + len > a->zbuffer_end)
|
if (a->zbuffer + len > a->zbuffer_end)
|
||||||
|
{
|
||||||
return stbi__err("read past buffer");
|
return stbi__err("read past buffer");
|
||||||
|
}
|
||||||
|
|
||||||
if (a->zout + len > a->zout_end)
|
if (a->zout + len > a->zout_end)
|
||||||
|
{
|
||||||
if (stbi__zexpand(a, a->zout, len) == 0)
|
if (stbi__zexpand(a, a->zout, len) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CRuntime.memcpy(a->zout, a->zbuffer, (ulong)len);
|
CRuntime.memcpy(a->zout, a->zbuffer, (ulong)len);
|
||||||
a->zbuffer += len;
|
a->zbuffer += len;
|
||||||
a->zout += len;
|
a->zout += len;
|
||||||
@@ -492,13 +625,25 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var cm = cmf & 15;
|
var cm = cmf & 15;
|
||||||
int flg = stbi__zget8(a);
|
int flg = stbi__zget8(a);
|
||||||
if (stbi__zeof(a) != 0)
|
if (stbi__zeof(a) != 0)
|
||||||
|
{
|
||||||
return stbi__err("bad zlib header");
|
return stbi__err("bad zlib header");
|
||||||
|
}
|
||||||
|
|
||||||
if ((cmf * 256 + flg) % 31 != 0)
|
if ((cmf * 256 + flg) % 31 != 0)
|
||||||
|
{
|
||||||
return stbi__err("bad zlib header");
|
return stbi__err("bad zlib header");
|
||||||
|
}
|
||||||
|
|
||||||
if ((flg & 32) != 0)
|
if ((flg & 32) != 0)
|
||||||
|
{
|
||||||
return stbi__err("no preset dict");
|
return stbi__err("no preset dict");
|
||||||
|
}
|
||||||
|
|
||||||
if (cm != 8)
|
if (cm != 8)
|
||||||
|
{
|
||||||
return stbi__err("bad compression");
|
return stbi__err("bad compression");
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,8 +652,13 @@ namespace Misaki.HighPerformance.Image
|
|||||||
var final = 0;
|
var final = 0;
|
||||||
var type = 0;
|
var type = 0;
|
||||||
if (parse_header != 0)
|
if (parse_header != 0)
|
||||||
|
{
|
||||||
if (stbi__parse_zlib_header(a) == 0)
|
if (stbi__parse_zlib_header(a) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
a->num_bits = 0;
|
a->num_bits = 0;
|
||||||
a->code_buffer = 0;
|
a->code_buffer = 0;
|
||||||
a->hit_zeof_once = 0;
|
a->hit_zeof_once = 0;
|
||||||
@@ -519,7 +669,9 @@ namespace Misaki.HighPerformance.Image
|
|||||||
if (type == 0)
|
if (type == 0)
|
||||||
{
|
{
|
||||||
if (stbi__parse_uncompressed_block(a) == 0)
|
if (stbi__parse_uncompressed_block(a) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (type == 3)
|
else if (type == 3)
|
||||||
{
|
{
|
||||||
@@ -532,23 +684,31 @@ namespace Misaki.HighPerformance.Image
|
|||||||
fixed (byte* b = stbi__zdefault_length)
|
fixed (byte* b = stbi__zdefault_length)
|
||||||
{
|
{
|
||||||
if (stbi__zbuild_huffman(&a->z_length, b, 288) == 0)
|
if (stbi__zbuild_huffman(&a->z_length, b, 288) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* b = stbi__zdefault_distance)
|
fixed (byte* b = stbi__zdefault_distance)
|
||||||
{
|
{
|
||||||
if (stbi__zbuild_huffman(&a->z_distance, b, 32) == 0)
|
if (stbi__zbuild_huffman(&a->z_distance, b, 32) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (stbi__compute_huffman_codes(a) == 0)
|
if (stbi__compute_huffman_codes(a) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stbi__parse_huffman_block(a) == 0)
|
if (stbi__parse_huffman_block(a) == 0)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (final == 0);
|
} while (final == 0);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Misaki.HighPerformance.Image.Runtime;
|
using Misaki.HighPerformance.Image.Runtime;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -31,7 +31,9 @@ public static unsafe partial class StbImage
|
|||||||
public stbi__context(Stream stream)
|
public stbi__context(Stream stream)
|
||||||
{
|
{
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
|
{
|
||||||
throw new ArgumentNullException("stream");
|
throw new ArgumentNullException("stream");
|
||||||
|
}
|
||||||
|
|
||||||
_stream = stream;
|
_stream = stream;
|
||||||
}
|
}
|
||||||
@@ -55,7 +57,9 @@ public static unsafe partial class StbImage
|
|||||||
{
|
{
|
||||||
var b = s.Stream.ReadByte();
|
var b = s.Stream.ReadByte();
|
||||||
if (b == -1)
|
if (b == -1)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (byte)b;
|
return (byte)b;
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,9 @@ public static unsafe partial class StbImage
|
|||||||
{
|
{
|
||||||
if (s._tempBuffer == null ||
|
if (s._tempBuffer == null ||
|
||||||
s._tempBuffer.Length < size)
|
s._tempBuffer.Length < size)
|
||||||
|
{
|
||||||
s._tempBuffer = new byte[size * 2];
|
s._tempBuffer = new byte[size * 2];
|
||||||
|
}
|
||||||
|
|
||||||
var result = s.Stream.Read(s._tempBuffer, 0, size);
|
var result = s.Stream.Read(s._tempBuffer, 0, size);
|
||||||
Marshal.Copy(s._tempBuffer, 0, new IntPtr(buf), result);
|
Marshal.Copy(s._tempBuffer, 0, new IntPtr(buf), result);
|
||||||
|
|||||||
@@ -6,6 +6,161 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.Jobs;
|
namespace Misaki.HighPerformance.Jobs;
|
||||||
|
|
||||||
|
public interface IJobScheduler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of worker threads managed by the job scheduler.
|
||||||
|
/// </summary>
|
||||||
|
int WorkerCount
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a single job for execution on a specified thread, with an optional dependency on another job.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <param name="dependency">A <see cref="JobHandle"/> representing the dependencies that must be completed before this job can begin.
|
||||||
|
/// Use <see cref="JobHandle.Invalid"/> if there are no dependencies.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
JobHandle Schedule<T>(ref T job, int threadIndex, JobHandle dependency)
|
||||||
|
where T : unmanaged, IJob;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a single job for execution on a specified thread without dependency.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
JobHandle Schedule<T>(ref T job, int threadIndex)
|
||||||
|
where T : unmanaged, IJob;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a single job for execution on any thread, with an optional dependency on another job.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
JobHandle Schedule<T>(ref T job, JobHandle dependency)
|
||||||
|
where T : unmanaged, IJob;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a single job for execution on any thread without dependency.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
JobHandle Schedule<T>(ref T job)
|
||||||
|
where T : unmanaged, IJob;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
||||||
|
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <param name="dependency">A <see cref="JobHandle"/> representing the dependencies that must be completed before this job can begin.
|
||||||
|
/// Use <see cref="JobHandle.Invalid"/> if there are no dependencies.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex, JobHandle dependency)
|
||||||
|
where T : unmanaged, IJobParallelFor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads on a specified thread without dependency.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
||||||
|
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex)
|
||||||
|
where T : unmanaged, IJobParallelFor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads on any thread, with an optional dependency on another job..
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
||||||
|
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, JobHandle dependency)
|
||||||
|
where T : unmanaged, IJobParallelFor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads on any thread without dependency.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
||||||
|
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
||||||
|
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
||||||
|
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
||||||
|
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
||||||
|
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
||||||
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize)
|
||||||
|
where T : unmanaged, IJobParallelFor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Combines multiple job dependencies into a single <see cref="JobHandle"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dependencies">A collection of <see cref="JobHandle"/> instances representing the dependencies to combine.</param>
|
||||||
|
/// <returns>A <see cref="JobHandle"/> that represents the combined dependencies. The returned handle can be used to ensure
|
||||||
|
/// that all specified dependencies are completed before proceeding.</returns>
|
||||||
|
public JobHandle CombineDependencies(params ReadOnlySpan<JobHandle> dependencies);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the current status of a job identified by the specified handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle representing the job whose status is to be retrieved. The handle must be valid.</param>
|
||||||
|
/// <returns>The current status of the job as a <see cref="JobState"/> value.
|
||||||
|
/// Returns <see cref="JobState.Invalid"/> if the handle is invalid or the job does not exist.</returns>
|
||||||
|
public JobState GetJobStatus(JobHandle handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blocks the calling thread until the specified job is completed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the job to wait for.</param>
|
||||||
|
public void WaitComplete(JobHandle handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blocks the calling thread until all specified job handles have completed.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This method waits for all jobs referenced by the provided handles to complete before
|
||||||
|
/// returning. The calling thread will be blocked until every job has finished. If any handle is invalid or does not
|
||||||
|
/// correspond to an active job, it is considered completed. This method is not thread-safe and should not be called
|
||||||
|
/// concurrently from multiple threads.</remarks>
|
||||||
|
/// <param name="handles">A collection of job handles to wait for. Each handle represents an asynchronous job whose completion is awaited.
|
||||||
|
/// The collection must not be empty.</param>
|
||||||
|
public void WaitAll(params ReadOnlySpan<JobHandle> handles);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits until any of the specified job handles has completed and returns the first completed handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This method blocks the calling thread until at least one of the specified jobs has finished.
|
||||||
|
/// The returned handle corresponds to the job that completed first among those provided. The order of handles in
|
||||||
|
/// the span may affect which handle is returned if multiple jobs complete simultaneously.</remarks>
|
||||||
|
/// <param name="handles">A read-only span containing the job handles to monitor for completion. Each handle represents a job whose
|
||||||
|
/// completion status will be checked.</param>
|
||||||
|
/// <returns>The first job handle from the provided collection that has completed.</returns>
|
||||||
|
public JobHandle WaitAny(params ReadOnlySpan<JobHandle> handles);
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe partial class JobScheduler
|
public unsafe partial class JobScheduler
|
||||||
{
|
{
|
||||||
public static readonly TempJobAllocator* pTempAllocator;
|
public static readonly TempJobAllocator* pTempAllocator;
|
||||||
@@ -37,7 +192,7 @@ public unsafe partial class JobScheduler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides a mechanism for scheduling and executing jobs across multiple worker threads.
|
/// Provides a mechanism for scheduling and executing jobs across multiple worker threads.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed unsafe partial class JobScheduler : IDisposable
|
public sealed unsafe partial class JobScheduler : IJobScheduler, IDisposable
|
||||||
{
|
{
|
||||||
private const int _SLEEP_THRESHOLD = 100;
|
private const int _SLEEP_THRESHOLD = 100;
|
||||||
|
|
||||||
@@ -253,16 +408,6 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a single job for execution on a specified thread, with an optional dependency on another job.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <param name="dependency">A <see cref="JobHandle"/> representing the dependencies that must be completed before this job can begin.
|
|
||||||
/// Use <see cref="JobHandle.Invalid"/> if there are no dependencies.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle Schedule<T>(ref T job, int threadIndex, JobHandle dependency)
|
public JobHandle Schedule<T>(ref T job, int threadIndex, JobHandle dependency)
|
||||||
where T : unmanaged, IJob
|
where T : unmanaged, IJob
|
||||||
{
|
{
|
||||||
@@ -291,54 +436,18 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
return CreateJobHandle(ref jobInfo, dependency);
|
return CreateJobHandle(ref jobInfo, dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a single job for execution on a specified thread without dependency.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle Schedule<T>(ref T job, int threadIndex)
|
public JobHandle Schedule<T>(ref T job, int threadIndex)
|
||||||
where T : unmanaged, IJob
|
where T : unmanaged, IJob
|
||||||
=> Schedule(ref job, threadIndex, JobHandle.Invalid);
|
=> Schedule(ref job, threadIndex, JobHandle.Invalid);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a single job for execution on any thread, with an optional dependency on another job.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle Schedule<T>(ref T job, JobHandle dependency)
|
public JobHandle Schedule<T>(ref T job, JobHandle dependency)
|
||||||
where T : unmanaged, IJob
|
where T : unmanaged, IJob
|
||||||
=> Schedule(ref job, -1, dependency);
|
=> Schedule(ref job, -1, dependency);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a single job for execution on any thread without dependency.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJob"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle Schedule<T>(ref T job)
|
public JobHandle Schedule<T>(ref T job)
|
||||||
where T : unmanaged, IJob
|
where T : unmanaged, IJob
|
||||||
=> Schedule(ref job, -1, JobHandle.Invalid);
|
=> Schedule(ref job, -1, JobHandle.Invalid);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
|
||||||
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <param name="dependency">A <see cref="JobHandle"/> representing the dependencies that must be completed before this job can begin.
|
|
||||||
/// Use <see cref="JobHandle.Invalid"/> if there are no dependencies.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex, JobHandle dependency)
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex, JobHandle dependency)
|
||||||
where T : unmanaged, IJobParallelFor
|
where T : unmanaged, IJobParallelFor
|
||||||
{
|
{
|
||||||
@@ -375,54 +484,18 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
return CreateJobHandle(ref jobInfo, dependency);
|
return CreateJobHandle(ref jobInfo, dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads on a specified thread without dependency.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
|
||||||
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex)
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex)
|
||||||
where T : unmanaged, IJobParallelFor
|
where T : unmanaged, IJobParallelFor
|
||||||
=> ScheduleParallel(ref job, totalIteration, batchSize, threadIndex, JobHandle.Invalid);
|
=> ScheduleParallel(ref job, totalIteration, batchSize, threadIndex, JobHandle.Invalid);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads on any thread, with an optional dependency on another job..
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
|
||||||
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, JobHandle dependency)
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, JobHandle dependency)
|
||||||
where T : unmanaged, IJobParallelFor
|
where T : unmanaged, IJobParallelFor
|
||||||
=> ScheduleParallel(ref job, totalIteration, batchSize, -1, dependency);
|
=> ScheduleParallel(ref job, totalIteration, batchSize, -1, dependency);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Schedules a parallel job for execution, dividing the workload into batches and distributing it across threads on any thread without dependency.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the job to execute. Must implement <see cref="IJobParallelFor"/> and be unmanaged.</typeparam>
|
|
||||||
/// <param name="job">The job instance to be executed. The job data will be copied internally.</param>
|
|
||||||
/// <param name="totalIteration">The total number of iterations to be processed by the job.</param>
|
|
||||||
/// <param name="batchSize">The number of iterations to include in each batch.</param>
|
|
||||||
/// <param name="threadIndex">The index of the thread that will execute the job. This is used to assign thread-specific data. Use -1 to allow any thread to execute the job.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that can be used to track the completion of the scheduled job.
|
|
||||||
/// Returns <see cref="JobHandle.Invalid"/> if the job data allocation fails.</returns>
|
|
||||||
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize)
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize)
|
||||||
where T : unmanaged, IJobParallelFor
|
where T : unmanaged, IJobParallelFor
|
||||||
=> ScheduleParallel(ref job, totalIteration, batchSize, -1, JobHandle.Invalid);
|
=> ScheduleParallel(ref job, totalIteration, batchSize, -1, JobHandle.Invalid);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Combines multiple job dependencies into a single <see cref="JobHandle"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dependencies">A collection of <see cref="JobHandle"/> instances representing the dependencies to combine.</param>
|
|
||||||
/// <returns>A <see cref="JobHandle"/> that represents the combined dependencies. The returned handle can be used to ensure
|
|
||||||
/// that all specified dependencies are completed before proceeding.</returns>
|
|
||||||
public JobHandle CombineDependencies(params ReadOnlySpan<JobHandle> dependencies)
|
public JobHandle CombineDependencies(params ReadOnlySpan<JobHandle> dependencies)
|
||||||
{
|
{
|
||||||
var jobInfo = new JobInfo
|
var jobInfo = new JobInfo
|
||||||
@@ -439,12 +512,6 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
return CreateJobHandle(ref jobInfo, dependencies);
|
return CreateJobHandle(ref jobInfo, dependencies);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the current status of a job identified by the specified handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle representing the job whose status is to be retrieved. The handle must be valid.</param>
|
|
||||||
/// <returns>The current status of the job as a <see cref="JobState"/> value.
|
|
||||||
/// Returns <see cref="JobState.Invalid"/> if the handle is invalid or the job does not exist.</returns>
|
|
||||||
public JobState GetJobStatus(JobHandle handle)
|
public JobState GetJobStatus(JobHandle handle)
|
||||||
{
|
{
|
||||||
if (!handle.IsValid)
|
if (!handle.IsValid)
|
||||||
@@ -461,10 +528,6 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
return (JobState)Volatile.Read(ref Unsafe.As<JobState, int>(ref jobInfo.state));
|
return (JobState)Volatile.Read(ref Unsafe.As<JobState, int>(ref jobInfo.state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blocks the calling thread until the specified job is completed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the job to wait for.</param>
|
|
||||||
public void WaitComplete(JobHandle handle)
|
public void WaitComplete(JobHandle handle)
|
||||||
{
|
{
|
||||||
if (!handle.IsValid)
|
if (!handle.IsValid)
|
||||||
@@ -484,15 +547,6 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Blocks the calling thread until all specified job handles have completed.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>This method waits for all jobs referenced by the provided handles to complete before
|
|
||||||
/// returning. The calling thread will be blocked until every job has finished. If any handle is invalid or does not
|
|
||||||
/// correspond to an active job, it is considered completed. This method is not thread-safe and should not be called
|
|
||||||
/// concurrently from multiple threads.</remarks>
|
|
||||||
/// <param name="handles">A collection of job handles to wait for. Each handle represents an asynchronous job whose completion is awaited.
|
|
||||||
/// The collection must not be empty.</param>
|
|
||||||
public void WaitAll(params ReadOnlySpan<JobHandle> handles)
|
public void WaitAll(params ReadOnlySpan<JobHandle> handles)
|
||||||
{
|
{
|
||||||
var sleepThreshold = _SLEEP_THRESHOLD * handles.Length;
|
var sleepThreshold = _SLEEP_THRESHOLD * handles.Length;
|
||||||
@@ -518,15 +572,6 @@ public sealed unsafe partial class JobScheduler : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Waits until any of the specified job handles has completed and returns the first completed handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>This method blocks the calling thread until at least one of the specified jobs has finished.
|
|
||||||
/// The returned handle corresponds to the job that completed first among those provided. The order of handles in
|
|
||||||
/// the span may affect which handle is returned if multiple jobs complete simultaneously.</remarks>
|
|
||||||
/// <param name="handles">A read-only span containing the job handles to monitor for completion. Each handle represents a job whose
|
|
||||||
/// completion status will be checked.</param>
|
|
||||||
/// <returns>The first job handle from the provided collection that has completed.</returns>
|
|
||||||
public JobHandle WaitAny(params ReadOnlySpan<JobHandle> handles)
|
public JobHandle WaitAny(params ReadOnlySpan<JobHandle> handles)
|
||||||
{
|
{
|
||||||
var sleepThreshold = _SLEEP_THRESHOLD * handles.Length;
|
var sleepThreshold = _SLEEP_THRESHOLD * handles.Length;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<AssemblyVersion>1.2.1</AssemblyVersion>
|
<AssemblyVersion>1.2.2</AssemblyVersion>
|
||||||
<Version>$(AssemblyVersion)</Version>
|
<Version>$(AssemblyVersion)</Version>
|
||||||
<Authors>Misaki</Authors>
|
<Authors>Misaki</Authors>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
private int _count;
|
private int _count;
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
|
|
||||||
public readonly int Count => _count - 1;
|
public readonly int Count => _count;
|
||||||
public readonly int Capacity => _capacity;
|
public readonly int Capacity => _capacity;
|
||||||
|
|
||||||
public readonly bool IsCreated => _data.IsCreated && _generations.IsCreated && _freeSlots.IsCreated && _validBits.IsCreated;
|
public readonly bool IsCreated => _data.IsCreated && _generations.IsCreated && _freeSlots.IsCreated && _validBits.IsCreated;
|
||||||
@@ -126,9 +126,6 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
_count = 0;
|
_count = 0;
|
||||||
_capacity = capacity;
|
_capacity = capacity;
|
||||||
|
|
||||||
// Add a default item for invalid slot
|
|
||||||
Add(default, out _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -212,8 +209,7 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
/// <returns>true if the slot at the specified index is valid and its generation matches the specified value; otherwise, false.</returns>
|
/// <returns>true if the slot at the specified index is valid and its generation matches the specified value; otherwise, false.</returns>
|
||||||
public readonly bool Contains(int slotIndex, int generation)
|
public readonly bool Contains(int slotIndex, int generation)
|
||||||
{
|
{
|
||||||
// 0 is reserved for invalid slot
|
if (slotIndex < 0 || slotIndex >= _capacity)
|
||||||
if (slotIndex <= 0 || slotIndex >= _capacity)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
|||||||
private int _nextId; // Next available sparse index
|
private int _nextId; // Next available sparse index
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
|
|
||||||
public readonly int Count => _count - 1;
|
public readonly int Count => _count;
|
||||||
public readonly int Capacity => _capacity;
|
public readonly int Capacity => _capacity;
|
||||||
public readonly bool IsCreated => _dense.IsCreated && _sparse.IsCreated && _reverse.IsCreated;
|
public readonly bool IsCreated => _dense.IsCreated && _sparse.IsCreated && _reverse.IsCreated;
|
||||||
|
|
||||||
@@ -133,8 +133,6 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
_sparse.AsSpan().Fill(-1);
|
_sparse.AsSpan().Fill(-1);
|
||||||
_generations.Clear();
|
_generations.Clear();
|
||||||
|
|
||||||
Add(default, out _); // Make index 0 invalid
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -240,8 +238,7 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly bool Contains(int sparseIndex, int generation)
|
public readonly bool Contains(int sparseIndex, int generation)
|
||||||
{
|
{
|
||||||
// 0 is reserved as invalid index
|
if (sparseIndex < 0 || sparseIndex >= _sparse.Count)
|
||||||
if (sparseIndex <= 0 || sparseIndex >= _sparse.Count)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<Authors>Misaki</Authors>
|
<Authors>Misaki</Authors>
|
||||||
<AssemblyVersion>1.3.2</AssemblyVersion>
|
<AssemblyVersion>1.3.3</AssemblyVersion>
|
||||||
<Version>$(AssemblyVersion)</Version>
|
<Version>$(AssemblyVersion)</Version>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public readonly unsafe struct SharedPtr<T> : IEquatable<SharedPtr<T>>
|
|||||||
/// Ensures that the pointer is not shared and can be safely transferred or detached.
|
/// Ensures that the pointer is not shared and can be safely transferred or detached.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// UniquePtr<T> is designed to encapsulate a raw pointer, enforcing unique ownership semantics similar to C++'s std::unique_ptr.
|
/// <see cref="UniquePtr{T}"/> is designed to encapsulate a raw pointer, enforcing unique ownership semantics similar to C++'s std::unique_ptr.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <typeparam name="T">The unmanaged type of the value to which the pointer refers.</typeparam>
|
/// <typeparam name="T">The unmanaged type of the value to which the pointer refers.</typeparam>
|
||||||
[NonCopyable]
|
[NonCopyable]
|
||||||
@@ -174,3 +174,47 @@ public ref struct Ref<T>
|
|||||||
return !(left == right);
|
return !(left == right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a wrapper for a value type that implements <see cref="IDisposable"/>, ensuring proper disposal of the contained value.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The <see cref="Owner{T}"/> class manages the lifetime of the contained value by calling its
|
||||||
|
/// <see cref="IDisposable.Dispose"/> method when the wrapper is disposed or finalized. After disposal, accessing the value
|
||||||
|
/// will throw an <see cref="ObjectDisposedException"/>.</remarks>
|
||||||
|
/// <typeparam name="T">The value type to wrap. Must be a struct that implements <see cref="IDisposable"/>.</typeparam>
|
||||||
|
public class Owner<T> : IDisposable
|
||||||
|
where T : struct, IDisposable
|
||||||
|
{
|
||||||
|
private T _value;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public Owner(T value)
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Owner()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T Get()
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return ref _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_value.Dispose();
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{
|
{
|
||||||
internal abstract class GeneratorBase
|
internal abstract class GeneratorBase
|
||||||
{
|
{
|
||||||
protected const string INLINE_METHOD_ATTRIBUTE = "[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining | global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]";
|
protected const string INLINE_METHOD_ATTRIBUTE = "[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]";
|
||||||
|
|
||||||
protected static readonly string[] s_matrixComponents = new[] { "c0", "c1", "c2", "c3" };
|
protected static readonly string[] s_matrixComponents = new[] { "c0", "c1", "c2", "c3" };
|
||||||
protected static readonly string[] s_vectorComponents = new[] { "x", "y", "z", "w" };
|
protected static readonly string[] s_vectorComponents = new[] { "x", "y", "z", "w" };
|
||||||
@@ -19,10 +19,9 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
this.typeInfo = typeInfo;
|
this.typeInfo = typeInfo;
|
||||||
sourceBuilder.Clear();
|
sourceBuilder.Clear();
|
||||||
|
|
||||||
var message = Validation();
|
if (!Validation(out var message))
|
||||||
if (message != null)
|
|
||||||
{
|
{
|
||||||
return message;
|
return message ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
@@ -51,9 +50,10 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
#endregion");
|
#endregion");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string? Validation()
|
protected virtual bool Validation(out string? message)
|
||||||
{
|
{
|
||||||
return null;
|
message = null;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Initialize()
|
protected virtual void Initialize()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
||||||
@@ -16,14 +15,16 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
.Replace("{c}", s_matrixComponents[componentIndex]);
|
.Replace("{c}", s_matrixComponents[componentIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string? Validation()
|
protected override bool Validation(out string? message)
|
||||||
{
|
{
|
||||||
if (typeInfo.ElementTypeSymbol == null)
|
if (typeInfo.ElementTypeSymbol == null)
|
||||||
{
|
{
|
||||||
return "You must specify 'elementType' in NumericTypeAttribute for matrix types.";
|
message = "You must specify 'elementType' in NumericTypeAttribute for matrix types.";
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
message = null;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void GenerateBody()
|
protected override void GenerateBody()
|
||||||
@@ -36,7 +37,6 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenerateConstructors();
|
GenerateConstructors();
|
||||||
GenerateUnsafeMethod();
|
|
||||||
GenerateOverrideMethod();
|
GenerateOverrideMethod();
|
||||||
|
|
||||||
if (typeInfo.Arithmetic)
|
if (typeInfo.Arithmetic)
|
||||||
@@ -67,15 +67,20 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
get
|
get
|
||||||
{{
|
{{
|
||||||
#if ENABLE_COLLECTION_CHECKS
|
RangeCheck(index);
|
||||||
if (index < 0 || index >= {typeInfo.Column})
|
|
||||||
{{
|
|
||||||
throw new global::System.ArgumentOutOfRangeException(nameof(index), $""Index {{index}} is out of range of '{typeInfo.TypeName}'"");
|
|
||||||
}}
|
|
||||||
#endif
|
|
||||||
return ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
return ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
||||||
}}
|
}}
|
||||||
}}");
|
}}");
|
||||||
|
|
||||||
|
sourceBuilder.AppendLine($@"
|
||||||
|
[global::System.Diagnostics.Conditional(""ENABLE_COLLECTION_CHECKS"")]
|
||||||
|
private void RangeCheck(int index)
|
||||||
|
{{
|
||||||
|
if (index < 0 || index >= {typeInfo.Column})
|
||||||
|
{{
|
||||||
|
throw new global::System.ArgumentOutOfRangeException(nameof(index), $""Index {{index}} is out of range of '{typeInfo.TypeName}'"");
|
||||||
|
}}
|
||||||
|
}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateUnitMatrix()
|
private void GenerateUnitMatrix()
|
||||||
@@ -213,27 +218,11 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
this.{s_matrixComponents[i]} = {assignment[i]};");
|
this.{s_matrixComponents[i]} = {assignment[i]};");
|
||||||
}
|
}
|
||||||
sourceBuilder.AppendLine($@"
|
sourceBuilder.AppendLine($@"
|
||||||
}}");
|
}}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateUnsafeMethod()
|
|
||||||
{
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public unsafe {typeInfo.ComponentTypeFullName}* AsPointer()
|
|
||||||
{{
|
|
||||||
return ({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this);
|
|
||||||
}}
|
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public unsafe global::System.Span<{typeInfo.ComponentTypeFullName}> AsSpan()
|
|
||||||
{{
|
|
||||||
return new global::System.Span<{typeInfo.ComponentTypeFullName}>(AsPointer(), {typeInfo.Column});
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateOverrideMethod()
|
private void GenerateOverrideMethod()
|
||||||
{
|
{
|
||||||
var components = s_matrixComponents.Take(typeInfo.Column).ToArray();
|
var components = s_matrixComponents.Take(typeInfo.Column).ToArray();
|
||||||
@@ -760,7 +749,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
|
|
||||||
var columnSizeBytes = lhsRows * typeInfo.ComponentSize;
|
var columnSizeBytes = lhsRows * typeInfo.ComponentSize;
|
||||||
var vectorBits = columnSizeBytes > 16 ? 256 : 128;
|
var vectorBits = columnSizeBytes > 16 ? 256 : 128;
|
||||||
bool isFloatingPoint = typeInfo.ElementTypeSymbol!.SpecialType == SpecialType.System_Single||
|
var isFloatingPoint = typeInfo.ElementTypeSymbol!.SpecialType == SpecialType.System_Single ||
|
||||||
typeInfo.ElementTypeSymbol!.SpecialType == SpecialType.System_Double;
|
typeInfo.ElementTypeSymbol!.SpecialType == SpecialType.System_Double;
|
||||||
|
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
@@ -768,7 +757,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
public static {resultVectorType} mul({lhsType} m, {rhsVectorType} v)
|
public static {resultVectorType} mul({lhsType} m, {rhsVectorType} v)
|
||||||
{{");
|
{{");
|
||||||
|
|
||||||
for (int i = 0; i < lhsCols; i++)
|
for (var i = 0; i < lhsCols; i++)
|
||||||
{
|
{
|
||||||
var component = s_vectorComponents[i];
|
var component = s_vectorComponents[i];
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
@@ -779,7 +768,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
|
|
||||||
var sum = global::System.Runtime.Intrinsics.Vector{vectorBits}.Multiply(m.c0.AsVector{vectorBits}(), vx);");
|
var sum = global::System.Runtime.Intrinsics.Vector{vectorBits}.Multiply(m.c0.AsVector{vectorBits}(), vx);");
|
||||||
|
|
||||||
for (int i = 1; i < lhsCols; i++)
|
for (var i = 1; i < lhsCols; i++)
|
||||||
{
|
{
|
||||||
var component = s_vectorComponents[i];
|
var component = s_vectorComponents[i];
|
||||||
var col = s_matrixComponents[i];
|
var col = s_matrixComponents[i];
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenerateConstructors();
|
GenerateConstructors();
|
||||||
GenerateUnsafeMethod();
|
|
||||||
GenerateOverrideMethod();
|
GenerateOverrideMethod();
|
||||||
GenerateConvertionMethod();
|
GenerateConvertionMethod();
|
||||||
|
|
||||||
@@ -95,15 +94,20 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
get
|
get
|
||||||
{{
|
{{
|
||||||
#if ENABLE_COLLECTION_CHECKS
|
RangeCheck(index);
|
||||||
if (index < 0 || index >= {typeInfo.Row})
|
|
||||||
{{
|
|
||||||
throw new global::System.ArgumentOutOfRangeException(nameof(index), $""Index {{index}} is out of range of '{typeInfo.TypeName}'"");
|
|
||||||
}}
|
|
||||||
#endif
|
|
||||||
return ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
return ref (({typeInfo.ComponentTypeFullName}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this))[index];
|
||||||
}}
|
}}
|
||||||
}}");
|
}}");
|
||||||
|
|
||||||
|
sourceBuilder.AppendLine($@"
|
||||||
|
[global::System.Diagnostics.Conditional(""ENABLE_COLLECTION_CHECKS"")]
|
||||||
|
private void RangeCheck(int index)
|
||||||
|
{{
|
||||||
|
if (index < 0 || index >= {typeInfo.Row})
|
||||||
|
{{
|
||||||
|
throw new global::System.ArgumentOutOfRangeException(nameof(index), $""Index {{index}} is out of range of '{typeInfo.TypeName}'"");
|
||||||
|
}}
|
||||||
|
}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<List<int>> GetPartitions(int target)
|
private static List<List<int>> GetPartitions(int target)
|
||||||
@@ -295,28 +299,10 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
EndRegion();
|
EndRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateUnsafeMethod()
|
|
||||||
{
|
|
||||||
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
||||||
|
|
||||||
StartRegion("Unsafe Methods");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public unsafe {componentType}* AsPointer()
|
|
||||||
{{
|
|
||||||
return ({componentType}*)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref this);
|
|
||||||
}}
|
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public unsafe global::System.Span<{componentType}> AsSpan()
|
|
||||||
{{
|
|
||||||
return new global::System.Span<{componentType}>(AsPointer(), {typeInfo.Row});
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateOverrideMethod()
|
private void GenerateOverrideMethod()
|
||||||
{
|
{
|
||||||
|
StartRegion("Override Methods");
|
||||||
|
|
||||||
var typeName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
var typeName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||||
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||||
var components = s_vectorComponents.Take(typeInfo.Row).ToArray();
|
var components = s_vectorComponents.Take(typeInfo.Row).ToArray();
|
||||||
@@ -715,6 +701,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
var modifier = canSet ? "public" : "public readonly";
|
var modifier = canSet ? "public" : "public readonly";
|
||||||
|
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
|
[global::System.Text.Json.Serialization.JsonIgnore]
|
||||||
{modifier} {targetStruct} {property}
|
{modifier} {targetStruct} {property}
|
||||||
{{
|
{{
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<Authors>Misaki</Authors>
|
<Authors>Misaki</Authors>
|
||||||
<AssemblyVersion>1.3.0</AssemblyVersion>
|
<AssemblyVersion>1.3.1</AssemblyVersion>
|
||||||
<Version>$(AssemblyVersion)</Version>
|
<Version>$(AssemblyVersion)</Version>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
||||||
|
|||||||
@@ -2,58 +2,18 @@
|
|||||||
|
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Test.Jobs;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.Intrinsics;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||||
|
|
||||||
public unsafe class MathematicsBenchmark
|
public class MathematicsBenchmark
|
||||||
{
|
{
|
||||||
public struct f2
|
|
||||||
{
|
|
||||||
public float x;
|
|
||||||
public float y;
|
|
||||||
|
|
||||||
public f2(float x, float y)
|
|
||||||
{
|
|
||||||
//this = Asf2(Vector128.Create(x, y, 0, 0));
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Vector128<float> AsVector128Unsafe(f2 value)
|
|
||||||
{
|
|
||||||
return Vector128.Create(value.x, value.y, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static f2 Asf2(Vector128<float> value)
|
|
||||||
{
|
|
||||||
//f2 result;
|
|
||||||
//result.x = value.GetElement(0);
|
|
||||||
//result.y = value.GetElement(1);
|
|
||||||
//return result;
|
|
||||||
|
|
||||||
ref byte address = ref Unsafe.As<Vector128<float>, byte>(ref value);
|
|
||||||
return Unsafe.ReadUnaligned<f2>(ref address);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static f2 operator +(f2 lhs, f2 rhs)
|
|
||||||
{
|
|
||||||
//return Asf2(AsVector128Unsafe(lhs) + AsVector128Unsafe(rhs));
|
|
||||||
return new f2(lhs.x + rhs.x, lhs.y + rhs.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if VECTOR_BENCHMARK
|
#if VECTOR_BENCHMARK
|
||||||
private Vector2 _v2a = new Vector2(1, 2);
|
private Vector2 _v2a = new Vector2(1, 2);
|
||||||
private Vector2 _v2b = new Vector2(3, 4);
|
private Vector2 _v2b = new Vector2(3, 4);
|
||||||
|
|
||||||
private f2 _f2a = new f2(1, 2);
|
private float2 _f2a = new float2(1, 2);
|
||||||
private f2 _f2b = new f2(3, 4);
|
private float2 _f2b = new float2(3, 4);
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public Vector2 VectorAdd()
|
public Vector2 VectorAdd()
|
||||||
@@ -69,9 +29,9 @@ public unsafe class MathematicsBenchmark
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public f2 f2Add()
|
public float2 float2Add()
|
||||||
{
|
{
|
||||||
var v = new f2(0, 0);
|
var v = new float2(0, 0);
|
||||||
|
|
||||||
for (var i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class ParallelNoiseBenchmark
|
|||||||
height = _HEIGHT
|
height = _HEIGHT
|
||||||
};
|
};
|
||||||
|
|
||||||
var handle = _jobScheduler.ScheduleParallel(ref job, _LENGTH, 64, -1);
|
var handle = _jobScheduler.ScheduleParallel(ref job, _LENGTH, 64, -1, JobHandle.Invalid);
|
||||||
_jobScheduler.WaitComplete(handle);
|
_jobScheduler.WaitComplete(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DefineConstants>$(DefineConstants);ENABLE_COLLECTION_CHECKS</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" />
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,6 @@
|
|||||||
//var threadCount = 8;
|
using Misaki.HighPerformance.Image;
|
||||||
//var map = new ConcurrentSlotMap<int>();
|
|
||||||
|
|
||||||
//var barrier = new Barrier(threadCount);
|
//BenchmarkDotNet.Running.BenchmarkRunner.Run<Misaki.HighPerformance.Test.Benchmark.ParallelNoiseBenchmark>();
|
||||||
|
|
||||||
//Parallel.For(0, threadCount, threadIndex =>
|
|
||||||
//{
|
|
||||||
// barrier.SignalAndWait();
|
|
||||||
// for (var i = 0; i < 1000; i++)
|
|
||||||
// {
|
|
||||||
// var id = map.Add(i + threadIndex * 1000, out var gen);
|
|
||||||
// if (i % 100 == 0)
|
|
||||||
// {
|
|
||||||
// map.Remove(id, gen);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//});
|
|
||||||
|
|
||||||
//Console.WriteLine($"Count should be {threadCount * 990}, actual: {map.Count}");
|
|
||||||
|
|
||||||
//using Misaki.HighPerformance.LowLevel;
|
|
||||||
|
|
||||||
using System.Runtime.Intrinsics;
|
|
||||||
|
|
||||||
BenchmarkDotNet.Running.BenchmarkRunner.Run<Misaki.HighPerformance.Test.Benchmark.MathematicsBenchmark>();
|
|
||||||
|
|
||||||
//using Misaki.HighPerformance.Collections;
|
//using Misaki.HighPerformance.Collections;
|
||||||
//using Misaki.HighPerformance.LowLevel.Buffer;
|
//using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
@@ -59,3 +37,12 @@ BenchmarkDotNet.Running.BenchmarkRunner.Run<Misaki.HighPerformance.Test.Benchmar
|
|||||||
// 8, 7, 6, 5,
|
// 8, 7, 6, 5,
|
||||||
// 4, 3, 2, 1);
|
// 4, 3, 2, 1);
|
||||||
//Console.WriteLine(Matrix4x4.Multiply(ma, mb));
|
//Console.WriteLine(Matrix4x4.Multiply(ma, mb));
|
||||||
|
|
||||||
|
|
||||||
|
const string _IMAGE_PATH = "C:/Users/Misaki/Downloads/Im/119683453_p2.jpg";
|
||||||
|
|
||||||
|
using var stream = File.OpenRead(_IMAGE_PATH);
|
||||||
|
var imageInfo = ImageInfo.FromStream(stream);
|
||||||
|
using var image = ImageResult.FromStream(stream);
|
||||||
|
|
||||||
|
Console.WriteLine($"{imageInfo.Width}x{imageInfo.Height} {imageInfo.ColorComponents}");
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Buffer
|
namespace Misaki.HighPerformance.Buffer
|
||||||
{
|
{
|
||||||
public class ObjectPool<T> : IDisposable where T : class
|
public class ObjectPool<T> : IDisposable
|
||||||
|
where T : class
|
||||||
{
|
{
|
||||||
private readonly Func<T> _factory;
|
private readonly Func<T> _factory;
|
||||||
private readonly ConcurrentQueue<T> _objects = new();
|
private readonly ConcurrentQueue<T> _pool = new();
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -18,7 +19,6 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
public uint MaxSize
|
public uint MaxSize
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectPool(Func<T> factory, uint initialSize = uint.MinValue, uint maxSize = uint.MaxValue)
|
public ObjectPool(Func<T> factory, uint initialSize = uint.MinValue, uint maxSize = uint.MaxValue)
|
||||||
@@ -32,7 +32,7 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
{
|
{
|
||||||
for (var i = 0; i < initialSize; i++)
|
for (var i = 0; i < initialSize; i++)
|
||||||
{
|
{
|
||||||
_objects.Enqueue(_factory());
|
_pool.Enqueue(_factory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,21 +45,24 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
public T Rent()
|
public T Rent()
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
if (_objects.TryDequeue(out var obj))
|
if (_pool.TryDequeue(out var obj))
|
||||||
{
|
{
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _factory();
|
var newInstance = _factory();
|
||||||
|
_pool.Enqueue(newInstance);
|
||||||
|
|
||||||
|
return newInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryRent([MaybeNullWhen(false)] out T obj)
|
public bool TryRent([MaybeNullWhen(false)] out T obj)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (!_objects.IsEmpty)
|
if (_pool.TryDequeue(out obj))
|
||||||
{
|
{
|
||||||
return _objects.TryDequeue(out obj);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = null;
|
obj = null;
|
||||||
@@ -70,15 +73,15 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
if (_objects.Count < MaxSize)
|
if (_pool.Count < MaxSize)
|
||||||
{
|
{
|
||||||
_objects.Enqueue(obj);
|
_pool.Enqueue(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
foreach (var obj in _objects)
|
foreach (var obj in _pool)
|
||||||
{
|
{
|
||||||
if (obj is IDisposable disposable)
|
if (obj is IDisposable disposable)
|
||||||
{
|
{
|
||||||
@@ -86,7 +89,7 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_objects.Clear();
|
_pool.Clear();
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class ConcurrentSlotMap<T> : IEnumerable<T>
|
|||||||
// For lock-free resizing
|
// For lock-free resizing
|
||||||
private int _isResizing;
|
private int _isResizing;
|
||||||
|
|
||||||
public int Count => Volatile.Read(ref _count) - 1;
|
public int Count => Volatile.Read(ref _count);
|
||||||
public int Capacity => Volatile.Read(ref _capacity);
|
public int Capacity => Volatile.Read(ref _capacity);
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator(this);
|
public IEnumerator<T> GetEnumerator() => new Enumerator(this);
|
||||||
@@ -75,8 +75,6 @@ public class ConcurrentSlotMap<T> : IEnumerable<T>
|
|||||||
|
|
||||||
_data = new SlotEntry[initialCapacity];
|
_data = new SlotEntry[initialCapacity];
|
||||||
_freeSlots = new();
|
_freeSlots = new();
|
||||||
|
|
||||||
Add(default!, out _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
@@ -211,7 +209,7 @@ public class ConcurrentSlotMap<T> : IEnumerable<T>
|
|||||||
|
|
||||||
public bool Contains(int slotIndex, int generation)
|
public bool Contains(int slotIndex, int generation)
|
||||||
{
|
{
|
||||||
if (slotIndex <= 0 || slotIndex >= Volatile.Read(ref _capacity))
|
if (slotIndex < 0 || slotIndex >= Volatile.Read(ref _capacity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ public class SlotMap<T> : IEnumerable<T>
|
|||||||
_generations = new int[initialCapacity];
|
_generations = new int[initialCapacity];
|
||||||
_isOccupiedBits = new BitArray(initialCapacity);
|
_isOccupiedBits = new BitArray(initialCapacity);
|
||||||
_freeSlots = new(initialCapacity);
|
_freeSlots = new(initialCapacity);
|
||||||
|
|
||||||
Add(default!, out _);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Resize()
|
private void Resize()
|
||||||
@@ -108,7 +106,7 @@ public class SlotMap<T> : IEnumerable<T>
|
|||||||
|
|
||||||
public bool Contains(int slotIndex, int generation)
|
public bool Contains(int slotIndex, int generation)
|
||||||
{
|
{
|
||||||
if (slotIndex <= 0 || slotIndex >= Volatile.Read(ref _capacity))
|
if (slotIndex < 0 || slotIndex >= Volatile.Read(ref _capacity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class SparseSet<T> : IEnumerable<T>
|
|||||||
private int _nextId; // Next available sparse index
|
private int _nextId; // Next available sparse index
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
|
|
||||||
public int Count => _count - 1;
|
public int Count => _count;
|
||||||
public int Capacity => _capacity;
|
public int Capacity => _capacity;
|
||||||
|
|
||||||
public Enumerator GetEnumerator() => new(this);
|
public Enumerator GetEnumerator() => new(this);
|
||||||
@@ -83,8 +83,6 @@ public class SparseSet<T> : IEnumerable<T>
|
|||||||
_count = 0;
|
_count = 0;
|
||||||
_nextId = 0;
|
_nextId = 0;
|
||||||
_capacity = capacity;
|
_capacity = capacity;
|
||||||
|
|
||||||
Add(default!, out _); // Reserve index 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -178,7 +176,7 @@ public class SparseSet<T> : IEnumerable<T>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Contains(int sparseIndex, int generation)
|
public bool Contains(int sparseIndex, int generation)
|
||||||
{
|
{
|
||||||
if (sparseIndex <= 0 || sparseIndex >= _sparse.Length)
|
if (sparseIndex < 0 || sparseIndex >= _sparse.Length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
<Authors>Misaki</Authors>
|
<Authors>Misaki</Authors>
|
||||||
<AssemblyVersion>1.0.2</AssemblyVersion>
|
<AssemblyVersion>1.0.3</AssemblyVersion>
|
||||||
<Version>$(AssemblyVersion)</Version>
|
<Version>$(AssemblyVersion)</Version>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ public static class CollectionUtility
|
|||||||
/// <typeparam name="T">The type of elements in the list.</typeparam>
|
/// <typeparam name="T">The type of elements in the list.</typeparam>
|
||||||
/// <param name="list">The list from which to remove the element. Cannot be null.</param>
|
/// <param name="list">The list from which to remove the element. Cannot be null.</param>
|
||||||
/// <param name="index">The zero-based index of the element to remove. Must be within the bounds of the list.</param>
|
/// <param name="index">The zero-based index of the element to remove. Must be within the bounds of the list.</param>
|
||||||
/// <returns>The modified list after the element has been removed.</returns>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Thrown if index is less than 0 or greater than or equal to the number of elements in the list.</exception>
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if index is less than 0 or greater than or equal to the number of elements in the list.</exception>
|
||||||
public static List<T> RemoveAndSwapBack<T>(this List<T> list, int index)
|
/// <returns>True if the element was successfully removed; otherwise, false.</returns>
|
||||||
|
public static bool RemoveAndSwapBack<T>(this List<T> list, int index)
|
||||||
{
|
{
|
||||||
var lastIndex = list.Count - 1;
|
var lastIndex = list.Count - 1;
|
||||||
if (index < 0 || index > lastIndex)
|
if (index < 0 || index > lastIndex)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != lastIndex)
|
if (index != lastIndex)
|
||||||
@@ -41,6 +41,6 @@ public static class CollectionUtility
|
|||||||
}
|
}
|
||||||
|
|
||||||
list.RemoveAt(lastIndex);
|
list.RemoveAt(lastIndex);
|
||||||
return list;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user