feat(nativegen)!: refactor to struct-based native wrappers

Major overhaul of native wrapper generation for ufbx and nvtt.
Replaces all hand-written and class-based wrappers with auto-generated partial struct wrappers that directly expose native API methods via pointers. Introduces a new JSON-driven configuration system using "remaps" and "actions" for flexible parameter/return mapping and method routing. Removes legacy config sections and helper classes, focusing solely on method wrappers. Updates all usages and tests to use the new pointer-based API. Cleans up obsolete code and ensures resource management is handled via struct Dispose methods. The result is a thinner, more direct, and maintainable interop layer.

BREAKING CHANGE: All managed wrapper classes and helpers are removed in favor of struct-based pointer wrappers. API usage and resource management patterns have changed.
This commit is contained in:
2026-03-15 20:48:54 +09:00
parent 3e4084c42a
commit 6cadd8edeb
278 changed files with 5387 additions and 12057 deletions

View File

@@ -284,7 +284,6 @@ internal class TextureAssetHandler : IImportableAssetHandler
public async ValueTask<Result> ImportAsync(Stream sourceStream, Stream targetStream, Guid id, CancellationToken token = default)
{
// ---- 1. Probe image info -----------------------------------------------
var info = ImageInfo.FromStream(sourceStream);
if (info.BitsPerChannel <= 0)
{
@@ -296,93 +295,94 @@ internal class TextureAssetHandler : IImportableAssetHandler
var height = info.Height;
var colorComponents = info.ColorComponents;
// ---- 2. Decode pixels into a managed byte[] ----------------------------
byte[] pixelBytes;
if (isFloat)
{
using var image = ImageResultFloat.FromStream(sourceStream, colorComponents);
var span = MemoryMarshal.AsBytes(image.AsSpan());
pixelBytes = new byte[span.Length];
pixelBytes = ArrayPool<byte>.Shared.Rent(span.Length);
span.CopyTo(pixelBytes);
}
else
{
using var image = ImageResult.FromStream(sourceStream, colorComponents);
var span = MemoryMarshal.AsBytes(image.AsSpan());
pixelBytes = new byte[span.Length];
var span = image.AsSpan();
pixelBytes = ArrayPool<byte>.Shared.Rent(span.Length);
span.CopyTo(pixelBytes);
}
// ---- 3. Run NVTT compression on a thread-pool thread (side-effect only) -
// The cache path is derivable at any time from (id, settingsHash), so we
// do NOT store it in the asset file. LoadAsync/SaveAsync will recompute it.
var settings = new TextureAssetSettings();
await Task.Run(() =>
TextureProcessor.CompressToCache(
EditorApplication.CachesFolderPath,
id,
pixelBytes,
width,
height,
isFloat,
colorComponents,
settings),
token).ConfigureAwait(false);
// ---- 4. Write asset file: header + settings + raw image data -----------
var header = new AssetMetadata(id, TextureAsset.s_typeGuid)
{
HandlerVersion = _CURRENT_VERSION,
SettingsOffset = AssetMetadata.SIZE,
};
targetStream.Seek(header.SettingsOffset, SeekOrigin.Begin);
var sizeResult = await WriteSettingsToStreamAsync(settings, targetStream, token).ConfigureAwait(false);
if (sizeResult.IsFailure)
{
return Result.Failure($"Failed to write texture asset settings: {sizeResult.Message}");
}
// Content layout (all little-endian):
// int32 width
// int32 height
// byte isFloat (0 = byte, 1 = float)
// int32 colorComponents (cast of ColorComponents enum)
// byte[] pixelBytes
const int _CONTENT_HEADER_SIZE = 4 + 4 + 1 + 4; // 13 bytes
header.SettingsSize = sizeResult.Value;
header.ContentOffset = header.SettingsOffset + sizeResult.Value;
header.ContentSize = _CONTENT_HEADER_SIZE + pixelBytes.Length;
// Write raw image content
targetStream.Seek(header.ContentOffset, SeekOrigin.Begin);
var contentHeader = ArrayPool<byte>.Shared.Rent(_CONTENT_HEADER_SIZE);
try
{
BitConverter.TryWriteBytes(contentHeader.AsSpan(0, 4), width);
BitConverter.TryWriteBytes(contentHeader.AsSpan(4, 4), height);
contentHeader[8] = isFloat ? (byte)1 : (byte)0;
BitConverter.TryWriteBytes(contentHeader.AsSpan(9, 4), (int)colorComponents);
var settings = new TextureAssetSettings();
await Task.Run(() =>
TextureProcessor.CompressToCache(
EditorApplication.CachesFolderPath,
id,
pixelBytes,
width,
height,
isFloat,
colorComponents,
settings),
token).ConfigureAwait(false);
await targetStream.WriteAsync(contentHeader.AsMemory(0, _CONTENT_HEADER_SIZE), token).ConfigureAwait(false);
var header = new AssetMetadata(id, TextureAsset.s_typeGuid)
{
HandlerVersion = _CURRENT_VERSION,
SettingsOffset = AssetMetadata.SIZE,
};
targetStream.Seek(header.SettingsOffset, SeekOrigin.Begin);
var sizeResult = await WriteSettingsToStreamAsync(settings, targetStream, token).ConfigureAwait(false);
if (sizeResult.IsFailure)
{
return Result.Failure($"Failed to write texture asset settings: {sizeResult.Message}");
}
// Content layout (all little-endian):
// int32 width
// int32 height
// byte isFloat (0 = byte, 1 = float)
// int32 colorComponents (cast of ColorComponents enum)
// byte[] pixelBytes
const int _CONTENT_HEADER_SIZE = 4 + 4 + 1 + 4; // 13 bytes
header.SettingsSize = sizeResult.Value;
header.ContentOffset = header.SettingsOffset + sizeResult.Value;
header.ContentSize = _CONTENT_HEADER_SIZE + pixelBytes.Length;
// Write raw image content
targetStream.Seek(header.ContentOffset, SeekOrigin.Begin);
var contentHeader = ArrayPool<byte>.Shared.Rent(_CONTENT_HEADER_SIZE);
try
{
BitConverter.TryWriteBytes(contentHeader.AsSpan(0, 4), width);
BitConverter.TryWriteBytes(contentHeader.AsSpan(4, 4), height);
contentHeader[8] = isFloat ? (byte)1 : (byte)0;
BitConverter.TryWriteBytes(contentHeader.AsSpan(9, 4), (int)colorComponents);
await targetStream.WriteAsync(contentHeader.AsMemory(0, _CONTENT_HEADER_SIZE), token).ConfigureAwait(false);
}
finally
{
ArrayPool<byte>.Shared.Return(contentHeader);
}
await targetStream.WriteAsync(pixelBytes, token).ConfigureAwait(false);
await targetStream.FlushAsync(token).ConfigureAwait(false);
// Patch header now that all sizes are known
targetStream.Seek(0, SeekOrigin.Begin);
AssetMetadata.WriteToStream(targetStream, ref header);
return Result.Success();
}
finally
{
ArrayPool<byte>.Shared.Return(contentHeader);
ArrayPool<byte>.Shared.Return(pixelBytes);
}
await targetStream.WriteAsync(pixelBytes, token).ConfigureAwait(false);
await targetStream.FlushAsync(token).ConfigureAwait(false);
// Patch header now that all sizes are known
targetStream.Seek(0, SeekOrigin.Begin);
AssetMetadata.WriteToStream(targetStream, ref header);
return Result.Success();
}
public ValueTask<Result<Asset>> LoadAsync(Stream sourceStream, IAssetRegistry assetRegistry, CancellationToken token = default)

View File

@@ -1,9 +1,10 @@
using Ghost.Nvtt;
using Ghost.Nvtt.Wrapper;
using Misaki.HighPerformance.Image;
using Misaki.HighPerformance.LowLevel;
using System.IO.Hashing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Ghost.Editor.Core.AssetHandler;
@@ -39,7 +40,6 @@ internal static unsafe class TextureProcessor
ColorComponents colorComponents,
TextureAssetSettings settings)
{
// --- derive cache path --------------------------------------------------
var cacheDir = Path.Combine(cachesFolderPath, _TEXTURE_CACHE_SUBFOLDER);
Directory.CreateDirectory(cacheDir);
@@ -47,19 +47,16 @@ internal static unsafe class TextureProcessor
var cacheFileName = $"{assetId:N}_{settingsHash:X16}.dds";
var cachePath = Path.Combine(cacheDir, cacheFileName);
// --- check validity: same file name = same settings hash = already done -
if (File.Exists(cachePath))
{
return cachePath;
}
// --- delete any stale cache entries for this asset ----------------------
foreach (var stale in Directory.EnumerateFiles(cacheDir, $"{assetId:N}_*.dds"))
{
File.Delete(stale);
}
// --- run NVTT pipeline --------------------------------------------------
RunNvttPipeline(cachePath, pixelData, width, height, isFloat, colorComponents, settings);
return cachePath;
@@ -74,84 +71,75 @@ internal static unsafe class TextureProcessor
ColorComponents colorComponents,
TextureAssetSettings settings)
{
using var surface = new NvttSurfaceHandle();
using var compOpts = new NvttCompressionOptionsHandle();
using var outOpts = new NvttOutputOptionsHandle();
using var ctx = new NvttContextHandle();
using var pSurface = new DisposablePtr<NvttSurface>(NvttSurface.Create());
using var pCompOpts = new DisposablePtr<NvttCompressionOptions>(NvttCompressionOptions.Create());
using var pOutOpts = new DisposablePtr<NvttOutputOptions>(NvttOutputOptions.Create());
using var pCtx = new DisposablePtr<NvttContext>(NvttContext.Create());
// ---- 1. load pixels into NVTT -----------------------------------------
// Misaki.HighPerformance.Image always decodes to RGBA channel order.
// Float images → RGBA_32F, byte images → BGRA_8UB.
// NOTE: NVTT BGRA_8UB expects Blue in byte[0]; stb decodes RGBA so we need
// to pass RGBA. There is no RGBA_8UB enum — we swizzle after load instead.
var inputFormat = isFloat
? NvttInputFormat.NVTT_InputFormat_RGBA_32F
: NvttInputFormat.NVTT_InputFormat_BGRA_8UB; // we'll swizzle RB below
surface.SetImageData(inputFormat, width, height, 1, pixelData);
fixed (void* pData = pixelData)
{
pSurface.Get()->SetImageData(inputFormat, width, height, 1, pData, NvttBoolean.NVTT_True, null);
}
// stb gives us RGBA byte order; NVTT BGRA_8UB reads it as BGRA,
// so channels R and B are swapped — fix with swizzle(2,1,0,3).
if (!isFloat)
{
surface.Swizzle(2, 1, 0, 3);
pSurface.Get()->Swizzle(2, 1, 0, 3, null);
}
// ---- 2. resize ---------------------------------------------------------
var maxExtent = (int)settings.Sampler.MaxSize;
if (settings.Advanced.StretchToPowerOfTwo)
{
surface.ResizeMakeSquare(maxExtent,
pSurface.Get()->ResizeMakeSquare(maxExtent,
NvttRoundMode.NVTT_RoundMode_ToNearestPowerOfTwo,
NvttResizeFilter.NVTT_ResizeFilter_Box);
NvttResizeFilter.NVTT_ResizeFilter_Box, null);
}
else if (surface.Width > maxExtent || surface.Height > maxExtent)
else if (pSurface.Get()->Width() > maxExtent || pSurface.Get()->Height() > maxExtent)
{
surface.ResizeMax(maxExtent,
pSurface.Get()->ResizeMax(maxExtent,
NvttRoundMode.NVTT_RoundMode_None,
NvttResizeFilter.NVTT_ResizeFilter_Box);
NvttResizeFilter.NVTT_ResizeFilter_Box, null);
}
// ---- 2b. border color --------------------------------------------------
if (settings.Advanced.UseBorderColor)
{
var c = settings.Advanced.BorderColor;
surface.SetBorder(c.r, c.g, c.b, c.a);
pSurface.Get()->SetBorder(c.r, c.g, c.b, c.a, null);
}
else if (settings.Advanced.ZeroAlphaBorder)
{
surface.SetBorder(0f, 0f, 0f, 0f);
pSurface.Get()->SetBorder(0f, 0f, 0f, 0f, null);
}
// ---- 3. colour-space: convert to linear before mip filtering -----------
if (settings.Basic.IsSRGB && settings.Advanced.GammaCorrection)
{
surface.ToLinearFromSrgb();
pSurface.Get()->ToLinearFromSrgb(null);
}
// ---- 4. premultiply alpha (before mip chain) ---------------------------
if (settings.Advanced.PremultiplyAlpha)
{
surface.PremultiplyAlpha();
pSurface.Get()->PremultiplyAlpha(null);
}
// ---- 5. configure compression options ----------------------------------
compOpts.Format = SelectFormat(settings);
compOpts.Quality = SelectQuality(settings.Advanced.CompressionLevel);
pCompOpts.Get()->SetFormat(SelectFormat(settings));
pCompOpts.Get()->SetQuality(SelectQuality(settings.Advanced.CompressionLevel));
if (settings.Advanced.CutoutAlpha)
{
compOpts.SetQuantization(false, false, true,
pCompOpts.Get()->SetQuantization(false, false, true,
settings.Advanced.CutoutAlphaThreshold);
}
// ---- 6. configure output options ---------------------------------------
outOpts.OutputHeader = true;
outOpts.Srgb = settings.Basic.IsSRGB;
outOpts.Container = NvttContainer.NVTT_Container_DDS10;
outOpts.FileName = outputPath;
pOutOpts.Get()->SetOutputHeader(true);
pOutOpts.Get()->SetSrgbFlag(settings.Basic.IsSRGB);
pOutOpts.Get()->SetContainer(NvttContainer.NVTT_Container_DDS10);
pOutOpts.Get()->SetFileName(Encoding.UTF8.GetBytes(outputPath));
// ---- 7. mipmap count ---------------------------------------------------
var nvttFilter = SelectMipmapFilter(settings.Advanced.MipmapFilter);
int mipmapCount;
@@ -161,38 +149,35 @@ internal static unsafe class TextureProcessor
}
else if (settings.Advanced.MipmapLevelCount == 0)
{
mipmapCount = surface.CountMipmaps();
mipmapCount = pSurface.Get()->CountMipmaps(1);
}
else
{
mipmapCount = (int)settings.Advanced.MipmapLevelCount;
}
// ---- 8. enable CUDA if available ---------------------------------------
ctx.SetCudaAcceleration(NvttGlobal.IsCudaSupported);
pCtx.Get()->SetCudaAcceleration(Api.nvttIsCudaSupported());
// ---- 9. write DDS header -----------------------------------------------
ctx.OutputHeader(surface, mipmapCount, compOpts, outOpts);
pCtx.Get()->OutputHeader(pSurface.Get(), mipmapCount, pCompOpts.Get(), pOutOpts.Get());
// ---- 10. compress mip chain using a working clone ----------------------
using var mip = surface.Clone();
using var pMip = new DisposablePtr<NvttSurface>(pSurface.Get()->Clone());
for (var level = 0; level < mipmapCount; level++)
{
// Scale alpha for coverage on each mip (if requested)
// Scale alpha for coverage on each pMip (if requested)
if (settings.Advanced.ScaleAlphaForMipCoverage && level > 0)
{
var refCoverage = mip.AlphaTestCoverage(
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f);
mip.ScaleAlphaToCoverage(refCoverage,
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f);
var refCoverage = pMip.Get()->AlphaTestCoverage(
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f, 3);
pMip.Get()->ScaleAlphaToCoverage(refCoverage,
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f, 3, null);
}
ctx.Compress(mip, 0, level, compOpts, outOpts);
pCtx.Get()->Compress(pMip.Get(), 0, level, pCompOpts.Get(), pOutOpts.Get());
if (level + 1 < mipmapCount)
{
mip.BuildNextMipmap(nvttFilter);
pMip.Get()->BuildNextMipmapDefaults(nvttFilter, 1, null);
}
}
}
@@ -203,7 +188,7 @@ internal static unsafe class TextureProcessor
TextureType.Normal => NvttFormat.NVTT_Format_BC5, // RG normal map
TextureType.SingleChannel => NvttFormat.NVTT_Format_BC4, // single channel
TextureType.Lightmap => NvttFormat.NVTT_Format_BC6U, // HDR lightmap (unsigned)
_ => NvttFormat.NVTT_Format_BC7, // default colour
_ => NvttFormat.NVTT_Format_BC7, // default color
};
private static NvttQuality SelectQuality(TextureCompressionLevel level)

View File

@@ -22,12 +22,12 @@
<ItemGroup>
<PackageReference Include="Misaki.HighPerformance" Version="1.0.4" />
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.5.1" />
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.4.3">
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.4.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.3.1" />
<PackageReference Include="System.IO.Hashing" Version="10.0.3" />
<PackageReference Include="System.IO.Hashing" Version="10.0.5" />
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.6" />
</ItemGroup>

View File

@@ -22,7 +22,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Misaki.HighPerformance.Image" Version="1.1.0" />
<PackageReference Include="Misaki.HighPerformance.Image" Version="1.1.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,6 +1,8 @@
using Ghost.Nvtt;
using Ghost.Nvtt.Wrapper;
using Ghost.Test.Core;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Ghost.MicroTest;
@@ -14,7 +16,7 @@ namespace Ghost.MicroTest;
/// 4. sRGB conversion — converts to linear colour space.
/// 5. Mipmap count — verifies CountMipmaps() returns a sensible value.
/// 6. Compression — compresses to BC7 with in-memory output.
/// 7. Mip chain — generates and compresses the full mip chain.
/// 7. Mip chain — generates and compresses the full pMip chain.
/// 8. Error callback — installs a global message callback and verifies
/// it doesn't crash.
/// 9. Output to file — re-runs the full pipeline writing a real .dds file
@@ -23,6 +25,7 @@ namespace Ghost.MicroTest;
internal sealed unsafe class NvttBindingTest : ITest
{
private const string _IMAGE_PATH = @"C:/Users/Misaki/Downloads/Screenshot 2024-07-20 035047.png";
private static ReadOnlySpan<byte> ImagePathByte => @"C:/Users/Misaki/Downloads/Screenshot 2024-07-20 035047.png"u8;
private string _outputDdsPath = string.Empty;
@@ -38,26 +41,20 @@ internal sealed unsafe class NvttBindingTest : ITest
{
// ---- Test 1: Version ---------------------------------------------------
Console.Write("[Test 1] nvttVersion ... ");
var version = NvttGlobal.Version;
var version = Api.nvttVersion();
Assert(version > 0, $"Expected version > 0, got {version}");
Console.WriteLine($"OK (version = {version >> 16}.{(version >> 8) & 0xFF}.{version & 0xFF})");
// ---- Test 2: CUDA support query (must not crash) ----------------------
Console.Write("[Test 2] IsCudaSupported ... ");
var cuda = NvttGlobal.IsCudaSupported;
var cuda = Api.nvttIsCudaSupported();
Console.WriteLine($"OK (cuda = {cuda})");
// ---- Test 3: Global message callback ----------------------------------
Console.Write("[Test 3] SetMessageCallback ... ");
var callbackFired = 0;
using (var token = NvttGlobal.SetMessageCallback((severity, error, msg) =>
{
callbackFired++;
Console.WriteLine($"/n [NVTT] [{severity}] {error}: {msg}");
}))
{
// Just install + dispose — no assertion needed; must not throw.
}
var token = Api.nvttSetMessageCallback(&CallBack, &callbackFired);
Console.WriteLine($"OK (no crash, callback fired {callbackFired} times during install)");
// ---- Test 4: Surface creation + load ----------------------------------
@@ -65,81 +62,92 @@ internal sealed unsafe class NvttBindingTest : ITest
Assert(File.Exists(_IMAGE_PATH),
$"Image not found: '{_IMAGE_PATH}'. Edit _IMAGE_PATH before running.");
using var surface = new NvttSurfaceHandle();
var loaded = surface.Load(_IMAGE_PATH, out var hasAlpha);
var pSurface = NvttSurface.Create();
NvttBoolean hasAlpha;
var loaded = pSurface->Load(ImagePathByte, &hasAlpha, false, null);
Assert(loaded, "nvttSurfaceLoad returned false");
Assert(!surface.IsNull, "Surface is null after load");
Assert(surface.Width > 0 && surface.Height > 0,
$"Bad dimensions after load: {surface.Width}x{surface.Height}");
Console.WriteLine($"OK ({surface.Width}x{surface.Height}, hasAlpha={hasAlpha})");
Assert(pSurface != null, "Surface is null after load");
Assert(pSurface->Width() > 0 && pSurface->Height() > 0,
$"Bad dimensions after load: {pSurface->Width()}x{pSurface->Height()}");
Console.WriteLine($"OK ({pSurface->Width()}x{pSurface->Height()}, hasAlpha={hasAlpha})");
// ---- Test 5: Resize to power-of-two ≤ 512 ----------------------------
Console.Write("[Test 5] ResizeMakeSquare ... ");
surface.ResizeMakeSquare(512,
pSurface->ResizeMakeSquare(512,
NvttRoundMode.NVTT_RoundMode_ToPreviousPowerOfTwo,
NvttResizeFilter.NVTT_ResizeFilter_Box);
Assert(surface.Width <= 512 && surface.Height <= 512,
$"Expected ≤512 after resize, got {surface.Width}x{surface.Height}");
Assert(IsPowerOfTwo(surface.Width) && IsPowerOfTwo(surface.Height),
$"Expected power-of-two after resize, got {surface.Width}x{surface.Height}");
Console.WriteLine($"OK ({surface.Width}x{surface.Height})");
NvttResizeFilter.NVTT_ResizeFilter_Box, null);
Assert(pSurface->Width() <= 512 && pSurface->Height() <= 512,
$"Expected ≤512 after resize, got {pSurface->Width()}x{pSurface->Height()}");
Assert(IsPowerOfTwo(pSurface->Width()) && IsPowerOfTwo(pSurface->Height()),
$"Expected power-of-two after resize, got {pSurface->Width()}x{pSurface->Height()}");
Console.WriteLine($"OK ({pSurface->Width()}x{pSurface->Height()})");
// ---- Test 6: sRGB → linear conversion ---------------------------------
Console.Write("[Test 6] ToLinearFromSrgb ... ");
surface.ToLinearFromSrgb(); // must not crash
pSurface->ToLinearFromSrgb(null); // must not crash
Console.WriteLine("OK");
// ---- Test 7: CountMipmaps ---------------------------------------------
Console.Write("[Test 7] CountMipmaps ... ");
var mipCount = surface.CountMipmaps();
var expectedMax = (int)Math.Log2(Math.Max(surface.Width, surface.Height)) + 1;
var mipCount = pSurface->CountMipmaps(1);
var expectedMax = (int)Math.Log2(Math.Max(pSurface->Width(), pSurface->Height())) + 1;
Assert(mipCount > 0 && mipCount <= expectedMax,
$"Unexpected mip count: {mipCount} (expected 1..{expectedMax})");
Console.WriteLine($"OK ({mipCount} levels)");
// ---- Test 8: In-memory BC7 compression + mip chain -------------------
// ---- Test 8: In-memory BC7 compression + pMip chain -------------------
Console.Write("[Test 8] Compress BC7 in-memory ... ");
long totalBytesReceived = 0;
var totalBytesReceived = 0L;
var imagesBegun = 0;
using var compOpts = new NvttCompressionOptionsHandle();
compOpts.Format = NvttFormat.NVTT_Format_BC7;
compOpts.Quality = NvttQuality.NVTT_Quality_Fastest;
var pCompOpts = NvttCompressionOptions.Create();
pCompOpts->SetFormat(NvttFormat.NVTT_Format_BC7);
pCompOpts->SetQuality(NvttQuality.NVTT_Quality_Fastest);
using var outOpts = new NvttOutputOptionsHandle();
outOpts.OutputHeader = true;
outOpts.Srgb = true;
outOpts.Container = NvttContainer.NVTT_Container_DDS10;
var pOutOpts = NvttOutputOptions.Create();
pOutOpts->SetOutputHeader(true);
pOutOpts->SetSrgbFlag(true);
pOutOpts->SetContainer(NvttContainer.NVTT_Container_DDS10);
outOpts.SetOutputHandler(
beginImage: (size, w, h, d, face, mip) =>
pOutOpts->SetOutputHandler(
(size, w, h, d, face, mip) =>
{
imagesBegun++;
},
outputData: (ptr, len) =>
(ptr, len) =>
{
totalBytesReceived += len;
return true;
},
endImage: null
null
);
outOpts.SetErrorHandler(err =>
pOutOpts->SetErrorHandler(err =>
Console.WriteLine($"/n [NVTT Error] {err}"));
using var ctx = new NvttContextHandle();
ctx.SetCudaAcceleration(false); // CPU only for the test
var pCtx = NvttContext.Create();
pCtx->SetCudaAcceleration(false); // CPU only for the test
using var mip = surface.Clone();
var headerOk = ctx.OutputHeader(mip, mipCount, compOpts, outOpts);
var pMip = pSurface->Clone();
var headerOk = pCtx->OutputHeader(pMip, mipCount, pCompOpts, pOutOpts);
Assert(headerOk, "OutputHeader returned false");
for (var level = 0; level < mipCount; level++)
{
var compressOk = ctx.Compress(mip, face: 0, mipmap: level, compOpts, outOpts);
var compressOk = pCtx->Compress(pMip, face: 0, mipmap: level, pCompOpts, pOutOpts);
Assert(compressOk, $"Compress returned false at mip level {level}");
if (level + 1 < mipCount)
mip.BuildNextMipmap(NvttMipmapFilter.NVTT_MipmapFilter_Kaiser);
{
pMip->BuildNextMipmapDefaults(NvttMipmapFilter.NVTT_MipmapFilter_Kaiser, 1, null);
}
}
Assert(imagesBegun == mipCount,
@@ -149,48 +157,75 @@ internal sealed unsafe class NvttBindingTest : ITest
Console.WriteLine($"OK ({imagesBegun} mips, {totalBytesReceived:N0} bytes total)");
// ---- Test 9: EstimateSize consistency ---------------------------------
Console.Write("[Test 9] EstimateSize ... ");
var estimated = ctx.EstimateSize(surface, mipCount, compOpts);
var estimated = pCtx->EstimateSize(pSurface, mipCount, pCompOpts);
// Estimate can differ from actual due to header overhead; just sanity-check it's > 0.
Assert(estimated > 0, $"EstimateSize returned {estimated}");
Console.WriteLine($"OK (estimated = {estimated:N0} bytes, actual = {totalBytesReceived:N0} bytes)");
// ---- Test 10: Output to real DDS file ---------------------------------
Console.Write("[Test 10] Compress to file ... ");
using var outOptsFile = new NvttOutputOptionsHandle();
outOptsFile.OutputHeader = true;
outOptsFile.Srgb = true;
outOptsFile.Container = NvttContainer.NVTT_Container_DDS10;
outOptsFile.FileName = _outputDdsPath;
var pOutOptsFile = NvttOutputOptions.Create();
pOutOptsFile->SetOutputHeader(true);
pOutOptsFile->SetSrgbFlag(true);
pOutOptsFile->SetContainer(NvttContainer.NVTT_Container_DDS10);
pOutOptsFile->SetFileName(Encoding.UTF8.GetBytes(_outputDdsPath));
using var ctxFile = new NvttContextHandle();
using var mipFile = surface.Clone();
var pCtxFile = NvttContext.Create();
var pMipFile = pSurface->Clone();
var fileHeaderOk = ctxFile.OutputHeader(mipFile, mipCount, compOpts, outOptsFile);
var fileHeaderOk = pCtxFile->OutputHeader(pMipFile, mipCount, pCompOpts, pOutOptsFile);
Assert(fileHeaderOk, "File OutputHeader returned false");
for (var level = 0; level < mipCount; level++)
{
var ok = ctxFile.Compress(mipFile, face: 0, mipmap: level, compOpts, outOptsFile);
var ok = pCtxFile->Compress(pMipFile, face: 0, mipmap: level, pCompOpts, pOutOptsFile);
Assert(ok, $"File Compress returned false at level {level}");
if (level + 1 < mipCount)
mipFile.BuildNextMipmap(NvttMipmapFilter.NVTT_MipmapFilter_Kaiser);
{
pMipFile->BuildNextMipmapDefaults(NvttMipmapFilter.NVTT_MipmapFilter_Kaiser, 1, null);
}
}
Assert(File.Exists(_outputDdsPath),
$"DDS output file was not created: {_outputDdsPath}");
Assert(File.Exists(_outputDdsPath), $"DDS output file was not created: {_outputDdsPath}");
var fileSize = new FileInfo(_outputDdsPath).Length;
Assert(fileSize > 128, $"DDS file suspiciously small: {fileSize} bytes");
Console.WriteLine($"OK ({fileSize:N0} bytes → {_outputDdsPath})");
Console.WriteLine("/n[NvttBindingTest] All tests PASSED.");
Console.WriteLine("[NvttBindingTest] All tests PASSED.");
pMipFile->Dispose();
pCtxFile->Dispose();
pOutOptsFile->Dispose();
pMip->Dispose();
pCtx->Dispose();
pOutOpts->Dispose();
pCompOpts->Dispose();
pSurface->Dispose();
}
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
private static void CallBack(NvttSeverity severity, NvttError error, sbyte* msg, void* userData)
{
(*(int*)userData)++;
int i = 0;
while (msg[i] != 0)
{
i++;
}
Console.WriteLine($"/n [NVTT] [{severity}] {error}: {Encoding.UTF8.GetString((byte*)msg, i)}");
}
public void Cleanup()
{
// Leave the DDS file in place so you can inspect it.
Console.WriteLine($"/n[NvttBindingTest] Output DDS left at: {_outputDdsPath}");
Console.WriteLine($"[NvttBindingTest] Output DDS left at: {_outputDdsPath}");
}
// -------------------------------------------------------------------------
@@ -198,7 +233,9 @@ internal sealed unsafe class NvttBindingTest : ITest
private static void Assert(bool condition, string message)
{
if (!condition)
{
throw new InvalidOperationException($"[ASSERTION FAILED] {message}");
}
}
private static bool IsPowerOfTwo(int n)

View File

@@ -3,69 +3,50 @@ using Ghost.Ufbx;
namespace Ghost.MicroTest;
internal class UfbxBindingTest : ITest
internal unsafe class UfbxBindingTest : ITest
{
private static ReadOnlySpan<byte> TestFilePath => "F:/c/Third Parties/ufbx/data/blender_340_z_up_7400_binary.fbx"u8;
public void Setup()
{
}
public void Run()
{
// Smoke-test LoadOpts heap-pointer shape (construct, set, read back, dispose)
using var opts = new LoadOpts();
opts.IgnoreAnimation = true;
opts.IgnoreEmbedded = true;
var load_Opts = new ufbx_load_opts();
var error = new ufbx_error();
// Load scene using the safe high-level wrapper (no unsafe, no fixed blocks)
using var scene = Scene.LoadFile(TestFilePath, opts);
var pScene = ufbx_scene.load_file_len("F:/c/Third Parties/ufbx/data/blender_340_z_up_7400_binary.fbx"u8, &load_Opts, &error);
// Enumerate nodes using the wrapper's NodeList (ref struct, no allocation)
for (var i = 0; i < scene.Nodes.Count; i++)
if (pScene == null)
{
var node = scene.Nodes[i];
if (node.IsRoot)
Console.WriteLine(error.description.ToString());
}
for (var i = 0u; i < pScene->nodes.count; i++)
{
var node = pScene->nodes.data[i];
if (node->is_root)
{
continue;
}
// node.Name is a string property — no manual ToString() needed
Console.WriteLine($"Object: {node.Name}");
Console.WriteLine($"Object: {node->name}");
if (node.HasMesh)
if (node->mesh != null)
{
Console.WriteLine($"-> mesh with {node.Mesh.NumFaces} faces");
Console.WriteLine($"-> mesh with {node->mesh->num_faces} faces");
Console.WriteLine($"-> mesh with positions: {node->local_transform.translation}");
}
for (var j = 0u; j < node->materials.count; j++)
{
var mat = node->materials.data[j];
Console.WriteLine("-> material: " + mat->name);
Console.WriteLine(" -> shader type: " + mat->shader_type);
Console.WriteLine(" -> texture count: " + mat->textures.count);
}
}
// Find a node by name using the new instance method (no unsafe, no fixed)
var rootNode = scene.FindNode("RootNode"u8);
if (!rootNode.IsNull)
{
Console.WriteLine($"Found root node: {rootNode.Name}");
}
// Find a material by name
var material = scene.FindMaterial("Material"u8);
if (!material.IsNull)
{
Console.WriteLine($"Found material: {material.Name}");
// Find a prop on the material's props using the instance method
var prop = material.Props.FindProp("DiffuseColor"u8);
if (!prop.IsNull)
{
Console.WriteLine($" DiffuseColor prop type: {prop.Type}");
}
}
// Find an anim stack
var animStack = scene.FindAnimStack("Take 001"u8);
if (!animStack.IsNull)
{
Console.WriteLine($"Found anim stack: {animStack.Name}");
}
pScene->free();
Console.WriteLine("Done.");
}

View File

@@ -1,8 +1,63 @@
namespace Ghost.Nvtt
{
public enum NvttBoolean
//public enum NvttBoolean
//{
// NVTT_False,
// NVTT_True,
//}
// The native NVTT API uses an enum for boolean values, but we want to expose it as a struct that can be implicitly converted to/from C# bool for better ergonomics.
// Since the binary layout of a struct with a single int field is the same as an enum, this should be safe for interop.
public readonly struct NvttBoolean : IEquatable<NvttBoolean>
{
NVTT_False,
NVTT_True,
public static NvttBoolean NVTT_False => new(0);
public static NvttBoolean NVTT_True => new(1);
private readonly int _value;
public NvttBoolean(int value)
{
_value = value;
}
public bool Equals(NvttBoolean other)
{
return _value == other._value;
}
public override bool Equals(object? obj)
{
return obj is NvttBoolean && Equals((NvttBoolean)obj);
}
public override int GetHashCode()
{
return _value;
}
public override string ToString()
{
return _value.ToString();
}
public static bool operator ==(NvttBoolean left, NvttBoolean right)
{
return left.Equals(right);
}
public static bool operator !=(NvttBoolean left, NvttBoolean right)
{
return !(left == right);
}
public static implicit operator NvttBoolean(bool value)
{
return value ? NVTT_True : NVTT_False;
}
public static implicit operator bool(NvttBoolean value)
{
return value._value != 0;
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Runtime.InteropServices;
namespace Ghost.Nvtt;
public delegate void BeginImageDelegate(int w, int h, int d, int f, int m, int t);
public delegate NvttBoolean OutputDelegate(IntPtr data, int size);
public delegate void EndImageDelegate();
public delegate void ErrorDelegate(NvttError error);
public unsafe partial struct NvttOutputOptions
{
public void SetOutputHandler(BeginImageDelegate? beginImageHandler, OutputDelegate? outputHandler, EndImageDelegate? endImageHandler)
{
var beginPtr = beginImageHandler == null ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(beginImageHandler);
var outputPtr = outputHandler == null ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(outputHandler);
var endPtr = endImageHandler == null ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(endImageHandler);
Api.nvttSetOutputOptionsOutputHandler(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(delegate* unmanaged[Cdecl]<int, int, int, int, int, int, void>)beginPtr,
(delegate* unmanaged[Cdecl]<void*, int, NvttBoolean>)outputPtr,
endPtr);
}
public void SetErrorHandler(ErrorDelegate? errorHandler)
{
var errorPtr = errorHandler == null ? IntPtr.Zero : Marshal.GetFunctionPointerForDelegate(errorHandler);
Api.nvttSetOutputOptionsErrorHandler(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(delegate* unmanaged[Cdecl]<NvttError, void>)errorPtr);
}
}

View File

@@ -0,0 +1,11 @@
namespace Ghost.Nvtt;
public static class Utility
{
//extension(NvttBoolean boolean)
//{
// public static bool operator true(NvttBoolean b) => b == NvttBoolean.NVTT_True;
// public static bool operator false(NvttBoolean b) => b == NvttBoolean.NVTT_False;
// public static bool operator !(NvttBoolean b) => b == NvttBoolean.NVTT_False;
//}
}

View File

@@ -1,91 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Wrapper around an nvtt batch list — a list of (surface, face, mipmap,
/// outputOptions) tuples passed to <see cref="NvttContext.CompressBatch"/>.
/// </summary>
public sealed unsafe class NvttBatchListHandle : IDisposable
{
private NvttBatchList* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttBatchList* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttBatchListHandle() => _ptr = Api.nvttCreateBatchList();
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroyBatchList(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// Mutation
// -------------------------------------------------------------------------
/// <summary>Removes all items from the list.</summary>
public void Clear()
{
ThrowIfDisposed();
Api.nvttBatchListClear(_ptr);
}
/// <summary>
/// Appends an entry. The <paramref name="surface"/> and
/// <paramref name="outputOptions"/> must remain alive for the duration of
/// any subsequent <see cref="NvttContext.CompressBatch"/> call.
/// </summary>
public void Append(NvttSurfaceHandle surface, int face, int mipmap,
NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
Api.nvttBatchListAppend(_ptr, surface.Ptr, face, mipmap,
outputOptions.Ptr);
}
// -------------------------------------------------------------------------
// Query
// -------------------------------------------------------------------------
/// <summary>Number of items currently in the list.</summary>
public uint Count
{
get { ThrowIfDisposed(); return Api.nvttBatchListGetSize(_ptr); }
}
/// <summary>
/// Returns the raw pointers for item <paramref name="index"/>.
/// The pointers are borrowed - do NOT dispose them.
/// </summary>
public void GetItem(uint index,
out NvttSurface* surface, out int face, out int mipmap,
out NvttOutputOptions* outputOptions)
{
ThrowIfDisposed();
NvttSurface* s;
NvttOutputOptions* o;
int f, m;
Api.nvttBatchListGetItem(_ptr, index, &s, &f, &m, &o);
surface = s;
face = f;
mipmap = m;
outputOptions = o;
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttBatchListHandle));
}
}
}

View File

@@ -0,0 +1,55 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttBatchList : System.IDisposable
{
// From: nvttCreateBatchList()
public static NvttBatchList* Create()
{
return Api.nvttCreateBatchList();
}
// From: nvttDestroyBatchList(NvttBatchList*)
public void Dispose()
{
Api.nvttDestroyBatchList((NvttBatchList*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttBatchListClear(NvttBatchList*)
public void Clear()
{
Api.nvttBatchListClear((NvttBatchList*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttBatchListAppend(NvttBatchList*, NvttSurface*, int, int, NvttOutputOptions*)
public void Append(NvttSurface* pImg, int face, int mipmap, NvttOutputOptions* outputOptions)
{
Api.nvttBatchListAppend(
(NvttBatchList*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
pImg,
face,
mipmap,
outputOptions);
}
// From: nvttBatchListGetSize(NvttBatchList*)
public uint GetSize()
{
return Api.nvttBatchListGetSize((NvttBatchList*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttBatchListGetItem(NvttBatchList*, uint, NvttSurface**, int*, int*, NvttOutputOptions**)
public void GetItem(uint i, NvttSurface** pImg, int* face, int* mipmap, NvttOutputOptions** outputOptions)
{
Api.nvttBatchListGetItem(
(NvttBatchList*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
i,
pImg,
face,
mipmap,
outputOptions);
}
}

View File

@@ -0,0 +1,212 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttCPUInputBuffer : System.IDisposable
{
// From: nvttDestroyCPUInputBuffer(NvttCPUInputBuffer*)
public void Dispose()
{
Api.nvttDestroyCPUInputBuffer((NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttCPUInputBufferNumTiles(NvttCPUInputBuffer*)
public int NumTiles()
{
return Api.nvttCPUInputBufferNumTiles((NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttCPUInputBufferTileSize(NvttCPUInputBuffer*, int*, int*)
public void TileSize(int* tile_w, int* tile_h)
{
Api.nvttCPUInputBufferTileSize(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
tile_w,
tile_h);
}
// From: nvttCPUInputBufferType(NvttCPUInputBuffer*)
public NvttValueType Type()
{
return Api.nvttCPUInputBufferType((NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttEncodeCPU(NvttCPUInputBuffer*, void*, NvttEncodeSettings*)
public NvttBoolean EncodeCPU(void* output, NvttEncodeSettings* settings)
{
return Api.nvttEncodeCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
settings);
}
// From: nvttEncodeBC1CPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC1CPU(NvttBoolean fast_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC1CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
fast_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC1ACPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC1ACPU(NvttBoolean fast_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC1ACPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
fast_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC2CPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC2CPU(NvttBoolean fast_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC2CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
fast_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC3CPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC3CPU(NvttBoolean fast_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC3CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
fast_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC3NCPU(NvttCPUInputBuffer*, int, void*, NvttTimingContext*)
public void EncodeBC3NCPU(int qualityLevel, void* output, NvttTimingContext* tc)
{
Api.nvttEncodeBC3NCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
qualityLevel,
output,
tc);
}
// From: nvttEncodeBC3RGBMCPU(NvttCPUInputBuffer*, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC3RGBMCPU(void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC3RGBMCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC4CPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC4CPU(NvttBoolean slow_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC4CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC4SCPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC4SCPU(NvttBoolean slow_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC4SCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeATI2CPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeATI2CPU(NvttBoolean slow_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeATI2CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC5CPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC5CPU(NvttBoolean slow_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC5CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC5SCPU(NvttCPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC5SCPU(NvttBoolean slow_mode, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC5SCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC6HCPU(NvttCPUInputBuffer*, NvttBoolean, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC6HCPU(NvttBoolean slow_mode, NvttBoolean is_signed, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC6HCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
is_signed,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeBC7CPU(NvttCPUInputBuffer*, NvttBoolean, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeBC7CPU(NvttBoolean slow_mode, NvttBoolean imageHasAlpha, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC7CPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
slow_mode,
imageHasAlpha,
output,
useGpu,
to_device_mem,
tc);
}
// From: nvttEncodeASTCCPU(NvttCPUInputBuffer*, int, NvttBoolean, void*, NvttBoolean, NvttBoolean, NvttTimingContext*)
public void EncodeASTCCPU(int qualityLevel, NvttBoolean imageHasAlpha, void* output, NvttBoolean useGpu, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeASTCCPU(
(NvttCPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
qualityLevel,
imageHasAlpha,
output,
useGpu,
to_device_mem,
tc);
}
}

View File

@@ -1,123 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Controls how a surface is compressed - format, quality, pixel layout and
/// optional quantization settings.
/// </summary>
public sealed unsafe class NvttCompressionOptionsHandle : IDisposable
{
private NvttCompressionOptions* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttCompressionOptions* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttCompressionOptionsHandle() => _ptr = Api.nvttCreateCompressionOptions();
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroyCompressionOptions(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
/// <summary>Target compressed format (e.g. BC1, BC7, ASTC …).</summary>
public NvttFormat Format
{
set { ThrowIfDisposed(); Api.nvttSetCompressionOptionsFormat(_ptr, value); }
}
/// <summary>Compression quality preset.</summary>
public NvttQuality Quality
{
set { ThrowIfDisposed(); Api.nvttSetCompressionOptionsQuality(_ptr, value); }
}
/// <summary>Pixel type for uncompressed RGB(A) output.</summary>
public NvttPixelType PixelType
{
set { ThrowIfDisposed(); Api.nvttSetCompressionOptionsPixelType(_ptr, value); }
}
/// <summary>Row-pitch alignment in bytes for uncompressed output.</summary>
public int PitchAlignment
{
set { ThrowIfDisposed(); Api.nvttSetCompressionOptionsPitchAlignment(_ptr, value); }
}
// -------------------------------------------------------------------------
// Methods
// -------------------------------------------------------------------------
/// <summary>Resets all options to their default values.</summary>
public void Reset()
{
ThrowIfDisposed();
Api.nvttResetCompressionOptions(_ptr);
}
/// <summary>
/// Sets per-channel importance weights used during block-compression error
/// minimisation.
/// </summary>
public void SetColorWeights(float red, float green, float blue, float alpha = 1f)
{
ThrowIfDisposed();
Api.nvttSetCompressionOptionsColorWeights(_ptr, red, green, blue, alpha);
}
/// <summary>
/// Configures a custom uncompressed pixel format by specifying the bit-depth
/// and per-channel bit masks.
/// </summary>
public void SetPixelFormat(uint bitCount, uint rMask, uint gMask, uint bMask, uint aMask)
{
ThrowIfDisposed();
Api.nvttSetCompressionOptionsPixelFormat(_ptr, bitCount, rMask, gMask, bMask, aMask);
}
/// <summary>
/// Enables or disables dithering and binary-alpha quantisation.
/// </summary>
/// <param name="colorDithering">Dither RGB channels.</param>
/// <param name="alphaDithering">Dither the alpha channel.</param>
/// <param name="binaryAlpha">Snap alpha to 0 or 255.</param>
/// <param name="alphaThreshold">Threshold used when <paramref name="binaryAlpha"/> is true.</param>
public void SetQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha,
int alphaThreshold = 127)
{
ThrowIfDisposed();
Api.nvttSetCompressionOptionsQuantization(
_ptr,
NvttInterop.ToNvtt(colorDithering),
NvttInterop.ToNvtt(alphaDithering),
NvttInterop.ToNvtt(binaryAlpha),
alphaThreshold);
}
/// <summary>Returns the D3D9 FourCC / D3DFORMAT value for the current settings.</summary>
public uint GetD3D9Format()
{
ThrowIfDisposed();
return Api.nvttGetCompressionOptionsD3D9Format(_ptr);
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttCompressionOptionsHandle));
}
}
}

View File

@@ -0,0 +1,98 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttCompressionOptions : System.IDisposable
{
// From: nvttCreateCompressionOptions()
public static NvttCompressionOptions* Create()
{
return Api.nvttCreateCompressionOptions();
}
// From: nvttDestroyCompressionOptions(NvttCompressionOptions*)
public void Dispose()
{
Api.nvttDestroyCompressionOptions((NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttResetCompressionOptions(NvttCompressionOptions*)
public void Reset()
{
Api.nvttResetCompressionOptions((NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSetCompressionOptionsFormat(NvttCompressionOptions*, NvttFormat)
public void SetFormat(NvttFormat format)
{
Api.nvttSetCompressionOptionsFormat(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
format);
}
// From: nvttSetCompressionOptionsQuality(NvttCompressionOptions*, NvttQuality)
public void SetQuality(NvttQuality quality)
{
Api.nvttSetCompressionOptionsQuality(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
quality);
}
// From: nvttSetCompressionOptionsColorWeights(NvttCompressionOptions*, float, float, float, float)
public void SetColorWeights(float red, float green, float blue, float alpha)
{
Api.nvttSetCompressionOptionsColorWeights(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
red,
green,
blue,
alpha);
}
// From: nvttSetCompressionOptionsPixelFormat(NvttCompressionOptions*, uint, uint, uint, uint, uint)
public void SetPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
{
Api.nvttSetCompressionOptionsPixelFormat(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
bitcount,
rmask,
gmask,
bmask,
amask);
}
// From: nvttSetCompressionOptionsPixelType(NvttCompressionOptions*, NvttPixelType)
public void SetPixelType(NvttPixelType pixelType)
{
Api.nvttSetCompressionOptionsPixelType(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
pixelType);
}
// From: nvttSetCompressionOptionsPitchAlignment(NvttCompressionOptions*, int)
public void SetPitchAlignment(int pitchAlignment)
{
Api.nvttSetCompressionOptionsPitchAlignment(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
pitchAlignment);
}
// From: nvttSetCompressionOptionsQuantization(NvttCompressionOptions*, NvttBoolean, NvttBoolean, NvttBoolean, int)
public void SetQuantization(NvttBoolean colorDithering, NvttBoolean alphaDithering, NvttBoolean binaryAlpha, int alphaThreshold)
{
Api.nvttSetCompressionOptionsQuantization(
(NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
colorDithering,
alphaDithering,
binaryAlpha,
alphaThreshold);
}
// From: nvttGetCompressionOptionsD3D9Format(NvttCompressionOptions*)
public uint GetD3D9Format()
{
return Api.nvttGetCompressionOptionsD3D9Format((NvttCompressionOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
}

View File

@@ -1,229 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Wrapper around the nvtt compression context — the central object that drives
/// the compression pipeline.
/// </summary>
public sealed unsafe class NvttContextHandle : IDisposable
{
private NvttContext* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttContext* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttContextHandle() => _ptr = Api.nvttCreateContext();
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroyContext(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// CUDA acceleration
// -------------------------------------------------------------------------
/// <summary>Enables or disables CUDA-accelerated compression.</summary>
public void SetCudaAcceleration(bool enable)
{
ThrowIfDisposed();
Api.nvttSetContextCudaAcceleration(_ptr, NvttInterop.ToNvtt(enable));
}
/// <summary>Returns <c>true</c> if CUDA acceleration is currently enabled.</summary>
public bool IsCudaAccelerationEnabled
{
get
{
ThrowIfDisposed();
return NvttInterop.ToBool(Api.nvttContextIsCudaAccelerationEnabled(_ptr));
}
}
// -------------------------------------------------------------------------
// Timing
// -------------------------------------------------------------------------
/// <summary>
/// Enables or disables internal timing collection.
/// <paramref name="detailLevel"/> controls the granularity (0 = off, higher = more detail).
/// </summary>
public void EnableTiming(bool enable, int detailLevel = 1)
{
ThrowIfDisposed();
Api.nvttContextEnableTiming(_ptr, NvttInterop.ToNvtt(enable), detailLevel);
}
/// <summary>
/// Returns the timing context owned by this nvtt context.
/// The pointer is borrowed - do NOT dispose it separately.
/// Returns <c>null</c> if timing was never enabled.
/// </summary>
public NvttTimingContext* GetTimingContextPtr()
{
ThrowIfDisposed();
return Api.nvttContextGetTimingContext(_ptr);
}
// -------------------------------------------------------------------------
// Estimate size
// -------------------------------------------------------------------------
/// <summary>
/// Estimates the compressed size in bytes for <paramref name="mipmapCount"/>
/// mip levels of <paramref name="img"/> using <paramref name="compressionOptions"/>.
/// </summary>
public int EstimateSize(NvttSurfaceHandle img, int mipmapCount,
NvttCompressionOptionsHandle compressionOptions)
{
ThrowIfDisposed();
return Api.nvttContextEstimateSize(_ptr, img.Ptr, mipmapCount,
compressionOptions.Ptr);
}
/// <summary>Estimates the compressed size for a cube map.</summary>
public int EstimateSizeCube(NvttCubeSurfaceHandle img, int mipmapCount,
NvttCompressionOptionsHandle compressionOptions)
{
ThrowIfDisposed();
return Api.nvttContextEstimateSizeCube(_ptr, img.Ptr, mipmapCount,
compressionOptions.Ptr);
}
/// <summary>Estimates the compressed size for raw-data dimensions.</summary>
public int EstimateSizeData(int w, int h, int d, int mipmapCount,
NvttCompressionOptionsHandle compressionOptions)
{
ThrowIfDisposed();
return Api.nvttContextEstimateSizeData(_ptr, w, h, d, mipmapCount,
compressionOptions.Ptr);
}
// -------------------------------------------------------------------------
// Output header
// -------------------------------------------------------------------------
/// <summary>
/// Writes the DDS / KTX header to <paramref name="outputOptions"/>.
/// Must be called once before compressing mip levels.
/// Returns <c>false</c> on failure.
/// </summary>
public bool OutputHeader(NvttSurfaceHandle img, int mipmapCount,
NvttCompressionOptionsHandle compressionOptions, NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttContextOutputHeader(_ptr, img.Ptr, mipmapCount,
compressionOptions.Ptr, outputOptions.Ptr));
}
/// <summary>Writes the header for a cube-map texture.</summary>
public bool OutputHeaderCube(NvttCubeSurfaceHandle img, int mipmapCount,
NvttCompressionOptionsHandle compressionOptions, NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttContextOutputHeaderCube(_ptr, img.Ptr, mipmapCount,
compressionOptions.Ptr, outputOptions.Ptr));
}
/// <summary>Writes the header using explicit dimensions instead of a surface.</summary>
public bool OutputHeaderData(NvttTextureType type, int w, int h, int d,
int mipmapCount, bool isNormalMap,
NvttCompressionOptionsHandle compressionOptions, NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttContextOutputHeaderData(_ptr, type, w, h, d, mipmapCount,
NvttInterop.ToNvtt(isNormalMap),
compressionOptions.Ptr, outputOptions.Ptr));
}
// -------------------------------------------------------------------------
// Compress
// -------------------------------------------------------------------------
/// <summary>
/// Compresses a single face/mip of <paramref name="img"/> and sends the
/// result to <paramref name="outputOptions"/>.
/// Returns <c>false</c> on failure.
/// </summary>
public bool Compress(NvttSurfaceHandle img, int face, int mipmap,
NvttCompressionOptionsHandle compressionOptions, NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttContextCompress(_ptr, img.Ptr, face, mipmap,
compressionOptions.Ptr, outputOptions.Ptr));
}
/// <summary>Compresses a single mip of a cube-map face.</summary>
public bool CompressCube(NvttCubeSurfaceHandle img, int mipmap,
NvttCompressionOptionsHandle compressionOptions, NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttContextCompressCube(_ptr, img.Ptr, mipmap,
compressionOptions.Ptr, outputOptions.Ptr));
}
/// <summary>Compresses a single mip from a raw float RGBA buffer.</summary>
public bool CompressData(int w, int h, int d, int face, int mipmap,
ReadOnlySpan<float> rgba,
NvttCompressionOptionsHandle compressionOptions, NvttOutputOptionsHandle outputOptions)
{
ThrowIfDisposed();
fixed (float* p = rgba)
{
return NvttInterop.ToBool(
Api.nvttContextCompressData(_ptr, w, h, d, face, mipmap, p,
compressionOptions.Ptr, outputOptions.Ptr));
}
}
/// <summary>
/// Compresses a batch of (surface, face, mipmap, outputOptions) entries
/// using the shared <paramref name="compressionOptions"/>.
/// Returns <c>false</c> on failure.
/// </summary>
public bool CompressBatch(NvttBatchListHandle batchList,
NvttCompressionOptionsHandle compressionOptions)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttContextCompressBatch(_ptr, batchList.Ptr,
compressionOptions.Ptr));
}
// -------------------------------------------------------------------------
// Quantize
// -------------------------------------------------------------------------
/// <summary>
/// Quantizes <paramref name="surface"/> in place according to
/// <paramref name="compressionOptions"/> (useful before compressing
/// to formats that only support limited bit depths).
/// </summary>
public void Quantize(NvttSurfaceHandle surface, NvttCompressionOptionsHandle compressionOptions)
{
ThrowIfDisposed();
Api.nvttContextQuantize(_ptr, surface.Ptr, compressionOptions.Ptr);
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttContextHandle));
}
}
}

View File

@@ -0,0 +1,174 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttContext : System.IDisposable
{
// From: nvttCreateContext()
public static NvttContext* Create()
{
return Api.nvttCreateContext();
}
// From: nvttDestroyContext(NvttContext*)
public void Dispose()
{
Api.nvttDestroyContext((NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSetContextCudaAcceleration(NvttContext*, NvttBoolean)
public void SetCudaAcceleration(NvttBoolean enable)
{
Api.nvttSetContextCudaAcceleration(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
enable);
}
// From: nvttContextIsCudaAccelerationEnabled(NvttContext*)
public NvttBoolean IsCudaAccelerationEnabled()
{
return Api.nvttContextIsCudaAccelerationEnabled((NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttContextOutputHeader(NvttContext*, NvttSurface*, int, NvttCompressionOptions*, NvttOutputOptions*)
public NvttBoolean OutputHeader(NvttSurface* img, int mipmapCount, NvttCompressionOptions* compressionOptions, NvttOutputOptions* outputOptions)
{
return Api.nvttContextOutputHeader(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
mipmapCount,
compressionOptions,
outputOptions);
}
// From: nvttContextCompress(NvttContext*, NvttSurface*, int, int, NvttCompressionOptions*, NvttOutputOptions*)
public NvttBoolean Compress(NvttSurface* img, int face, int mipmap, NvttCompressionOptions* compressionOptions, NvttOutputOptions* outputOptions)
{
return Api.nvttContextCompress(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
face,
mipmap,
compressionOptions,
outputOptions);
}
// From: nvttContextEstimateSize(NvttContext*, NvttSurface*, int, NvttCompressionOptions*)
public int EstimateSize(NvttSurface* img, int mipmapCount, NvttCompressionOptions* compressionOptions)
{
return Api.nvttContextEstimateSize(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
mipmapCount,
compressionOptions);
}
// From: nvttContextQuantize(NvttContext*, NvttSurface*, NvttCompressionOptions*)
public void Quantize(NvttSurface* tex, NvttCompressionOptions* compressionOptions)
{
Api.nvttContextQuantize(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
tex,
compressionOptions);
}
// From: nvttContextOutputHeaderCube(NvttContext*, NvttCubeSurface*, int, NvttCompressionOptions*, NvttOutputOptions*)
public NvttBoolean OutputHeaderCube(NvttCubeSurface* img, int mipmapCount, NvttCompressionOptions* compressionOptions, NvttOutputOptions* outputOptions)
{
return Api.nvttContextOutputHeaderCube(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
mipmapCount,
compressionOptions,
outputOptions);
}
// From: nvttContextCompressCube(NvttContext*, NvttCubeSurface*, int, NvttCompressionOptions*, NvttOutputOptions*)
public NvttBoolean CompressCube(NvttCubeSurface* img, int mipmap, NvttCompressionOptions* compressionOptions, NvttOutputOptions* outputOptions)
{
return Api.nvttContextCompressCube(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
mipmap,
compressionOptions,
outputOptions);
}
// From: nvttContextEstimateSizeCube(NvttContext*, NvttCubeSurface*, int, NvttCompressionOptions*)
public int EstimateSizeCube(NvttCubeSurface* img, int mipmapCount, NvttCompressionOptions* compressionOptions)
{
return Api.nvttContextEstimateSizeCube(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
mipmapCount,
compressionOptions);
}
// From: nvttContextOutputHeaderData(NvttContext*, NvttTextureType, int, int, int, int, NvttBoolean, NvttCompressionOptions*, NvttOutputOptions*)
public NvttBoolean OutputHeaderData(NvttTextureType type, int w, int h, int d, int mipmapCount, NvttBoolean isNormalMap, NvttCompressionOptions* compressionOptions, NvttOutputOptions* outputOptions)
{
return Api.nvttContextOutputHeaderData(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
type,
w,
h,
d,
mipmapCount,
isNormalMap,
compressionOptions,
outputOptions);
}
// From: nvttContextCompressData(NvttContext*, int, int, int, int, int, float*, NvttCompressionOptions*, NvttOutputOptions*)
public NvttBoolean CompressData(int w, int h, int d, int face, int mipmap, float* rgba, NvttCompressionOptions* compressionOptions, NvttOutputOptions* outputOptions)
{
return Api.nvttContextCompressData(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
w,
h,
d,
face,
mipmap,
rgba,
compressionOptions,
outputOptions);
}
// From: nvttContextEstimateSizeData(NvttContext*, int, int, int, int, NvttCompressionOptions*)
public int EstimateSizeData(int w, int h, int d, int mipmapCount, NvttCompressionOptions* compressionOptions)
{
return Api.nvttContextEstimateSizeData(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
w,
h,
d,
mipmapCount,
compressionOptions);
}
// From: nvttContextCompressBatch(NvttContext*, NvttBatchList*, NvttCompressionOptions*)
public NvttBoolean CompressBatch(NvttBatchList* lst, NvttCompressionOptions* compressionOptions)
{
return Api.nvttContextCompressBatch(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
lst,
compressionOptions);
}
// From: nvttContextEnableTiming(NvttContext*, NvttBoolean, int)
public void EnableTiming(NvttBoolean enable, int detailLevel)
{
Api.nvttContextEnableTiming(
(NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
enable,
detailLevel);
}
// From: nvttContextGetTimingContext(NvttContext*)
public NvttTimingContext* GetTiming()
{
return Api.nvttContextGetTimingContext((NvttContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
}

View File

@@ -1,227 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Wrapper around an nvtt cube-map surface (six faces, optional mip chain).
///
/// Methods that return a new <see cref="NvttCubeSurface"/> transfer ownership
/// to the caller; dispose the result when done.
/// </summary>
public sealed unsafe class NvttCubeSurfaceHandle : IDisposable
{
private NvttCubeSurface* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttCubeSurface* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttCubeSurfaceHandle() => _ptr = Api.nvttCreateCubeSurface();
/// <summary>Wraps an existing raw pointer (takes ownership; will destroy on dispose).</summary>
internal NvttCubeSurfaceHandle(NvttCubeSurface* existing) => _ptr = existing;
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroyCubeSurface(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// Read-only properties
// -------------------------------------------------------------------------
/// <summary>Returns <c>true</c> when the cube surface holds no data.</summary>
public bool IsNull
{
get { ThrowIfDisposed(); return NvttInterop.ToBool(Api.nvttCubeSurfaceIsNull(_ptr)); }
}
/// <summary>Side length in pixels of each face.</summary>
public int EdgeLength
{
get { ThrowIfDisposed(); return Api.nvttCubeSurfaceEdgeLength(_ptr); }
}
/// <summary>Number of mip levels stored in this cube surface.</summary>
public int MipmapCount
{
get { ThrowIfDisposed(); return Api.nvttCubeSurfaceCountMipmaps(_ptr); }
}
// -------------------------------------------------------------------------
// Load / Save
// -------------------------------------------------------------------------
/// <summary>
/// Loads a cube map from disk.
/// <paramref name="mipmap"/> selects which mip level to load (-1 = all).
/// Returns <c>false</c> on failure.
/// </summary>
public bool Load(string fileName, int mipmap = 0)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(fileName, buf);
fixed (byte* p = utf8)
{
return NvttInterop.ToBool(Api.nvttCubeSurfaceLoad(_ptr, (sbyte*)p, mipmap));
}
}
/// <summary>Loads a cube map from a managed byte array. Returns <c>false</c> on failure.</summary>
public bool LoadFromMemory(ReadOnlySpan<byte> data, int mipmap = 0)
{
ThrowIfDisposed();
fixed (byte* p = data)
{
return NvttInterop.ToBool(
Api.nvttCubeSurfaceLoadFromMemory(_ptr, p, (ulong)data.Length, mipmap));
}
}
/// <summary>Saves the cube map to disk. Returns <c>false</c> on failure.</summary>
public bool Save(string fileName)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(fileName, buf);
fixed (byte* p = utf8)
{
return NvttInterop.ToBool(Api.nvttCubeSurfaceSave(_ptr, (sbyte*)p));
}
}
// -------------------------------------------------------------------------
// Face access
// -------------------------------------------------------------------------
/// <summary>
/// Returns the raw <see cref="NvttSurface"/> pointer for the given face
/// (05). The pointer is owned by this cube surface - do NOT dispose it.
/// </summary>
public NvttSurface* FacePtr(int face)
{
ThrowIfDisposed();
return Api.nvttCubeSurfaceFace(_ptr, face);
}
// -------------------------------------------------------------------------
// Fold / Unfold
// -------------------------------------------------------------------------
/// <summary>
/// Folds a cross-layout <see cref="NvttSurface"/> into this cube surface.
/// </summary>
public void Fold(NvttSurfaceHandle img, NvttCubeLayout layout)
{
ThrowIfDisposed();
Api.nvttCubeSurfaceFold(_ptr, img.Ptr, layout);
}
/// <summary>
/// Unfolds the cube surface into a flat cross-layout image.
/// Caller owns the returned surface.
/// </summary>
public NvttSurfaceHandle Unfold(NvttCubeLayout layout)
{
ThrowIfDisposed();
return new NvttSurfaceHandle(Api.nvttCubeSurfaceUnfold(_ptr, layout));
}
// -------------------------------------------------------------------------
// Query methods
// -------------------------------------------------------------------------
/// <summary>Returns the per-channel average for the given channel index.</summary>
public float Average(int channel)
{
ThrowIfDisposed();
return Api.nvttCubeSurfaceAverage(_ptr, channel);
}
/// <summary>Returns the min and max values of a channel across all faces.</summary>
public void Range(int channel, out float min, out float max)
{
ThrowIfDisposed();
float lo, hi;
Api.nvttCubeSurfaceRange(_ptr, channel, &lo, &hi);
min = lo;
max = hi;
}
// -------------------------------------------------------------------------
// Pixel operations
// -------------------------------------------------------------------------
/// <summary>Clamps a channel to [<paramref name="low"/>, <paramref name="high"/>].</summary>
public void Clamp(int channel, float low, float high)
{
ThrowIfDisposed();
Api.nvttCubeSurfaceClamp(_ptr, channel, low, high);
}
/// <summary>Applies gamma expansion (toLinear) to all faces.</summary>
public void ToLinear(float gamma)
{
ThrowIfDisposed();
Api.nvttCubeSurfaceToLinear(_ptr, gamma);
}
/// <summary>Applies gamma compression to all faces.</summary>
public void ToGamma(float gamma)
{
ThrowIfDisposed();
Api.nvttCubeSurfaceToGamma(_ptr, gamma);
}
// -------------------------------------------------------------------------
// Filtering (return new owned NvttCubeSurface)
// -------------------------------------------------------------------------
/// <summary>
/// Computes an irradiance-filtered cube map of the given <paramref name="size"/>.
/// Caller owns the result.
/// </summary>
public NvttCubeSurfaceHandle IrradianceFilter(int size, EdgeFixup fixup = EdgeFixup.NVTT_EdgeFixup_None)
{
ThrowIfDisposed();
return new NvttCubeSurfaceHandle(Api.nvttCubeSurfaceIrradianceFilter(_ptr, size, fixup));
}
/// <summary>
/// Computes a cosine-power (specular) filtered cube map.
/// Caller owns the result.
/// </summary>
public NvttCubeSurfaceHandle CosinePowerFilter(int size, float cosinePower,
EdgeFixup fixup = EdgeFixup.NVTT_EdgeFixup_None)
{
ThrowIfDisposed();
return new NvttCubeSurfaceHandle(
Api.nvttCubeSurfaceCosinePowerFilter(_ptr, size, cosinePower, fixup));
}
/// <summary>
/// Resamples the cube map to the given <paramref name="size"/> using fast bilinear resampling.
/// Caller owns the result.
/// </summary>
public NvttCubeSurfaceHandle FastResample(int size, EdgeFixup fixup = EdgeFixup.NVTT_EdgeFixup_None)
{
ThrowIfDisposed();
return new NvttCubeSurfaceHandle(Api.nvttCubeSurfaceFastResample(_ptr, size, fixup));
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttCubeSurfaceHandle));
}
}
}

View File

@@ -0,0 +1,168 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttCubeSurface : System.IDisposable
{
// From: nvttCreateCubeSurface()
public static NvttCubeSurface* Create()
{
return Api.nvttCreateCubeSurface();
}
// From: nvttDestroyCubeSurface(NvttCubeSurface*)
public void Dispose()
{
Api.nvttDestroyCubeSurface((NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttCubeSurfaceIsNull(NvttCubeSurface*)
public NvttBoolean IsNull()
{
return Api.nvttCubeSurfaceIsNull((NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttCubeSurfaceEdgeLength(NvttCubeSurface*)
public int EdgeLength()
{
return Api.nvttCubeSurfaceEdgeLength((NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttCubeSurfaceCountMipmaps(NvttCubeSurface*)
public int CountMipmaps()
{
return Api.nvttCubeSurfaceCountMipmaps((NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttCubeSurfaceLoad(NvttCubeSurface*, sbyte*, int)
public NvttBoolean Load(ReadOnlySpan<byte> fileName, int mipmap)
{
fixed (byte* pfileName = fileName)
{
return Api.nvttCubeSurfaceLoad(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(sbyte*)pfileName,
mipmap);
}
}
// From: nvttCubeSurfaceLoadFromMemory(NvttCubeSurface*, void*, ulong, int)
public NvttBoolean LoadFromMemory(void* data, ulong sizeInBytes, int mipmap)
{
return Api.nvttCubeSurfaceLoadFromMemory(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
data,
sizeInBytes,
mipmap);
}
// From: nvttCubeSurfaceSave(NvttCubeSurface*, sbyte*)
public NvttBoolean Save(ReadOnlySpan<byte> fileName)
{
fixed (byte* pfileName = fileName)
{
return Api.nvttCubeSurfaceSave(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(sbyte*)pfileName);
}
}
// From: nvttCubeSurfaceFace(NvttCubeSurface*, int)
public NvttSurface* Face(int face)
{
return Api.nvttCubeSurfaceFace(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
face);
}
// From: nvttCubeSurfaceFold(NvttCubeSurface*, NvttSurface*, NvttCubeLayout)
public void Fold(NvttSurface* img, NvttCubeLayout layout)
{
Api.nvttCubeSurfaceFold(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
img,
layout);
}
// From: nvttCubeSurfaceUnfold(NvttCubeSurface*, NvttCubeLayout)
public NvttSurface* Unfold(NvttCubeLayout layout)
{
return Api.nvttCubeSurfaceUnfold(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
layout);
}
// From: nvttCubeSurfaceAverage(NvttCubeSurface*, int)
public float Average(int channel)
{
return Api.nvttCubeSurfaceAverage(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
channel);
}
// From: nvttCubeSurfaceRange(NvttCubeSurface*, int, float*, float*)
public void Range(int channel, float* minimum_ptr, float* maximum_ptr)
{
Api.nvttCubeSurfaceRange(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
channel,
minimum_ptr,
maximum_ptr);
}
// From: nvttCubeSurfaceClamp(NvttCubeSurface*, int, float, float)
public void Clamp(int channel, float low, float high)
{
Api.nvttCubeSurfaceClamp(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
channel,
low,
high);
}
// From: nvttCubeSurfaceIrradianceFilter(NvttCubeSurface*, int, EdgeFixup)
public NvttCubeSurface* IrradianceFilter(int size, EdgeFixup fixupMethod)
{
return Api.nvttCubeSurfaceIrradianceFilter(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
size,
fixupMethod);
}
// From: nvttCubeSurfaceCosinePowerFilter(NvttCubeSurface*, int, float, EdgeFixup)
public NvttCubeSurface* CosinePowerFilter(int size, float cosinePower, EdgeFixup fixupMethod)
{
return Api.nvttCubeSurfaceCosinePowerFilter(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
size,
cosinePower,
fixupMethod);
}
// From: nvttCubeSurfaceFastResample(NvttCubeSurface*, int, EdgeFixup)
public NvttCubeSurface* FastResample(int size, EdgeFixup fixupMethod)
{
return Api.nvttCubeSurfaceFastResample(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
size,
fixupMethod);
}
// From: nvttCubeSurfaceToLinear(NvttCubeSurface*, float)
public void ToLinear(float gamma)
{
Api.nvttCubeSurfaceToLinear(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
gamma);
}
// From: nvttCubeSurfaceToGamma(NvttCubeSurface*, float)
public void ToGamma(float gamma)
{
Api.nvttCubeSurfaceToGamma(
(NvttCubeSurface*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
gamma);
}
}

View File

@@ -0,0 +1,169 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttGPUInputBuffer : System.IDisposable
{
// From: nvttDestroyGPUInputBuffer(NvttGPUInputBuffer*)
public void Dispose()
{
Api.nvttDestroyGPUInputBuffer((NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttGPUInputBufferNumTiles(NvttGPUInputBuffer*)
public int NumTiles()
{
return Api.nvttGPUInputBufferNumTiles((NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttGPUInputBufferTileSize(NvttGPUInputBuffer*, int*, int*)
public void TileSize(int* tile_w, int* tile_h)
{
Api.nvttGPUInputBufferTileSize(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
tile_w,
tile_h);
}
// From: nvttGPUInputBufferType(NvttGPUInputBuffer*)
public NvttValueType Type()
{
return Api.nvttGPUInputBufferType((NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttEncodeGPU(NvttGPUInputBuffer*, void*, NvttEncodeSettings*)
public NvttBoolean EncodeGPU(void* output, NvttEncodeSettings* settings)
{
return Api.nvttEncodeGPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
settings);
}
// From: nvttEncodeBC1GPU(NvttGPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC1GPU(NvttBoolean fast_mode, void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC1GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
fast_mode,
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC1AGPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC1AGPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC1AGPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC2GPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC2GPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC2GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC3GPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC3GPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC3GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC4GPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC4GPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC4GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC4SGPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC4SGPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC4SGPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeATI2GPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeATI2GPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeATI2GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC5GPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC5GPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC5GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC5SGPU(NvttGPUInputBuffer*, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC5SGPU(void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC5SGPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC6HGPU(NvttGPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC6HGPU(NvttBoolean is_signed, void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC6HGPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
is_signed,
output,
to_device_mem,
tc);
}
// From: nvttEncodeBC7GPU(NvttGPUInputBuffer*, NvttBoolean, void*, NvttBoolean, NvttTimingContext*)
public void EncodeBC7GPU(NvttBoolean imageHasAlpha, void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeBC7GPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
imageHasAlpha,
output,
to_device_mem,
tc);
}
// From: nvttEncodeASTCGPU(NvttGPUInputBuffer*, int, NvttBoolean, void*, NvttBoolean, NvttTimingContext*)
public void EncodeASTCGPU(int qualityLevel, NvttBoolean imageHasAlpha, void* output, NvttBoolean to_device_mem, NvttTimingContext* tc)
{
Api.nvttEncodeASTCGPU(
(NvttGPUInputBuffer*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
qualityLevel,
imageHasAlpha,
output,
to_device_mem,
tc);
}
}

View File

@@ -1,183 +0,0 @@
using System.Runtime.InteropServices;
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Static helpers wrapping global nvtt functions (version, CUDA detection,
/// error utilities, image comparison, mipmap helpers).
/// </summary>
public static unsafe class NvttGlobal
{
// -------------------------------------------------------------------------
// Library info
// -------------------------------------------------------------------------
/// <summary>Returns the nvtt library version as a packed uint (major*10000 + minor*100 + patch).</summary>
public static uint Version => Api.nvttVersion();
/// <summary>Returns <c>true</c> when a CUDA-capable GPU is available.</summary>
public static bool IsCudaSupported
=> NvttInterop.ToBool(Api.nvttIsCudaSupported());
// -------------------------------------------------------------------------
// Error strings
// -------------------------------------------------------------------------
/// <summary>Returns a human-readable string for <paramref name="error"/>.</summary>
public static string? ErrorString(NvttError error)
=> NvttInterop.FromUtf8(Api.nvttErrorString(error));
// -------------------------------------------------------------------------
// Global message callback
//
// The delegate type must be kept alive as long as the callback is registered.
// Store the returned token and dispose it to clear the callback.
// -------------------------------------------------------------------------
/// <summary>
/// Delegate type for the global nvtt message callback.
/// </summary>
public delegate void MessageCallback(
NvttSeverity severity, NvttError error, string? description);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void NativeMessageCallback(
NvttSeverity severity, NvttError error, sbyte* description, void* userData);
/// <summary>
/// A registration token returned by <see cref="SetMessageCallback"/>.
/// Dispose to clear the callback and release the pinned delegate.
/// </summary>
public sealed class MessageCallbackToken : IDisposable
{
private NativeMessageCallback? _pinned;
internal MessageCallbackToken(NativeMessageCallback pinned)
=> _pinned = pinned;
public void Dispose()
{
if (_pinned != null)
{
// Clear the callback by registering null.
Api.nvttSetMessageCallback(null, null);
_pinned = null;
}
}
}
/// <summary>
/// Registers a managed message callback that nvtt calls for warnings and errors.
/// Returns a token; dispose the token to unregister.
/// </summary>
public static MessageCallbackToken SetMessageCallback(MessageCallback callback)
{
void native(NvttSeverity sev, NvttError err, sbyte* descPtr, void* _)
{
var desc = NvttInterop.FromUtf8(descPtr);
callback(sev, err, desc);
}
var fp = Marshal.GetFunctionPointerForDelegate(native);
Api.nvttSetMessageCallback(
(delegate* unmanaged[Cdecl]<NvttSeverity, NvttError, sbyte*, void*, void>)fp,
null);
return new MessageCallbackToken(native);
}
// -------------------------------------------------------------------------
// Image comparison (error metrics)
// -------------------------------------------------------------------------
/// <summary>RMS per-channel colour error between two surfaces.</summary>
public static float RmsError(NvttSurfaceHandle reference, NvttSurfaceHandle img,
NvttTimingContext* tc = null)
=> Api.nvttRmsError(reference.Ptr, img.Ptr, tc);
/// <summary>RMS alpha-channel error between two surfaces.</summary>
public static float RmsAlphaError(NvttSurfaceHandle reference, NvttSurfaceHandle img,
NvttTimingContext* tc = null)
=> Api.nvttRmsAlphaError(reference.Ptr, img.Ptr, tc);
/// <summary>RMS CIE-Lab perceptual error between two surfaces.</summary>
public static float RmsCIELabError(NvttSurfaceHandle reference, NvttSurfaceHandle img,
NvttTimingContext* tc = null)
=> Api.nvttRmsCIELabError(reference.Ptr, img.Ptr, tc);
/// <summary>Angular error between two normal-map surfaces.</summary>
public static float AngularError(NvttSurfaceHandle reference, NvttSurfaceHandle img,
NvttTimingContext* tc = null)
=> Api.nvttAngularError(reference.Ptr, img.Ptr, tc);
/// <summary>
/// Tone-mapped RMS error. Useful for HDR comparisons.
/// </summary>
public static float RmsToneMappedError(NvttSurfaceHandle reference, NvttSurfaceHandle img,
float exposure, NvttTimingContext* tc = null)
=> Api.nvttRmsToneMappedError(reference.Ptr, img.Ptr, exposure, tc);
// -------------------------------------------------------------------------
// Difference image
// -------------------------------------------------------------------------
/// <summary>
/// Returns a new surface containing the scaled per-pixel difference.
/// Caller owns the returned surface.
/// </summary>
public static NvttSurfaceHandle Diff(NvttSurfaceHandle reference, NvttSurfaceHandle img,
float scale, NvttTimingContext* tc = null)
=> new NvttSurfaceHandle(Api.nvttDiff(reference.Ptr, img.Ptr, scale, tc));
// -------------------------------------------------------------------------
// Histogram
// -------------------------------------------------------------------------
/// <summary>
/// Returns a new surface containing a histogram visualisation of
/// <paramref name="img"/> at the given dimensions.
/// Caller owns the returned surface.
/// </summary>
public static NvttSurfaceHandle Histogram(NvttSurfaceHandle img, int width, int height,
NvttTimingContext* tc = null)
=> new NvttSurfaceHandle(Api.nvttHistogram(img.Ptr, width, height, tc));
/// <summary>
/// Returns a new surface containing a histogram visualisation with an
/// explicit value range.
/// Caller owns the returned surface.
/// </summary>
public static NvttSurfaceHandle HistogramRange(NvttSurfaceHandle img,
float minRange, float maxRange, int width, int height,
NvttTimingContext* tc = null)
=> new NvttSurfaceHandle(
Api.nvttHistogramRange(img.Ptr, minRange, maxRange, width, height, tc));
// -------------------------------------------------------------------------
// Extent / mipmap helpers
// -------------------------------------------------------------------------
/// <summary>
/// Computes the target extent (power-of-two rounding, texture type clamping,
/// etc.) for a texture of the given dimensions.
/// Modifies <paramref name="width"/>, <paramref name="height"/> and
/// <paramref name="depth"/> in place.
/// </summary>
public static void GetTargetExtent(ref int width, ref int height, ref int depth,
int maxExtent, NvttRoundMode roundMode, NvttTextureType textureType,
NvttTimingContext* tc = null)
{
fixed (int* pw = &width, ph = &height, pd = &depth)
{
Api.nvttGetTargetExtent(pw, ph, pd, maxExtent, roundMode, textureType, tc);
}
}
/// <summary>
/// Returns the number of mip levels that can be generated for the given
/// base dimensions.
/// </summary>
public static int CountMipmaps(int w, int h, int d,
NvttTimingContext* tc = null)
=> Api.nvttCountMipmaps(w, h, d, tc);
}

View File

@@ -1,67 +0,0 @@
using System.Runtime.CompilerServices;
using System.Text;
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Internal helpers for converting between managed and unmanaged types.
/// </summary>
internal static unsafe class NvttInterop
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static NvttBoolean ToNvtt(bool value)
=> value ? NvttBoolean.NVTT_True : NvttBoolean.NVTT_False;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool ToBool(NvttBoolean value)
=> value != NvttBoolean.NVTT_False;
// -------------------------------------------------------------------------
// String to UTF-8 sbyte*
//
// Usage pattern:
// fixed (byte* ptr = NvttInterop.ToUtf8(str, stackalloc byte[MaxStack]))
// Api.nvttSomething((sbyte*)ptr);
//
// For paths longer than MaxStack bytes the helper falls back to a heap
// allocation via Encoding.UTF8.GetBytes. The Span<byte> overload lets the
// caller decide the stackalloc size.
// -------------------------------------------------------------------------
internal const int _MAX_STACK_PATH = 512;
/// <summary>
/// Encode <paramref name="value"/> as null-terminated UTF-8 into
/// <paramref name="buffer"/>. Returns the used portion (including the
/// null terminator). If the buffer is too small a new heap array is
/// returned instead.
/// </summary>
internal static Span<byte> ToUtf8(string value, Span<byte> buffer)
{
var needed = Encoding.UTF8.GetByteCount(value) + 1; // +1 for null term
if (needed > buffer.Length)
{
buffer = new byte[needed];
}
var written = Encoding.UTF8.GetBytes(value, buffer);
buffer[written] = 0; // null terminator
return buffer[..(written + 1)];
}
internal static string? FromUtf8(sbyte* ptr)
{
if (ptr == null)
{
return null;
}
var len = 0;
while (ptr[len] != 0)
{
len++;
}
return Encoding.UTF8.GetString((byte*)ptr, len);
}
}

View File

@@ -1,210 +0,0 @@
using System.Runtime.InteropServices;
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Configures where compressed data is written and how it is formatted.
///
/// Managed callback delegates are stored in this object and passed to the
/// native library via <see cref="Marshal.GetFunctionPointerForDelegate"/>.
/// The delegates are kept alive by pinned <see cref="GCHandle"/> instances
/// for the lifetime of this object.
/// </summary>
public sealed unsafe class NvttOutputOptionsHandle : IDisposable
{
private NvttOutputOptions* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttOutputOptions* Ptr => _ptr;
// -------------------------------------------------------------------------
// Managed callback storage
// -------------------------------------------------------------------------
// Delegate types that match the native C signatures exactly.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void BeginImageDelegate(int size, int width, int height, int depth, int face, int mipLevel);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate NvttBoolean OutputDataDelegate(void* data, int size, NvttBoolean lastChunk);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ErrorDelegate(NvttError error);
// Pinned delegate instances - must stay alive as long as native code may call them.
private BeginImageDelegate? _beginImageDelegate;
private OutputDataDelegate? _outputDataDelegate;
private ErrorDelegate? _errorDelegate;
// Managed user-facing callbacks.
private Action<int, int, int, int, int, int>? _beginImage;
private Func<nint, int, bool>? _outputData;
private Action? _endImage;
private Action<NvttError>? _errorHandler;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttOutputOptionsHandle() => _ptr = Api.nvttCreateOutputOptions();
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroyOutputOptions(_ptr);
_ptr = null;
}
// Release delegate references so GC can collect them.
_beginImageDelegate = null;
_outputDataDelegate = null;
_errorDelegate = null;
}
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
/// <summary>
/// Path of the output file. The file is created/overwritten when
/// compression runs.
/// </summary>
public string FileName
{
set
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(value, buf);
fixed (byte* p = utf8)
{
Api.nvttSetOutputOptionsFileName(_ptr, (sbyte*)p);
}
}
}
/// <summary>
/// Whether to write a DDS / KTX file header. Default is <c>true</c>.
/// </summary>
public bool OutputHeader
{
set { ThrowIfDisposed(); Api.nvttSetOutputOptionsOutputHeader(_ptr, NvttInterop.ToNvtt(value)); }
}
/// <summary>Container format (DDS or DDS10).</summary>
public NvttContainer Container
{
set { ThrowIfDisposed(); Api.nvttSetOutputOptionsContainer(_ptr, value); }
}
/// <summary>Application-defined version number stored in the header.</summary>
public int UserVersion
{
set { ThrowIfDisposed(); Api.nvttSetOutputOptionsUserVersion(_ptr, value); }
}
/// <summary>Sets the sRGB flag in the output header.</summary>
public bool Srgb
{
set { ThrowIfDisposed(); Api.nvttSetOutputOptionsSrgbFlag(_ptr, NvttInterop.ToNvtt(value)); }
}
// -------------------------------------------------------------------------
// Methods
// -------------------------------------------------------------------------
/// <summary>Resets all options to their default values.</summary>
public void Reset()
{
ThrowIfDisposed();
Api.nvttResetOutputOptions(_ptr);
}
/// <summary>
/// Installs managed callbacks that receive the compressed data stream.
///
/// <para><paramref name="beginImage"/> is called once per mip level before any
/// data arrives: <c>(size, width, height, depth, face, mipLevel)</c>.</para>
/// <para><paramref name="outputData"/> receives each chunk of compressed bytes.
/// The first argument is an <see cref="nint"/> pointing to the data, the
/// second is the byte count. Return <c>true</c> to continue, <c>false</c>
/// to abort.</para>
/// <para><paramref name="endImage"/> is called once after the last chunk.</para>
///
/// Only one set of output callbacks can be active at a time; calling this
/// method again replaces the previous ones.
/// </summary>
public void SetOutputHandler(
Action<int, int, int, int, int, int>? beginImage,
Func<nint, int, bool>? outputData,
Action? endImage)
{
ThrowIfDisposed();
_beginImage = beginImage;
_outputData = outputData;
_endImage = endImage;
RebindOutputHandler();
}
/// <summary>
/// Installs a managed error handler. The handler is invoked with the
/// <see cref="NvttError"/> code whenever the native library encounters an
/// error.
/// </summary>
public void SetErrorHandler(Action<NvttError>? handler)
{
ThrowIfDisposed();
_errorHandler = handler;
RebindErrorHandler();
}
// -------------------------------------------------------------------------
// Internal delegate trampolines (instance-bound via closures)
// -------------------------------------------------------------------------
private void RebindOutputHandler()
{
// Capture current callbacks into local vars for the closure.
var beginImage = _beginImage;
var outputData = _outputData;
_beginImageDelegate = (size, width, height, depth, face, mipLevel) =>
beginImage?.Invoke(size, width, height, depth, face, mipLevel);
_outputDataDelegate = (data, size, lastChunk) =>
{
var ok = outputData?.Invoke((nint)data, size) ?? true;
return ok ? Ghost.Nvtt.NvttBoolean.NVTT_True : Ghost.Nvtt.NvttBoolean.NVTT_False;
};
var beginPtr = Marshal.GetFunctionPointerForDelegate(_beginImageDelegate);
var outputPtr = Marshal.GetFunctionPointerForDelegate(_outputDataDelegate);
Api.nvttSetOutputOptionsOutputHandler(
_ptr,
(delegate* unmanaged[Cdecl]<int, int, int, int, int, int, void>)beginPtr,
(delegate* unmanaged[Cdecl]<void*, int, NvttBoolean>)outputPtr,
IntPtr.Zero);
}
private void RebindErrorHandler()
{
var handler = _errorHandler;
_errorDelegate = error => handler?.Invoke(error);
var errorPtr = Marshal.GetFunctionPointerForDelegate(_errorDelegate);
Api.nvttSetOutputOptionsErrorHandler(
_ptr,
(delegate* unmanaged[Cdecl]<NvttError, void>)errorPtr);
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttOutputOptionsHandle));
}
}
}

View File

@@ -0,0 +1,95 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttOutputOptions : System.IDisposable
{
// From: nvttCreateOutputOptions()
public static NvttOutputOptions* Create()
{
return Api.nvttCreateOutputOptions();
}
// From: nvttDestroyOutputOptions(NvttOutputOptions*)
public void Dispose()
{
Api.nvttDestroyOutputOptions((NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttResetOutputOptions(NvttOutputOptions*)
public void Reset()
{
Api.nvttResetOutputOptions((NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSetOutputOptionsFileName(NvttOutputOptions*, sbyte*)
public void SetFileName(ReadOnlySpan<byte> fileName)
{
fixed (byte* pfileName = fileName)
{
Api.nvttSetOutputOptionsFileName(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(sbyte*)pfileName);
}
}
// From: nvttSetOutputOptionsFileHandle(NvttOutputOptions*, void*)
public void SetFileHandle(void* fp)
{
Api.nvttSetOutputOptionsFileHandle(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
fp);
}
// From: nvttSetOutputOptionsOutputHandler(NvttOutputOptions*, delegate* unmanaged[Cdecl]<int, int, int, int, int, int, void>, delegate* unmanaged[Cdecl]<void*, int, NvttBoolean>, IntPtr)
public void SetOutputHandler(delegate* unmanaged[Cdecl]<int, int, int, int, int, int, void> beginImageHandler, delegate* unmanaged[Cdecl]<void*, int, NvttBoolean> outputHandler, IntPtr endImageHandler)
{
Api.nvttSetOutputOptionsOutputHandler(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
beginImageHandler,
outputHandler,
endImageHandler);
}
// From: nvttSetOutputOptionsErrorHandler(NvttOutputOptions*, delegate* unmanaged[Cdecl]<NvttError, void>)
public void SetErrorHandler(delegate* unmanaged[Cdecl]<NvttError, void> errorHandler)
{
Api.nvttSetOutputOptionsErrorHandler(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
errorHandler);
}
// From: nvttSetOutputOptionsOutputHeader(NvttOutputOptions*, NvttBoolean)
public void SetOutputHeader(NvttBoolean b)
{
Api.nvttSetOutputOptionsOutputHeader(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
b);
}
// From: nvttSetOutputOptionsContainer(NvttOutputOptions*, NvttContainer)
public void SetContainer(NvttContainer container)
{
Api.nvttSetOutputOptionsContainer(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
container);
}
// From: nvttSetOutputOptionsUserVersion(NvttOutputOptions*, int)
public void SetUserVersion(int version)
{
Api.nvttSetOutputOptionsUserVersion(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
version);
}
// From: nvttSetOutputOptionsSrgbFlag(NvttOutputOptions*, NvttBoolean)
public void SetSrgbFlag(NvttBoolean b)
{
Api.nvttSetOutputOptionsSrgbFlag(
(NvttOutputOptions*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
b);
}
}

View File

@@ -0,0 +1,42 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttRefImage
{
// From: nvttCreateCPUInputBuffer(NvttRefImage*, NvttValueType, int, int, int, float, float, float, float, NvttTimingContext*, uint*)
public NvttCPUInputBuffer* CreateCPUInputBuffer(NvttValueType value_type, int numImages, int tile_w, int tile_h, float WeightR, float WeightG, float WeightB, float WeightA, NvttTimingContext* tc, uint* num_tiles)
{
return Api.nvttCreateCPUInputBuffer(
(NvttRefImage*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
value_type,
numImages,
tile_w,
tile_h,
WeightR,
WeightG,
WeightB,
WeightA,
tc,
num_tiles);
}
// From: nvttCreateGPUInputBuffer(NvttRefImage*, NvttValueType, int, int, int, float, float, float, float, NvttTimingContext*, uint*)
public NvttGPUInputBuffer* CreateGPUInputBuffer(NvttValueType value_type, int numImages, int tile_w, int tile_h, float WeightR, float WeightG, float WeightB, float WeightA, NvttTimingContext* tc, uint* num_tiles)
{
return Api.nvttCreateGPUInputBuffer(
(NvttRefImage*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
value_type,
numImages,
tile_w,
tile_h,
WeightR,
WeightG,
WeightB,
WeightA,
tc,
num_tiles);
}
}

View File

@@ -1,712 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Wrapper around a single 2-D / 3-D / cube-face image surface used as input
/// to the compression pipeline.
///
/// Most mutating methods accept an optional <paramref name="tc"/> timing
/// context. Pass <c>null</c> (the default) to skip timing.
/// </summary>
public sealed unsafe class NvttSurfaceHandle : IDisposable
{
private NvttSurface* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttSurface* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttSurfaceHandle() => _ptr = Api.nvttCreateSurface();
/// <summary>Wraps an existing raw pointer (takes ownership; will destroy on dispose).</summary>
internal NvttSurfaceHandle(NvttSurface* existing) => _ptr = existing;
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroySurface(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// Clone / sub-image
// -------------------------------------------------------------------------
/// <summary>Returns a deep copy of this surface.</summary>
public NvttSurfaceHandle Clone()
{
ThrowIfDisposed();
return new NvttSurfaceHandle(Api.nvttSurfaceClone(_ptr));
}
/// <summary>
/// Extracts a rectangular sub-region into a new <see cref="NvttSurfaceHandle"/>.
/// </summary>
public NvttSurfaceHandle CreateSubImage(
int x0, int x1, int y0, int y1, int z0, int z1,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return new NvttSurfaceHandle(Api.nvttSurfaceCreateSubImage(_ptr, x0, x1, y0, y1, z0, z1, tc));
}
// -------------------------------------------------------------------------
// Read-only properties
// -------------------------------------------------------------------------
/// <summary>Returns <c>true</c> when the surface holds no data.</summary>
public bool IsNull
{
get { ThrowIfDisposed(); return NvttInterop.ToBool(Api.nvttSurfaceIsNull(_ptr)); }
}
/// <summary>Image width in pixels.</summary>
public int Width
{
get { ThrowIfDisposed(); return Api.nvttSurfaceWidth(_ptr); }
}
/// <summary>Image height in pixels.</summary>
public int Height
{
get { ThrowIfDisposed(); return Api.nvttSurfaceHeight(_ptr); }
}
/// <summary>Image depth (1 for 2-D textures).</summary>
public int Depth
{
get { ThrowIfDisposed(); return Api.nvttSurfaceDepth(_ptr); }
}
/// <summary>Texture dimensionality.</summary>
public NvttTextureType TextureType
{
get { ThrowIfDisposed(); return Api.nvttSurfaceType(_ptr); }
}
/// <summary>Whether the surface contains a normal map.</summary>
public bool IsNormalMap
{
get { ThrowIfDisposed(); return NvttInterop.ToBool(Api.nvttSurfaceIsNormalMap(_ptr)); }
}
// -------------------------------------------------------------------------
// Settable properties
// -------------------------------------------------------------------------
/// <summary>UV wrap mode used when filtering near edges.</summary>
public NvttWrapMode WrapMode
{
get { ThrowIfDisposed(); return Api.nvttSurfaceWrapMode(_ptr); }
}
/// <summary>Alpha mode interpretation.</summary>
public NvttAlphaMode AlphaMode
{
get { ThrowIfDisposed(); return Api.nvttSurfaceAlphaMode(_ptr); }
}
// -------------------------------------------------------------------------
// Query methods
// -------------------------------------------------------------------------
/// <summary>
/// Returns the number of mip levels that can be generated down to
/// <paramref name="minSize"/> pixels on the smallest side.
/// </summary>
public int CountMipmaps(int minSize = 1)
{
ThrowIfDisposed();
return Api.nvttSurfaceCountMipmaps(_ptr, minSize);
}
/// <summary>Alpha-test coverage for the given reference value and channel.</summary>
public float AlphaTestCoverage(float alphaRef, int alphaChannel = 3)
{
ThrowIfDisposed();
return Api.nvttSurfaceAlphaTestCoverage(_ptr, alphaRef, alphaChannel);
}
/// <summary>Per-channel average luminance.</summary>
public float Average(int channel, int alphaChannel = 3, float gamma = 2.2f)
{
ThrowIfDisposed();
return Api.nvttSurfaceAverage(_ptr, channel, alphaChannel, gamma);
}
/// <summary>
/// Returns a pointer to the raw float data for all four channels interleaved.
/// The span is valid only while this surface is alive.
/// </summary>
public Span<float> Data
{
get
{
ThrowIfDisposed();
var p = Api.nvttSurfaceData(_ptr);
var count = Width * Height * Depth * 4;
return p == null ? Span<float>.Empty : new Span<float>(p, count);
}
}
/// <summary>
/// Returns a pointer to the raw float data for a single channel (0=R,1=G,2=B,3=A).
/// The span is valid only while this surface is alive.
/// </summary>
public Span<float> Channel(int index)
{
ThrowIfDisposed();
var p = Api.nvttSurfaceChannel(_ptr, index);
var count = Width * Height * Depth;
return p == null ? Span<float>.Empty : new Span<float>(p, count);
}
/// <summary>Populates a histogram array for the given channel.</summary>
public void Histogram(int channel, float rangeMin, float rangeMax, Span<int> bins,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (int* b = bins)
{
Api.nvttSurfaceHistogram(_ptr, channel, rangeMin, rangeMax, bins.Length, b, tc);
}
}
/// <summary>Returns the minimum and maximum values of a channel.</summary>
public void Range(int channel, out float min, out float max,
int alphaChannel = 3, float alphaRef = 0f,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
float lo, hi;
Api.nvttSurfaceRange(_ptr, channel, &lo, &hi, alphaChannel, alphaRef, tc);
min = lo;
max = hi;
}
// -------------------------------------------------------------------------
// Load / Save
// -------------------------------------------------------------------------
/// <summary>Loads an image from disk. Returns <c>false</c> on failure.</summary>
public bool Load(string fileName, out bool hasAlpha, bool expectSigned = false,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(fileName, buf);
fixed (byte* p = utf8)
{
NvttBoolean nvAlpha;
var ok = NvttInterop.ToBool(
Api.nvttSurfaceLoad(_ptr, (sbyte*)p, &nvAlpha,
NvttInterop.ToNvtt(expectSigned), tc));
hasAlpha = NvttInterop.ToBool(nvAlpha);
return ok;
}
}
/// <summary>Loads an image from a managed byte array. Returns <c>false</c> on failure.</summary>
public bool LoadFromMemory(ReadOnlySpan<byte> data, out bool hasAlpha,
bool expectSigned = false, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (byte* p = data)
{
NvttBoolean nvAlpha;
var ok = NvttInterop.ToBool(
Api.nvttSurfaceLoadFromMemory(_ptr, p, (ulong)data.Length,
&nvAlpha, NvttInterop.ToNvtt(expectSigned), tc));
hasAlpha = NvttInterop.ToBool(nvAlpha);
return ok;
}
}
/// <summary>Saves the surface to disk. Returns <c>false</c> on failure.</summary>
public bool Save(string fileName, bool hasAlpha = false, bool hdr = false,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(fileName, buf);
fixed (byte* p = utf8)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSave(_ptr, (sbyte*)p,
NvttInterop.ToNvtt(hasAlpha), NvttInterop.ToNvtt(hdr), tc));
}
}
// -------------------------------------------------------------------------
// Set image data
// -------------------------------------------------------------------------
/// <summary>Allocates an empty surface of the given dimensions.</summary>
public bool SetImage(int w, int h, int d = 1, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return NvttInterop.ToBool(Api.nvttSurfaceSetImage(_ptr, w, h, d, tc));
}
/// <summary>Sets the surface from interleaved RGBA data.</summary>
public bool SetImageData(NvttInputFormat format, int w, int h, int d,
ReadOnlySpan<byte> data, bool unsignedToSigned = false,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (byte* p = data)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetImageData(_ptr, format, w, h, d, p,
NvttInterop.ToNvtt(unsignedToSigned), tc));
}
}
/// <summary>Sets the surface from separate RGBA channel planes.</summary>
public bool SetImageRGBA(NvttInputFormat format, int w, int h, int d,
ReadOnlySpan<byte> r, ReadOnlySpan<byte> g,
ReadOnlySpan<byte> b, ReadOnlySpan<byte> a,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (byte* pr = r, pg = g, pb = b, pa = a)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetImageRGBA(_ptr, format, w, h, d, pr, pg, pb, pa, tc));
}
}
/// <summary>Sets the surface from a compressed 2-D image.</summary>
public bool SetImage2D(NvttFormat format, int w, int h,
ReadOnlySpan<byte> data, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (byte* p = data)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetImage2D(_ptr, format, w, h, p, tc));
}
}
/// <summary>Sets the surface from a compressed 3-D image.</summary>
public bool SetImage3D(NvttFormat format, int w, int h, int d,
ReadOnlySpan<byte> data, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (byte* p = data)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetImage3D(_ptr, format, w, h, d, p, tc));
}
}
// -------------------------------------------------------------------------
// Resize / mipmap
// -------------------------------------------------------------------------
/// <summary>Resizes the surface to the exact dimensions given.</summary>
public void Resize(int w, int h, int d, NvttResizeFilter filter,
float filterWidth = 1f, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceResize(_ptr, w, h, d, filter, filterWidth, null, tc);
}
/// <summary>Resizes so that the longest extent is at most <paramref name="maxExtent"/>.</summary>
public void ResizeMax(int maxExtent, NvttRoundMode mode, NvttResizeFilter filter,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceResizeMax(_ptr, maxExtent, mode, filter, tc);
}
/// <summary>Resizes to a square texture with side at most <paramref name="maxExtent"/>.</summary>
public void ResizeMakeSquare(int maxExtent, NvttRoundMode mode, NvttResizeFilter filter,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceResizeMakeSquare(_ptr, maxExtent, mode, filter, tc);
}
/// <summary>Pads or crops the canvas to the given dimensions without resampling.</summary>
public void CanvasSize(int w, int h, int d, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceCanvasSize(_ptr, w, h, d, tc);
}
/// <summary>Returns <c>true</c> if a next mip level can still be generated.</summary>
public bool CanMakeNextMipmap(int minSize = 1)
{
ThrowIfDisposed();
return NvttInterop.ToBool(Api.nvttSurfaceCanMakeNextMipmap(_ptr, minSize));
}
/// <summary>Generates the next mip level in place (downsamples by 2).</summary>
public bool BuildNextMipmap(NvttMipmapFilter filter, int minSize = 1,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttSurfaceBuildNextMipmapDefaults(_ptr, filter, minSize, tc));
}
/// <summary>Generates the next mip level using a solid colour.</summary>
public bool BuildNextMipmapSolidColor(float r, float g, float b, float a,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
var color = stackalloc float[4] { r, g, b, a };
return NvttInterop.ToBool(
Api.nvttSurfaceBuildNextMipmapSolidColor(_ptr, color, tc));
}
// -------------------------------------------------------------------------
// Colour-space conversions
// -------------------------------------------------------------------------
/// <summary>Converts from sRGB to linear (per-channel).</summary>
public void ToLinearFromSrgb(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToLinearFromSrgb(_ptr, tc);
}
/// <summary>Converts from linear to sRGB (clamped).</summary>
public void ToSrgb(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToSrgb(_ptr, tc);
}
/// <summary>Converts from sRGB to linear (unclamped).</summary>
public void ToLinearFromSrgbUnclamped(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToLinearFromSrgbUnclamped(_ptr, tc);
}
/// <summary>Converts from linear to sRGB (unclamped).</summary>
public void ToSrgbUnclamped(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToSrgbUnclamped(_ptr, tc);
}
/// <summary>Applies gamma expansion (toLinear) to all channels.</summary>
public void ToLinear(float gamma, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToLinear(_ptr, gamma, tc);
}
/// <summary>Applies gamma compression to all channels.</summary>
public void ToGamma(float gamma, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToGamma(_ptr, gamma, tc);
}
/// <summary>Applies gamma expansion to a single channel.</summary>
public void ToLinearChannel(int channel, float gamma, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToLinearChannel(_ptr, channel, gamma, tc);
}
/// <summary>Applies gamma compression to a single channel.</summary>
public void ToGammaChannel(int channel, float gamma, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToGammaChannel(_ptr, channel, gamma, tc);
}
// -------------------------------------------------------------------------
// Pixel operations
// -------------------------------------------------------------------------
/// <summary>Applies a 4×4 colour transform matrix plus per-channel offset.</summary>
public void Transform(
float[] w0, float[] w1, float[] w2, float[] w3, float[] offset,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
fixed (float* pw0 = w0, pw1 = w1, pw2 = w2, pw3 = w3, po = offset)
{
Api.nvttSurfaceTransform(_ptr, pw0, pw1, pw2, pw3, po, tc);
}
}
/// <summary>Rearranges channels: result[0]=src[r], result[1]=src[g], etc.</summary>
public void Swizzle(int r, int g, int b, int a, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceSwizzle(_ptr, r, g, b, a, tc);
}
/// <summary>Applies <c>x = x * scale + bias</c> to a single channel.</summary>
public void ScaleBias(int channel, float scale, float bias,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceScaleBias(_ptr, channel, scale, bias, tc);
}
/// <summary>Clamps a channel to [<paramref name="low"/>, <paramref name="high"/>].</summary>
public void Clamp(int channel, float low, float high, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceClamp(_ptr, channel, low, high, tc);
}
/// <summary>Blends toward a constant RGBA colour by factor <paramref name="t"/>.</summary>
public void Blend(float r, float g, float b, float a, float t,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceBlend(_ptr, r, g, b, a, t, tc);
}
/// <summary>Multiplies RGB by alpha.</summary>
public void PremultiplyAlpha(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfacePremultiplyAlpha(_ptr, tc);
}
/// <summary>Divides RGB by alpha (with epsilon guard against divide-by-zero).</summary>
public void DemultiplyAlpha(float epsilon = 1e-6f, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceDemultiplyAlpha(_ptr, epsilon, tc);
}
/// <summary>Converts to greyscale by weighted sum of channels.</summary>
public void ToGreyScale(float redScale, float greenScale, float blueScale,
float alphaScale, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceToGreyScale(_ptr, redScale, greenScale, blueScale, alphaScale, tc);
}
/// <summary>Fills the edge border of the surface with the given colour.</summary>
public void SetBorder(float r, float g, float b, float a,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceSetBorder(_ptr, r, g, b, a, tc);
}
/// <summary>Fills the entire surface with a constant colour.</summary>
public void Fill(float r, float g, float b, float a, NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFill(_ptr, r, g, b, a, tc);
}
/// <summary>Scales alpha so that alpha-test coverage matches the given target.</summary>
public void ScaleAlphaToCoverage(float coverage, float alphaRef = 0.5f,
int alphaChannel = 3, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceScaleAlphaToCoverage(_ptr, coverage, alphaRef, alphaChannel, tc);
}
// -------------------------------------------------------------------------
// HDR encodings
// -------------------------------------------------------------------------
/// <summary>Encodes to RGBM (RGB * M, M in alpha).</summary>
public void ToRGBM(float range = 6f, float threshold = 0.25f,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToRGBM(_ptr, range, threshold, tc);
}
/// <summary>Decodes from RGBM back to linear HDR.</summary>
public void FromRGBM(float range = 6f, float threshold = 0.25f,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFromRGBM(_ptr, range, threshold, tc);
}
/// <summary>Encodes to RGBE (Radiance HDR format).</summary>
public void ToRGBE(int mantissaBits = 9, int exponentBits = 5,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToRGBE(_ptr, mantissaBits, exponentBits, tc);
}
/// <summary>Decodes from RGBE back to linear HDR.</summary>
public void FromRGBE(int mantissaBits = 9, int exponentBits = 5,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFromRGBE(_ptr, mantissaBits, exponentBits, tc);
}
/// <summary>Converts to YCoCg colour space.</summary>
public void ToYCoCg(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToYCoCg(_ptr, tc);
}
/// <summary>Converts from YCoCg back to RGB.</summary>
public void FromYCoCg(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFromYCoCg(_ptr, tc);
}
// -------------------------------------------------------------------------
// Normal-map operations
// -------------------------------------------------------------------------
/// <summary>
/// Generates a normal map from the surface (treated as a height map)
/// using four blur kernel sizes.
/// </summary>
public void ToNormalMap(float sm, float medium, float big, float large,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceToNormalMap(_ptr, sm, medium, big, large, tc);
}
/// <summary>Re-normalises all normal vectors in the surface.</summary>
public void NormalizeNormalMap(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceNormalizeNormalMap(_ptr, tc);
}
/// <summary>Applies a normal-space transform.</summary>
public void TransformNormals(NvttNormalTransform xform,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceTransformNormals(_ptr, xform, tc);
}
/// <summary>Reconstructs normals from a packed representation.</summary>
public void ReconstructNormals(NvttNormalTransform xform,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceReconstructNormals(_ptr, xform, tc);
}
/// <summary>Packs normals into [0,1] range using <c>n*scale+bias</c>.</summary>
public void PackNormals(float scale = 0.5f, float bias = 0.5f,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfacePackNormals(_ptr, scale, bias, tc);
}
/// <summary>Expands packed normals back to [-1,1] range.</summary>
public void ExpandNormals(float scale = 2f, float bias = -1f,
NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceExpandNormals(_ptr, scale, bias, tc);
}
/// <summary>
/// Creates a Toksvig specular power map from a normal map.
/// Caller owns the returned surface.
/// </summary>
public NvttSurfaceHandle CreateToksvigMap(float power, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return new NvttSurfaceHandle(Api.nvttSurfaceCreateToksvigMap(_ptr, power, tc));
}
// -------------------------------------------------------------------------
// Flip
// -------------------------------------------------------------------------
/// <summary>Flips the surface along the X axis.</summary>
public void FlipX(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFlipX(_ptr, tc);
}
/// <summary>Flips the surface along the Y axis.</summary>
public void FlipY(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFlipY(_ptr, tc);
}
/// <summary>Flips the surface along the Z axis.</summary>
public void FlipZ(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceFlipZ(_ptr, tc);
}
// -------------------------------------------------------------------------
// Channel copy / add
// -------------------------------------------------------------------------
/// <summary>Copies a single channel from another surface.</summary>
public bool CopyChannel(NvttSurfaceHandle src, int srcChannel, int dstChannel,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttSurfaceCopyChannel(_ptr, src.Ptr, srcChannel, dstChannel, tc));
}
/// <summary>Adds a scaled channel from another surface into this one.</summary>
public bool AddChannel(NvttSurfaceHandle src, int srcChannel, int dstChannel,
float scale = 1f, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttSurfaceAddChannel(_ptr, src.Ptr, srcChannel, dstChannel, scale, tc));
}
/// <summary>Copies a rectangular region from another surface into this one.</summary>
public bool Copy(NvttSurfaceHandle src,
int xsrc, int ysrc, int zsrc,
int xsize, int ysize, int zsize,
int xdst, int ydst, int zdst,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
return NvttInterop.ToBool(
Api.nvttSurfaceCopy(_ptr, src.Ptr,
xsrc, ysrc, zsrc, xsize, ysize, zsize, xdst, ydst, zdst, tc));
}
// -------------------------------------------------------------------------
// GPU transfer
// -------------------------------------------------------------------------
/// <summary>Uploads the surface to the GPU (CUDA). <paramref name="performCopy"/> clones instead of moving.</summary>
public void ToGPU(bool performCopy = false, NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceToGPU(_ptr, NvttInterop.ToNvtt(performCopy), tc);
}
/// <summary>Downloads the surface back to CPU memory.</summary>
public void ToCPU(NvttTimingContext* tc = null)
{
ThrowIfDisposed(); Api.nvttSurfaceToCPU(_ptr, tc);
}
// -------------------------------------------------------------------------
// Quantize / binarize
// -------------------------------------------------------------------------
/// <summary>Quantizes a channel to the given bit depth.</summary>
public void Quantize(int channel, int bits,
bool exactEndPoints = false, bool dither = false,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceQuantize(_ptr, channel, bits,
NvttInterop.ToNvtt(exactEndPoints), NvttInterop.ToNvtt(dither), tc);
}
/// <summary>Binarizes a channel using a threshold.</summary>
public void Binarize(int channel, float threshold, bool dither = false,
NvttTimingContext* tc = null)
{
ThrowIfDisposed();
Api.nvttSurfaceBinarize(_ptr, channel, threshold,
NvttInterop.ToNvtt(dither), tc);
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttSurfaceHandle));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,144 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Wrapper around an nvtt surface set — a collection of faces and mip levels
/// loaded from a DDS file or built programmatically.
/// </summary>
public sealed unsafe class NvttSurfaceSetHandle : IDisposable
{
private NvttSurfaceSet* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttSurfaceSet* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
public NvttSurfaceSetHandle() => _ptr = Api.nvttCreateSurfaceSet();
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroySurfaceSet(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// Read-only properties
// -------------------------------------------------------------------------
/// <summary>Texture dimensionality stored in this set.</summary>
public NvttTextureType TextureType
{
get { ThrowIfDisposed(); return Api.nvttSurfaceSetGetTextureType(_ptr); }
}
/// <summary>Number of faces (1 for 2-D / 3-D, 6 for cube maps).</summary>
public int FaceCount
{
get { ThrowIfDisposed(); return Api.nvttSurfaceSetGetFaceCount(_ptr); }
}
/// <summary>Number of mip levels.</summary>
public int MipmapCount
{
get { ThrowIfDisposed(); return Api.nvttSurfaceSetGetMipmapCount(_ptr); }
}
/// <summary>Width of the base (mip 0) image in pixels.</summary>
public int Width
{
get { ThrowIfDisposed(); return Api.nvttSurfaceSetGetWidth(_ptr); }
}
/// <summary>Height of the base (mip 0) image in pixels.</summary>
public int Height
{
get { ThrowIfDisposed(); return Api.nvttSurfaceSetGetHeight(_ptr); }
}
/// <summary>Depth of the base (mip 0) image (1 for 2-D textures).</summary>
public int Depth
{
get { ThrowIfDisposed(); return Api.nvttSurfaceSetGetDepth(_ptr); }
}
// -------------------------------------------------------------------------
// Surface access
// -------------------------------------------------------------------------
/// <summary>
/// Returns the raw <see cref="NvttSurface"/> pointer for the given face
/// and mip level. The pointer is owned by this surface set - do NOT dispose
/// it.
/// </summary>
public NvttSurface* GetSurfacePtr(int faceId, int mipId, bool expectSigned = false)
{
ThrowIfDisposed();
return Api.nvttSurfaceSetGetSurface(_ptr, faceId, mipId,
NvttInterop.ToNvtt(expectSigned));
}
// -------------------------------------------------------------------------
// Load / Save
// -------------------------------------------------------------------------
/// <summary>Resets the surface set to an empty state.</summary>
public void Reset()
{
ThrowIfDisposed();
Api.nvttResetSurfaceSet(_ptr);
}
/// <summary>Loads from a DDS file. Returns <c>false</c> on failure.</summary>
public bool LoadDDS(string fileName, bool forceNormal = false)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(fileName, buf);
fixed (byte* p = utf8)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetLoadDDS(_ptr, (sbyte*)p,
NvttInterop.ToNvtt(forceNormal)));
}
}
/// <summary>Loads from a managed byte array containing DDS data. Returns <c>false</c> on failure.</summary>
public bool LoadDDSFromMemory(ReadOnlySpan<byte> data, bool forceNormal = false)
{
ThrowIfDisposed();
fixed (byte* p = data)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetLoadDDSFromMemory(_ptr, p, (ulong)data.Length,
NvttInterop.ToNvtt(forceNormal)));
}
}
/// <summary>Saves a single face/mip as an image file. Returns <c>false</c> on failure.</summary>
public bool SaveImage(string fileName, int faceId, int mipId)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[NvttInterop._MAX_STACK_PATH];
var utf8 = NvttInterop.ToUtf8(fileName, buf);
fixed (byte* p = utf8)
{
return NvttInterop.ToBool(
Api.nvttSurfaceSetSaveImage(_ptr, (sbyte*)p, faceId, mipId));
}
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttSurfaceSetHandle));
}
}
}

View File

@@ -0,0 +1,107 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttSurfaceSet : System.IDisposable
{
// From: nvttCreateSurfaceSet()
public static NvttSurfaceSet* Create()
{
return Api.nvttCreateSurfaceSet();
}
// From: nvttDestroySurfaceSet(NvttSurfaceSet*)
public void Dispose()
{
Api.nvttDestroySurfaceSet((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttResetSurfaceSet(NvttSurfaceSet*)
public void Reset()
{
Api.nvttResetSurfaceSet((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetTextureType(NvttSurfaceSet*)
public NvttTextureType GetTextureType()
{
return Api.nvttSurfaceSetGetTextureType((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetFaceCount(NvttSurfaceSet*)
public int GetFaceCount()
{
return Api.nvttSurfaceSetGetFaceCount((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetMipmapCount(NvttSurfaceSet*)
public int GetMipmapCount()
{
return Api.nvttSurfaceSetGetMipmapCount((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetWidth(NvttSurfaceSet*)
public int GetWidth()
{
return Api.nvttSurfaceSetGetWidth((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetHeight(NvttSurfaceSet*)
public int GetHeight()
{
return Api.nvttSurfaceSetGetHeight((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetDepth(NvttSurfaceSet*)
public int GetDepth()
{
return Api.nvttSurfaceSetGetDepth((NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttSurfaceSetGetSurface(NvttSurfaceSet*, int, int, NvttBoolean)
public NvttSurface* GetSurface(int faceId, int mipId, NvttBoolean expectSigned)
{
return Api.nvttSurfaceSetGetSurface(
(NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
faceId,
mipId,
expectSigned);
}
// From: nvttSurfaceSetLoadDDS(NvttSurfaceSet*, sbyte*, NvttBoolean)
public NvttBoolean LoadDDS(ReadOnlySpan<byte> fileName, NvttBoolean forcenormal)
{
fixed (byte* pfileName = fileName)
{
return Api.nvttSurfaceSetLoadDDS(
(NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(sbyte*)pfileName,
forcenormal);
}
}
// From: nvttSurfaceSetLoadDDSFromMemory(NvttSurfaceSet*, void*, ulong, NvttBoolean)
public NvttBoolean LoadDDSFromMemory(void* data, ulong sizeInBytes, NvttBoolean forcenormal)
{
return Api.nvttSurfaceSetLoadDDSFromMemory(
(NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
data,
sizeInBytes,
forcenormal);
}
// From: nvttSurfaceSetSaveImage(NvttSurfaceSet*, sbyte*, int, int)
public NvttBoolean SaveImage(ReadOnlySpan<byte> fileName, int faceId, int mipId)
{
fixed (byte* pfileName = fileName)
{
return Api.nvttSurfaceSetSaveImage(
(NvttSurfaceSet*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
(sbyte*)pfileName,
faceId,
mipId);
}
}
}

View File

@@ -1,99 +0,0 @@
namespace Ghost.Nvtt.Wrapper;
/// <summary>
/// Wraps an nvtt timing context that records per-operation wall-clock times.
/// Obtain one from <see cref="NvttContext.TimingContext"/> or create a
/// standalone instance and pass it as the optional <c>tc</c> parameter on
/// surface methods.
/// </summary>
public sealed unsafe class NvttTimingContextHandle : IDisposable
{
private NvttTimingContext* _ptr;
/// <summary>Raw pointer - use only when calling the native API directly.</summary>
public NvttTimingContext* Ptr => _ptr;
// -------------------------------------------------------------------------
// Construction / destruction
// -------------------------------------------------------------------------
/// <summary>Creates a timing context at the specified detail level (0 = off, higher = more detail).</summary>
public NvttTimingContextHandle(int detailLevel = 1)
=> _ptr = Api.nvttCreateTimingContext(detailLevel);
/// <summary>Wraps an already-owned native pointer (ownership transferred to this object).</summary>
internal NvttTimingContextHandle(NvttTimingContext* owned) => _ptr = owned;
public void Dispose()
{
if (_ptr != null)
{
Api.nvttDestroyTimingContext(_ptr);
_ptr = null;
}
}
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
/// <summary>
/// Sets the detail level (0 = disabled; higher values record more sub-operations).
/// </summary>
public int DetailLevel
{
set
{
ThrowIfDisposed();
Api.nvttTimingContextSetDetailLevel(_ptr, value);
}
}
/// <summary>Number of timing records captured so far.</summary>
public int RecordCount
{
get
{
ThrowIfDisposed();
return Api.nvttTimingContextGetRecordCount(_ptr);
}
}
// -------------------------------------------------------------------------
// Methods
// -------------------------------------------------------------------------
/// <summary>
/// Returns the description and elapsed seconds for the record at
/// <paramref name="index"/>.
/// </summary>
public (string description, double seconds) GetRecord(int index)
{
ThrowIfDisposed();
Span<byte> buf = stackalloc byte[256];
double seconds;
fixed (byte* p = buf)
{
Api.nvttTimingContextGetRecordSafe(_ptr, index, (sbyte*)p, (nuint)buf.Length, &seconds);
var desc = NvttInterop.FromUtf8((sbyte*)p) ?? string.Empty;
return (desc, seconds);
}
}
/// <summary>Prints all timing records to stdout via the native library.</summary>
public void PrintRecords()
{
ThrowIfDisposed();
Api.nvttTimingContextPrintRecords(_ptr);
}
// -------------------------------------------------------------------------
private void ThrowIfDisposed()
{
if (_ptr == null)
{
throw new ObjectDisposedException(nameof(NvttTimingContextHandle));
}
}
}

View File

@@ -0,0 +1,61 @@
// <auto-generated>
// This file is generated by Ghost.NativeWrapperGen. Do not edit manually.
// </auto-generated>
namespace Ghost.Nvtt;
public unsafe partial struct NvttTimingContext : System.IDisposable
{
// From: nvttCreateTimingContext(int)
public static NvttTimingContext* Create(int detailLevel)
{
return Api.nvttCreateTimingContext(detailLevel);
}
// From: nvttDestroyTimingContext(NvttTimingContext*)
public void Dispose()
{
Api.nvttDestroyTimingContext((NvttTimingContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttTimingContextSetDetailLevel(NvttTimingContext*, int)
public void SetDetailLevel(int detailLevel)
{
Api.nvttTimingContextSetDetailLevel(
(NvttTimingContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
detailLevel);
}
// From: nvttTimingContextGetRecordCount(NvttTimingContext*)
public int GetRecordCount()
{
return Api.nvttTimingContextGetRecordCount((NvttTimingContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
// From: nvttTimingContextGetRecord(NvttTimingContext*, int, sbyte*, double*)
public void GetRecord(int i, sbyte* description, double* seconds)
{
Api.nvttTimingContextGetRecord(
(NvttTimingContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
i,
description,
seconds);
}
// From: nvttTimingContextGetRecordSafe(NvttTimingContext*, int, sbyte*, nuint, double*)
public nuint GetRecordSafe(int i, sbyte* outDescription, nuint outDescriptionSize, double* seconds)
{
return Api.nvttTimingContextGetRecordSafe(
(NvttTimingContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this),
i,
outDescription,
outDescriptionSize,
seconds);
}
// From: nvttTimingContextPrintRecords(NvttTimingContext*)
public void PrintRecords()
{
Api.nvttTimingContextPrintRecords((NvttTimingContext*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref this));
}
}

View File

@@ -1,47 +0,0 @@
using System.Runtime.InteropServices;
namespace Ghost.Ufbx;
public unsafe partial class LoadOpts
{
public partial cstring ObjMtlPath
{
get => _objMtlPath;
set
{
_objMtlPath.Dispose();
_objMtlPath = new cstring(value);
_ptr->obj_mtl_path = new ufbx_string
{
data = (sbyte*)_objMtlPath.ptr,
length = (nuint)_objMtlPath.length,
};
}
}
public partial cstring Filename
{
get => _filename;
set
{
_filename.Dispose();
_filename = new cstring(value);
_ptr->filename = new ufbx_string
{
data = (sbyte*)_filename.ptr,
length = (nuint)_filename.length,
};
}
}
public partial void Dispose()
{
_objMtlPath.Dispose();
_filename.Dispose();
if (_csAlloc && _ptr != null)
{
NativeMemory.Free(_ptr);
_ptr = null;
}
}
}

View File

@@ -1,25 +0,0 @@
using System.Text;
namespace Ghost.Ufbx;
public static unsafe class UfbxErrorExtensions
{
/// <summary>
/// Formats a ufbx_error into a human-readable string using ufbx_format_error.
/// Allocates a 2KB stack buffer; the result is truncated if the message exceeds that.
/// </summary>
public static string FormatError(ref this ufbx_error error)
{
const int BufferSize = 2048;
Span<byte> buffer = stackalloc byte[BufferSize];
fixed (ufbx_error* pError = &error)
fixed (byte* pBuffer = buffer)
{
var len = Api.ufbx_format_error((sbyte*)pBuffer, (nuint)BufferSize, pError);
if (len == 0)
return string.Empty;
// ufbx_format_error returns the number of characters written (excluding null terminator)
return Encoding.UTF8.GetString(buffer[..(int)len]);
}
}
}

View File

@@ -1,17 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Allocator
{
private ufbx_allocator* _ptr;
internal Allocator(ufbx_allocator* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public void* User => _ptr->user;
internal ufbx_allocator* GetUnsafePtr() => _ptr;
}

View File

@@ -1,25 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AllocatorOpts
{
private ufbx_allocator_opts* _ptr;
internal AllocatorOpts(ufbx_allocator_opts* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public Allocator Allocator => new((ufbx_allocator*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->allocator));
public nuint MemoryLimit => _ptr->memory_limit;
public nuint AllocationLimit => _ptr->allocation_limit;
public nuint HugeThreshold => _ptr->huge_threshold;
public nuint MaxChunkSize => _ptr->max_chunk_size;
internal ufbx_allocator_opts* GetUnsafePtr() => _ptr;
}

View File

@@ -1,91 +0,0 @@
namespace Ghost.Ufbx;
public unsafe ref struct Anim
{
private ufbx_anim* _ptr;
internal Anim(ufbx_anim* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ufbx_prop EvaluatePropLen(Element element, sbyte* name, nuint nameLen, double time)
{
return Api.ufbx_evaluate_prop_len(_ptr, element.GetUnsafePtr(), name, nameLen, time);
}
public ufbx_prop EvaluateProp(Element element, sbyte* name, double time)
{
return Api.ufbx_evaluate_prop(_ptr, element.GetUnsafePtr(), name, time);
}
public ufbx_prop EvaluatePropFlagsLen(Element element, sbyte* name, nuint nameLen, double time, uint flags)
{
return Api.ufbx_evaluate_prop_flags_len(_ptr, element.GetUnsafePtr(), name, nameLen, time, flags);
}
public ufbx_prop EvaluatePropFlags(Element element, sbyte* name, double time, uint flags)
{
return Api.ufbx_evaluate_prop_flags(_ptr, element.GetUnsafePtr(), name, time, flags);
}
public ufbx_props EvaluateProps(Element element, double time, Prop buffer, nuint bufferSize)
{
return Api.ufbx_evaluate_props(_ptr, element.GetUnsafePtr(), time, buffer.GetUnsafePtr(), bufferSize);
}
public ufbx_props EvaluatePropsFlags(Element element, double time, Prop buffer, nuint bufferSize, uint flags)
{
return Api.ufbx_evaluate_props_flags(_ptr, element.GetUnsafePtr(), time, buffer.GetUnsafePtr(), bufferSize, flags);
}
public ufbx_transform EvaluateTransform(Node node, double time)
{
return Api.ufbx_evaluate_transform(_ptr, node.GetUnsafePtr(), time);
}
public ufbx_transform EvaluateTransformFlags(Node node, double time, uint flags)
{
return Api.ufbx_evaluate_transform_flags(_ptr, node.GetUnsafePtr(), time, flags);
}
public float EvaluateBlendWeight(BlendChannel channel, double time)
{
return Api.ufbx_evaluate_blend_weight(_ptr, channel.GetUnsafePtr(), time);
}
public float EvaluateBlendWeightFlags(BlendChannel channel, double time, uint flags)
{
return Api.ufbx_evaluate_blend_weight_flags(_ptr, channel.GetUnsafePtr(), time, flags);
}
public void FreeAnim()
{
Api.ufbx_free_anim(_ptr);
}
public void RetainAnim()
{
Api.ufbx_retain_anim(_ptr);
}
public double TimeBegin => _ptr->time_begin;
public double TimeEnd => _ptr->time_end;
public AnimLayerList Layers => new(_ptr->layers.data, _ptr->layers.count);
public ReadOnlySpan<float> OverrideLayerWeights => _ptr->override_layer_weights.data == null ? ReadOnlySpan<float>.Empty : new ReadOnlySpan<float>(_ptr->override_layer_weights.data, checked((int)_ptr->override_layer_weights.count));
public ReadOnlySpan<ufbx_prop_override> PropOverrides => _ptr->prop_overrides.data == null ? ReadOnlySpan<ufbx_prop_override>.Empty : new ReadOnlySpan<ufbx_prop_override>(_ptr->prop_overrides.data, checked((int)_ptr->prop_overrides.count));
public ReadOnlySpan<ufbx_transform_override> TransformOverrides => _ptr->transform_overrides.data == null ? ReadOnlySpan<ufbx_transform_override>.Empty : new ReadOnlySpan<ufbx_transform_override>(_ptr->transform_overrides.data, checked((int)_ptr->transform_overrides.count));
public bool IgnoreConnections => _ptr->ignore_connections;
public bool Custom => _ptr->custom;
internal ufbx_anim* GetUnsafePtr() => _ptr;
}

View File

@@ -1,50 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AnimCurve
{
private ufbx_anim_curve* _ptr;
internal AnimCurve(ufbx_anim_curve* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public float EvaluateCurve(double time, float defaultValue)
{
return Api.ufbx_evaluate_curve(_ptr, time, defaultValue);
}
public float EvaluateCurveFlags(double time, float defaultValue, uint flags)
{
return Api.ufbx_evaluate_curve_flags(_ptr, time, defaultValue, flags);
}
public ReadOnlySpan<ufbx_keyframe> Keyframes => _ptr->keyframes.data == null ? ReadOnlySpan<ufbx_keyframe>.Empty : new ReadOnlySpan<ufbx_keyframe>(_ptr->keyframes.data, checked((int)_ptr->keyframes.count));
public Extrapolation PreExtrapolation => new((ufbx_extrapolation*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->pre_extrapolation));
public Extrapolation PostExtrapolation => new((ufbx_extrapolation*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->post_extrapolation));
public float MinValue => _ptr->min_value;
public float MaxValue => _ptr->max_value;
public double MinTime => _ptr->min_time;
public double MaxTime => _ptr->max_time;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_anim_curve* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct AnimCurveList
{
private readonly ufbx_anim_curve** _data;
public int Count { get; }
internal AnimCurveList(ufbx_anim_curve** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public AnimCurve this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_anim_curve** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_anim_curve** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public AnimCurve Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,60 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AnimLayer
{
private ufbx_anim_layer* _ptr;
internal AnimLayer(ufbx_anim_layer* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public AnimProp FindAnimPropLen(Element element, sbyte* prop, nuint propLen)
{
return new(Api.ufbx_find_anim_prop_len(_ptr, element.GetUnsafePtr(), prop, propLen));
}
public AnimProp FindAnimProp(Element element, sbyte* prop)
{
return new(Api.ufbx_find_anim_prop(_ptr, element.GetUnsafePtr(), prop));
}
public ufbx_anim_prop_list FindAnimProps(Element element)
{
return Api.ufbx_find_anim_props(_ptr, element.GetUnsafePtr());
}
public float Weight => _ptr->weight;
public bool WeightIsAnimated => _ptr->weight_is_animated;
public bool Blended => _ptr->blended;
public bool Additive => _ptr->additive;
public bool ComposeRotation => _ptr->compose_rotation;
public bool ComposeScale => _ptr->compose_scale;
public AnimValueList AnimValues => new(_ptr->anim_values.data, _ptr->anim_values.count);
public ReadOnlySpan<ufbx_anim_prop> AnimProps => _ptr->anim_props.data == null ? ReadOnlySpan<ufbx_anim_prop>.Empty : new ReadOnlySpan<ufbx_anim_prop>(_ptr->anim_props.data, checked((int)_ptr->anim_props.count));
public bool HasAnim => _ptr->anim != null;
public Anim Anim => _ptr->anim != null ? new(_ptr->anim) : throw new InvalidOperationException("Anim is null.");
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_anim_layer* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct AnimLayerList
{
private readonly ufbx_anim_layer** _data;
public int Count { get; }
internal AnimLayerList(ufbx_anim_layer** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public AnimLayer this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_anim_layer** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_anim_layer** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public AnimLayer Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,27 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AnimOpts
{
private ufbx_anim_opts* _ptr;
internal AnimOpts(ufbx_anim_opts* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<uint> LayerIds => _ptr->layer_ids.data == null ? ReadOnlySpan<uint>.Empty : new ReadOnlySpan<uint>(_ptr->layer_ids.data, checked((int)_ptr->layer_ids.count));
public ReadOnlySpan<float> OverrideLayerWeights => _ptr->override_layer_weights.data == null ? ReadOnlySpan<float>.Empty : new ReadOnlySpan<float>(_ptr->override_layer_weights.data, checked((int)_ptr->override_layer_weights.count));
public ReadOnlySpan<ufbx_prop_override_desc> PropOverrides => _ptr->prop_overrides.data == null ? ReadOnlySpan<ufbx_prop_override_desc>.Empty : new ReadOnlySpan<ufbx_prop_override_desc>(_ptr->prop_overrides.data, checked((int)_ptr->prop_overrides.count));
public ReadOnlySpan<ufbx_transform_override> TransformOverrides => _ptr->transform_overrides.data == null ? ReadOnlySpan<ufbx_transform_override>.Empty : new ReadOnlySpan<ufbx_transform_override>(_ptr->transform_overrides.data, checked((int)_ptr->transform_overrides.count));
public bool IgnoreConnections => _ptr->ignore_connections;
public AllocatorOpts ResultAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->result_allocator));
internal ufbx_anim_opts* GetUnsafePtr() => _ptr;
}

View File

@@ -1,24 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AnimProp
{
private ufbx_anim_prop* _ptr;
internal AnimProp(ufbx_anim_prop* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public bool HasElement => _ptr->element != null;
public Element Element => _ptr->element != null ? new(_ptr->element) : throw new InvalidOperationException("Element is null.");
public ReadOnlySpan<byte> PropNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->prop_name);
public string PropName => NativeWrapperHelpers.GetString(_ptr->prop_name);
public bool HasAnimValue => _ptr->anim_value != null;
public AnimValue AnimValue => _ptr->anim_value != null ? new(_ptr->anim_value) : throw new InvalidOperationException("AnimValue is null.");
internal ufbx_anim_prop* GetUnsafePtr() => _ptr;
}

View File

@@ -1,35 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AnimStack
{
private ufbx_anim_stack* _ptr;
internal AnimStack(ufbx_anim_stack* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public double TimeBegin => _ptr->time_begin;
public double TimeEnd => _ptr->time_end;
public AnimLayerList Layers => new(_ptr->layers.data, _ptr->layers.count);
public bool HasAnim => _ptr->anim != null;
public Anim Anim => _ptr->anim != null ? new(_ptr->anim) : throw new InvalidOperationException("Anim is null.");
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_anim_stack* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct AnimStackList
{
private readonly ufbx_anim_stack** _data;
public int Count { get; }
internal AnimStackList(ufbx_anim_stack** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public AnimStack this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_anim_stack** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_anim_stack** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public AnimStack Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,48 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AnimValue
{
private ufbx_anim_value* _ptr;
internal AnimValue(ufbx_anim_value* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public float EvaluateAnimValueReal(double time)
{
return Api.ufbx_evaluate_anim_value_real(_ptr, time);
}
public Misaki.HighPerformance.Mathematics.float3 EvaluateAnimValueVec3(double time)
{
return Api.ufbx_evaluate_anim_value_vec3(_ptr, time);
}
public float EvaluateAnimValueRealFlags(double time, uint flags)
{
return Api.ufbx_evaluate_anim_value_real_flags(_ptr, time, flags);
}
public Misaki.HighPerformance.Mathematics.float3 EvaluateAnimValueVec3Flags(double time, uint flags)
{
return Api.ufbx_evaluate_anim_value_vec3_flags(_ptr, time, flags);
}
public Misaki.HighPerformance.Mathematics.float3 DefaultValue => _ptr->default_value;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_anim_value* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct AnimValueList
{
private readonly ufbx_anim_value** _data;
public int Count { get; }
internal AnimValueList(ufbx_anim_value** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public AnimValue this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_anim_value** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_anim_value** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public AnimValue Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,24 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Application
{
private ufbx_application* _ptr;
internal Application(ufbx_application* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<byte> VendorBytes => NativeWrapperHelpers.AsByteSpan(_ptr->vendor);
public string Vendor => NativeWrapperHelpers.GetString(_ptr->vendor);
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public ReadOnlySpan<byte> VersionBytes => NativeWrapperHelpers.AsByteSpan(_ptr->version);
public string Version => NativeWrapperHelpers.GetString(_ptr->version);
internal ufbx_application* GetUnsafePtr() => _ptr;
}

View File

@@ -1,43 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AudioClip
{
private ufbx_audio_clip* _ptr;
internal AudioClip(ufbx_audio_clip* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<byte> FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
public ReadOnlySpan<byte> AbsoluteFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->absolute_filename);
public string AbsoluteFilename => NativeWrapperHelpers.GetString(_ptr->absolute_filename);
public ReadOnlySpan<byte> RelativeFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->relative_filename);
public string RelativeFilename => NativeWrapperHelpers.GetString(_ptr->relative_filename);
public ReadOnlySpan<byte> RawFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_filename);
public ReadOnlySpan<byte> RawAbsoluteFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_absolute_filename);
public ReadOnlySpan<byte> RawRelativeFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_relative_filename);
public ReadOnlySpan<byte> Content => NativeWrapperHelpers.AsSpan(_ptr->content);
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_audio_clip* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct AudioClipList
{
private readonly ufbx_audio_clip** _data;
public int Count { get; }
internal AudioClipList(ufbx_audio_clip** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public AudioClip this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_audio_clip** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_audio_clip** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public AudioClip Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,28 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct AudioLayer
{
private ufbx_audio_layer* _ptr;
internal AudioLayer(ufbx_audio_layer* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public AudioClipList Clips => new(_ptr->clips.data, _ptr->clips.count);
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_audio_layer* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct AudioLayerList
{
private readonly ufbx_audio_layer** _data;
public int Count { get; }
internal AudioLayerList(ufbx_audio_layer** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public AudioLayer this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_audio_layer** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_audio_layer** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public AudioLayer Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,53 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakeOpts
{
private ufbx_bake_opts* _ptr;
internal BakeOpts(ufbx_bake_opts* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public AllocatorOpts TempAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->temp_allocator));
public AllocatorOpts ResultAllocator => new((ufbx_allocator_opts*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->result_allocator));
public bool TrimStartTime => _ptr->trim_start_time;
public double ResampleRate => _ptr->resample_rate;
public double MinimumSampleRate => _ptr->minimum_sample_rate;
public double MaximumSampleRate => _ptr->maximum_sample_rate;
public bool BakeTransformProps => _ptr->bake_transform_props;
public bool SkipNodeTransforms => _ptr->skip_node_transforms;
public bool NoResampleRotation => _ptr->no_resample_rotation;
public bool IgnoreLayerWeightAnimation => _ptr->ignore_layer_weight_animation;
public nuint MaxKeyframeSegments => _ptr->max_keyframe_segments;
public ufbx_bake_step_handling StepHandling => _ptr->step_handling;
public double StepCustomDuration => _ptr->step_custom_duration;
public double StepCustomEpsilon => _ptr->step_custom_epsilon;
public uint EvaluateFlags => _ptr->evaluate_flags;
public bool KeyReductionEnabled => _ptr->key_reduction_enabled;
public bool KeyReductionRotation => _ptr->key_reduction_rotation;
public double KeyReductionThreshold => _ptr->key_reduction_threshold;
public nuint KeyReductionPasses => _ptr->key_reduction_passes;
internal ufbx_bake_opts* GetUnsafePtr() => _ptr;
}

View File

@@ -1,61 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedAnim
{
private ufbx_baked_anim* _ptr;
internal BakedAnim(ufbx_baked_anim* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public void RetainBakedAnim()
{
Api.ufbx_retain_baked_anim(_ptr);
}
public void FreeBakedAnim()
{
Api.ufbx_free_baked_anim(_ptr);
}
public BakedNode FindBakedNodeByTypedId(uint typedId)
{
return new(Api.ufbx_find_baked_node_by_typed_id(_ptr, typedId));
}
public BakedNode FindBakedNode(Node node)
{
return new(Api.ufbx_find_baked_node(_ptr, node.GetUnsafePtr()));
}
public BakedElement FindBakedElementByElementId(uint elementId)
{
return new(Api.ufbx_find_baked_element_by_element_id(_ptr, elementId));
}
public BakedElement FindBakedElement(Element element)
{
return new(Api.ufbx_find_baked_element(_ptr, element.GetUnsafePtr()));
}
public ReadOnlySpan<ufbx_baked_node> Nodes => _ptr->nodes.data == null ? ReadOnlySpan<ufbx_baked_node>.Empty : new ReadOnlySpan<ufbx_baked_node>(_ptr->nodes.data, checked((int)_ptr->nodes.count));
public ReadOnlySpan<ufbx_baked_element> Elements => _ptr->elements.data == null ? ReadOnlySpan<ufbx_baked_element>.Empty : new ReadOnlySpan<ufbx_baked_element>(_ptr->elements.data, checked((int)_ptr->elements.count));
public double PlaybackTimeBegin => _ptr->playback_time_begin;
public double PlaybackTimeEnd => _ptr->playback_time_end;
public double PlaybackDuration => _ptr->playback_duration;
public double KeyTimeMin => _ptr->key_time_min;
public double KeyTimeMax => _ptr->key_time_max;
public BakedAnimMetadata Metadata => new((ufbx_baked_anim_metadata*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->metadata));
internal ufbx_baked_anim* GetUnsafePtr() => _ptr;
}

View File

@@ -1,23 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedAnimMetadata
{
private ufbx_baked_anim_metadata* _ptr;
internal BakedAnimMetadata(ufbx_baked_anim_metadata* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public nuint ResultMemoryUsed => _ptr->result_memory_used;
public nuint TempMemoryUsed => _ptr->temp_memory_used;
public nuint ResultAllocs => _ptr->result_allocs;
public nuint TempAllocs => _ptr->temp_allocs;
internal ufbx_baked_anim_metadata* GetUnsafePtr() => _ptr;
}

View File

@@ -1,19 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedElement
{
private ufbx_baked_element* _ptr;
internal BakedElement(ufbx_baked_element* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public uint ElementId => _ptr->element_id;
public ReadOnlySpan<ufbx_baked_prop> Props => _ptr->props.data == null ? ReadOnlySpan<ufbx_baked_prop>.Empty : new ReadOnlySpan<ufbx_baked_prop>(_ptr->props.data, checked((int)_ptr->props.count));
internal ufbx_baked_element* GetUnsafePtr() => _ptr;
}

View File

@@ -1,31 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedNode
{
private ufbx_baked_node* _ptr;
internal BakedNode(ufbx_baked_node* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public uint TypedId => _ptr->typed_id;
public uint ElementId => _ptr->element_id;
public bool ConstantTranslation => _ptr->constant_translation;
public bool ConstantRotation => _ptr->constant_rotation;
public bool ConstantScale => _ptr->constant_scale;
public ReadOnlySpan<ufbx_baked_vec3> TranslationKeys => _ptr->translation_keys.data == null ? ReadOnlySpan<ufbx_baked_vec3>.Empty : new ReadOnlySpan<ufbx_baked_vec3>(_ptr->translation_keys.data, checked((int)_ptr->translation_keys.count));
public ReadOnlySpan<ufbx_baked_quat> RotationKeys => _ptr->rotation_keys.data == null ? ReadOnlySpan<ufbx_baked_quat>.Empty : new ReadOnlySpan<ufbx_baked_quat>(_ptr->rotation_keys.data, checked((int)_ptr->rotation_keys.count));
public ReadOnlySpan<ufbx_baked_vec3> ScaleKeys => _ptr->scale_keys.data == null ? ReadOnlySpan<ufbx_baked_vec3>.Empty : new ReadOnlySpan<ufbx_baked_vec3>(_ptr->scale_keys.data, checked((int)_ptr->scale_keys.count));
internal ufbx_baked_node* GetUnsafePtr() => _ptr;
}

View File

@@ -1,22 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedProp
{
private ufbx_baked_prop* _ptr;
internal BakedProp(ufbx_baked_prop* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public bool ConstantValue => _ptr->constant_value;
public ReadOnlySpan<ufbx_baked_vec3> Keys => _ptr->keys.data == null ? ReadOnlySpan<ufbx_baked_vec3>.Empty : new ReadOnlySpan<ufbx_baked_vec3>(_ptr->keys.data, checked((int)_ptr->keys.count));
internal ufbx_baked_prop* GetUnsafePtr() => _ptr;
}

View File

@@ -1,21 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedQuat
{
private ufbx_baked_quat* _ptr;
internal BakedQuat(ufbx_baked_quat* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public double Time => _ptr->time;
public Misaki.HighPerformance.Mathematics.quaternion Value => _ptr->value;
public ufbx_baked_key_flags Flags => _ptr->flags;
internal ufbx_baked_quat* GetUnsafePtr() => _ptr;
}

View File

@@ -1,21 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BakedVec3
{
private ufbx_baked_vec3* _ptr;
internal BakedVec3(ufbx_baked_vec3* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public double Time => _ptr->time;
public Misaki.HighPerformance.Mathematics.float3 Value => _ptr->value;
public ufbx_baked_key_flags Flags => _ptr->flags;
internal ufbx_baked_vec3* GetUnsafePtr() => _ptr;
}

View File

@@ -1,33 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BlendChannel
{
private ufbx_blend_channel* _ptr;
internal BlendChannel(ufbx_blend_channel* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public float Weight => _ptr->weight;
public ReadOnlySpan<ufbx_blend_keyframe> Keyframes => _ptr->keyframes.data == null ? ReadOnlySpan<ufbx_blend_keyframe>.Empty : new ReadOnlySpan<ufbx_blend_keyframe>(_ptr->keyframes.data, checked((int)_ptr->keyframes.count));
public bool HasTargetShape => _ptr->target_shape != null;
public BlendShape TargetShape => _ptr->target_shape != null ? new(_ptr->target_shape) : throw new InvalidOperationException("TargetShape is null.");
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_blend_channel* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct BlendChannelList
{
private readonly ufbx_blend_channel** _data;
public int Count { get; }
internal BlendChannelList(ufbx_blend_channel** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public BlendChannel this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_blend_channel** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_blend_channel** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public BlendChannel Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,38 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BlendDeformer
{
private ufbx_blend_deformer* _ptr;
internal BlendDeformer(ufbx_blend_deformer* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public Misaki.HighPerformance.Mathematics.float3 GetBlendVertexOffset(nuint vertex)
{
return Api.ufbx_get_blend_vertex_offset(_ptr, vertex);
}
public void AddBlendVertexOffsets(Misaki.HighPerformance.Mathematics.float3* vertices, nuint numVertices, float weight)
{
Api.ufbx_add_blend_vertex_offsets(_ptr, vertices, numVertices, weight);
}
public BlendChannelList Channels => new(_ptr->channels.data, _ptr->channels.count);
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_blend_deformer* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct BlendDeformerList
{
private readonly ufbx_blend_deformer** _data;
public int Count { get; }
internal BlendDeformerList(ufbx_blend_deformer** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public BlendDeformer this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_blend_deformer** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_blend_deformer** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public BlendDeformer Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,22 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BlendKeyframe
{
private ufbx_blend_keyframe* _ptr;
internal BlendKeyframe(ufbx_blend_keyframe* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public bool HasShape => _ptr->shape != null;
public BlendShape Shape => _ptr->shape != null ? new(_ptr->shape) : throw new InvalidOperationException("Shape is null.");
public float TargetWeight => _ptr->target_weight;
public float EffectiveWeight => _ptr->effective_weight;
internal ufbx_blend_keyframe* GetUnsafePtr() => _ptr;
}

View File

@@ -1,51 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BlendShape
{
private ufbx_blend_shape* _ptr;
internal BlendShape(ufbx_blend_shape* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public uint GetBlendShapeOffsetIndex(nuint vertex)
{
return Api.ufbx_get_blend_shape_offset_index(_ptr, vertex);
}
public Misaki.HighPerformance.Mathematics.float3 GetBlendShapeVertexOffset(nuint vertex)
{
return Api.ufbx_get_blend_shape_vertex_offset(_ptr, vertex);
}
public void AddBlendShapeVertexOffsets(Misaki.HighPerformance.Mathematics.float3* vertices, nuint numVertices, float weight)
{
Api.ufbx_add_blend_shape_vertex_offsets(_ptr, vertices, numVertices, weight);
}
public nuint NumOffsets => _ptr->num_offsets;
public ReadOnlySpan<uint> OffsetVertices => _ptr->offset_vertices.data == null ? ReadOnlySpan<uint>.Empty : new ReadOnlySpan<uint>(_ptr->offset_vertices.data, checked((int)_ptr->offset_vertices.count));
public ReadOnlySpan<Misaki.HighPerformance.Mathematics.float3> PositionOffsets => _ptr->position_offsets.data == null ? ReadOnlySpan<Misaki.HighPerformance.Mathematics.float3>.Empty : new ReadOnlySpan<Misaki.HighPerformance.Mathematics.float3>(_ptr->position_offsets.data, checked((int)_ptr->position_offsets.count));
public ReadOnlySpan<Misaki.HighPerformance.Mathematics.float3> NormalOffsets => _ptr->normal_offsets.data == null ? ReadOnlySpan<Misaki.HighPerformance.Mathematics.float3>.Empty : new ReadOnlySpan<Misaki.HighPerformance.Mathematics.float3>(_ptr->normal_offsets.data, checked((int)_ptr->normal_offsets.count));
public ReadOnlySpan<float> OffsetWeights => _ptr->offset_weights.data == null ? ReadOnlySpan<float>.Empty : new ReadOnlySpan<float>(_ptr->offset_weights.data, checked((int)_ptr->offset_weights.count));
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_blend_shape* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct BlendShapeList
{
private readonly ufbx_blend_shape** _data;
public int Count { get; }
internal BlendShapeList(ufbx_blend_shape** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public BlendShape this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_blend_shape** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_blend_shape** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public BlendShape Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,34 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Bone
{
private ufbx_bone* _ptr;
internal Bone(ufbx_bone* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public float Radius => _ptr->radius;
public float RelativeLength => _ptr->relative_length;
public bool IsRoot => _ptr->is_root;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
internal ufbx_bone* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct BoneList
{
private readonly ufbx_bone** _data;
public int Count { get; }
internal BoneList(ufbx_bone** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public Bone this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_bone** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_bone** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public Bone Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,22 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct BonePose
{
private ufbx_bone_pose* _ptr;
internal BonePose(ufbx_bone_pose* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public bool HasBoneNode => _ptr->bone_node != null;
public Node BoneNode => _ptr->bone_node != null ? new(_ptr->bone_node) : throw new InvalidOperationException("BoneNode is null.");
public Misaki.HighPerformance.Mathematics.float3x4 BoneToWorld => _ptr->bone_to_world;
public Misaki.HighPerformance.Mathematics.float3x4 BoneToParent => _ptr->bone_to_parent;
internal ufbx_bone_pose* GetUnsafePtr() => _ptr;
}

View File

@@ -1,39 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct CacheChannel
{
private ufbx_cache_channel* _ptr;
internal CacheChannel(ufbx_cache_channel* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public nuint SampleGeometryCacheReal(double time, float* data, nuint numData, GeometryCacheDataOpts opts)
{
return Api.ufbx_sample_geometry_cache_real(_ptr, time, data, numData, opts.GetUnsafePtr());
}
public nuint SampleGeometryCacheVec3(double time, Misaki.HighPerformance.Mathematics.float3* data, nuint numData, GeometryCacheDataOpts opts)
{
return Api.ufbx_sample_geometry_cache_vec3(_ptr, time, data, numData, opts.GetUnsafePtr());
}
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public ufbx_cache_interpretation Interpretation => _ptr->interpretation;
public ReadOnlySpan<byte> InterpretationNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->interpretation_name);
public string InterpretationName => NativeWrapperHelpers.GetString(_ptr->interpretation_name);
public ReadOnlySpan<ufbx_cache_frame> Frames => _ptr->frames.data == null ? ReadOnlySpan<ufbx_cache_frame>.Empty : new ReadOnlySpan<ufbx_cache_frame>(_ptr->frames.data, checked((int)_ptr->frames.count));
public ufbx_mirror_axis MirrorAxis => _ptr->mirror_axis;
public float ScaleFactor => _ptr->scale_factor;
internal ufbx_cache_channel* GetUnsafePtr() => _ptr;
}

View File

@@ -1,38 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct CacheDeformer
{
private ufbx_cache_deformer* _ptr;
internal CacheDeformer(ufbx_cache_deformer* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<byte> ChannelBytes => NativeWrapperHelpers.AsByteSpan(_ptr->channel);
public string Channel => NativeWrapperHelpers.GetString(_ptr->channel);
public bool HasFile => _ptr->file != null;
public CacheFile File => _ptr->file != null ? new(_ptr->file) : throw new InvalidOperationException("File is null.");
public bool HasExternalCache => _ptr->external_cache != null;
public GeometryCache ExternalCache => _ptr->external_cache != null ? new(_ptr->external_cache) : throw new InvalidOperationException("ExternalCache is null.");
public bool HasExternalChannel => _ptr->external_channel != null;
public CacheChannel ExternalChannel => _ptr->external_channel != null ? new(_ptr->external_channel) : throw new InvalidOperationException("ExternalChannel is null.");
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_cache_deformer* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct CacheDeformerList
{
private readonly ufbx_cache_deformer** _data;
public int Count { get; }
internal CacheDeformerList(ufbx_cache_deformer** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public CacheDeformer this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_cache_deformer** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_cache_deformer** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public CacheDeformer Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,46 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct CacheFile
{
private ufbx_cache_file* _ptr;
internal CacheFile(ufbx_cache_file* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<byte> FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
public ReadOnlySpan<byte> AbsoluteFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->absolute_filename);
public string AbsoluteFilename => NativeWrapperHelpers.GetString(_ptr->absolute_filename);
public ReadOnlySpan<byte> RelativeFilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->relative_filename);
public string RelativeFilename => NativeWrapperHelpers.GetString(_ptr->relative_filename);
public ReadOnlySpan<byte> RawFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_filename);
public ReadOnlySpan<byte> RawAbsoluteFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_absolute_filename);
public ReadOnlySpan<byte> RawRelativeFilename => NativeWrapperHelpers.AsSpan(_ptr->raw_relative_filename);
public ufbx_cache_file_format Format => _ptr->format;
public bool HasExternalCache => _ptr->external_cache != null;
public GeometryCache ExternalCache => _ptr->external_cache != null ? new(_ptr->external_cache) : throw new InvalidOperationException("ExternalCache is null.");
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_cache_file* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct CacheFileList
{
private readonly ufbx_cache_file** _data;
public int Count { get; }
internal CacheFileList(ufbx_cache_file** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public CacheFile this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_cache_file** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_cache_file** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public CacheFile Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,51 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct CacheFrame
{
private ufbx_cache_frame* _ptr;
internal CacheFrame(ufbx_cache_frame* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public nuint ReadGeometryCacheReal(float* data, nuint numData, GeometryCacheDataOpts opts)
{
return Api.ufbx_read_geometry_cache_real(_ptr, data, numData, opts.GetUnsafePtr());
}
public nuint ReadGeometryCacheVec3(Misaki.HighPerformance.Mathematics.float3* data, nuint numData, GeometryCacheDataOpts opts)
{
return Api.ufbx_read_geometry_cache_vec3(_ptr, data, numData, opts.GetUnsafePtr());
}
public ReadOnlySpan<byte> ChannelBytes => NativeWrapperHelpers.AsByteSpan(_ptr->channel);
public string Channel => NativeWrapperHelpers.GetString(_ptr->channel);
public double Time => _ptr->time;
public ReadOnlySpan<byte> FilenameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->filename);
public string Filename => NativeWrapperHelpers.GetString(_ptr->filename);
public ufbx_cache_file_format FileFormat => _ptr->file_format;
public ufbx_mirror_axis MirrorAxis => _ptr->mirror_axis;
public float ScaleFactor => _ptr->scale_factor;
public ufbx_cache_data_format DataFormat => _ptr->data_format;
public ufbx_cache_data_encoding DataEncoding => _ptr->data_encoding;
public ulong DataOffset => _ptr->data_offset;
public uint DataCount => _ptr->data_count;
public uint DataElementBytes => _ptr->data_element_bytes;
public ulong DataTotalBytes => _ptr->data_total_bytes;
internal ufbx_cache_frame* GetUnsafePtr() => _ptr;
}

View File

@@ -1,68 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Camera
{
private ufbx_camera* _ptr;
internal Camera(ufbx_camera* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ufbx_projection_mode ProjectionMode => _ptr->projection_mode;
public bool ResolutionIsPixels => _ptr->resolution_is_pixels;
public Misaki.HighPerformance.Mathematics.float2 Resolution => _ptr->resolution;
public Misaki.HighPerformance.Mathematics.float2 FieldOfViewDeg => _ptr->field_of_view_deg;
public Misaki.HighPerformance.Mathematics.float2 FieldOfViewTan => _ptr->field_of_view_tan;
public float OrthographicExtent => _ptr->orthographic_extent;
public Misaki.HighPerformance.Mathematics.float2 OrthographicSize => _ptr->orthographic_size;
public Misaki.HighPerformance.Mathematics.float2 ProjectionPlane => _ptr->projection_plane;
public float AspectRatio => _ptr->aspect_ratio;
public float NearPlane => _ptr->near_plane;
public float FarPlane => _ptr->far_plane;
public CoordinateAxes ProjectionAxes => new((ufbx_coordinate_axes*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->projection_axes));
public ufbx_aspect_mode AspectMode => _ptr->aspect_mode;
public ufbx_aperture_mode ApertureMode => _ptr->aperture_mode;
public ufbx_gate_fit GateFit => _ptr->gate_fit;
public ufbx_aperture_format ApertureFormat => _ptr->aperture_format;
public float FocalLengthMm => _ptr->focal_length_mm;
public Misaki.HighPerformance.Mathematics.float2 FilmSizeInch => _ptr->film_size_inch;
public Misaki.HighPerformance.Mathematics.float2 ApertureSizeInch => _ptr->aperture_size_inch;
public float SqueezeRatio => _ptr->squeeze_ratio;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
internal ufbx_camera* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct CameraList
{
private readonly ufbx_camera** _data;
public int Count { get; }
internal CameraList(ufbx_camera** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public Camera this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_camera** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_camera** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public Camera Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,28 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct CameraSwitcher
{
private ufbx_camera_switcher* _ptr;
internal CameraSwitcher(ufbx_camera_switcher* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
public NodeList Instances => new(_ptr->instances.data, _ptr->instances.count);
internal ufbx_camera_switcher* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct CameraSwitcherList
{
private readonly ufbx_camera_switcher** _data;
public int Count { get; }
internal CameraSwitcherList(ufbx_camera_switcher** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public CameraSwitcher this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_camera_switcher** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_camera_switcher** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public CameraSwitcher Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,26 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Character
{
private ufbx_character* _ptr;
internal Character(ufbx_character* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_character* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct CharacterList
{
private readonly ufbx_character** _data;
public int Count { get; }
internal CharacterList(ufbx_character** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public Character this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_character** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_character** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public Character Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,17 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct CloseMemoryCb
{
private ufbx_close_memory_cb* _ptr;
internal CloseMemoryCb(ufbx_close_memory_cb* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public void* User => _ptr->user;
internal ufbx_close_memory_cb* GetUnsafePtr() => _ptr;
}

View File

@@ -1,22 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct ColorSet
{
private ufbx_color_set* _ptr;
internal ColorSet(ufbx_color_set* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public uint Index => _ptr->index;
public VertexVec4 VertexColor => new((ufbx_vertex_vec4*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->vertex_color));
internal ufbx_color_set* GetUnsafePtr() => _ptr;
}

View File

@@ -1,27 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Connection
{
private ufbx_connection* _ptr;
internal Connection(ufbx_connection* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public bool HasSrc => _ptr->src != null;
public Element Src => _ptr->src != null ? new(_ptr->src) : throw new InvalidOperationException("Src is null.");
public bool HasDst => _ptr->dst != null;
public Element Dst => _ptr->dst != null ? new(_ptr->dst) : throw new InvalidOperationException("Dst is null.");
public ReadOnlySpan<byte> SrcPropBytes => NativeWrapperHelpers.AsByteSpan(_ptr->src_prop);
public string SrcProp => NativeWrapperHelpers.GetString(_ptr->src_prop);
public ReadOnlySpan<byte> DstPropBytes => NativeWrapperHelpers.AsByteSpan(_ptr->dst_prop);
public string DstProp => NativeWrapperHelpers.GetString(_ptr->dst_prop);
internal ufbx_connection* GetUnsafePtr() => _ptr;
}

View File

@@ -1,59 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct Constraint
{
private ufbx_constraint* _ptr;
internal Constraint(ufbx_constraint* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public ufbx_constraint_type Type => _ptr->type;
public ReadOnlySpan<byte> TypeNameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->type_name);
public string TypeName => NativeWrapperHelpers.GetString(_ptr->type_name);
public bool HasNode => _ptr->node != null;
public Node Node => _ptr->node != null ? new(_ptr->node) : throw new InvalidOperationException("Node is null.");
public ReadOnlySpan<ufbx_constraint_target> Targets => _ptr->targets.data == null ? ReadOnlySpan<ufbx_constraint_target>.Empty : new ReadOnlySpan<ufbx_constraint_target>(_ptr->targets.data, checked((int)_ptr->targets.count));
public float Weight => _ptr->weight;
public bool Active => _ptr->active;
public Transform TransformOffset => new((ufbx_transform*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transform_offset));
public Misaki.HighPerformance.Mathematics.float3 AimVector => _ptr->aim_vector;
public ufbx_constraint_aim_up_type AimUpType => _ptr->aim_up_type;
public bool HasAimUpNode => _ptr->aim_up_node != null;
public Node AimUpNode => _ptr->aim_up_node != null ? new(_ptr->aim_up_node) : throw new InvalidOperationException("AimUpNode is null.");
public Misaki.HighPerformance.Mathematics.float3 AimUpVector => _ptr->aim_up_vector;
public bool HasIkEffector => _ptr->ik_effector != null;
public Node IkEffector => _ptr->ik_effector != null ? new(_ptr->ik_effector) : throw new InvalidOperationException("IkEffector is null.");
public bool HasIkEndNode => _ptr->ik_end_node != null;
public Node IkEndNode => _ptr->ik_end_node != null ? new(_ptr->ik_end_node) : throw new InvalidOperationException("IkEndNode is null.");
public Misaki.HighPerformance.Mathematics.float3 IkPoleVector => _ptr->ik_pole_vector;
public Element Element => new((ufbx_element*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->element));
public ReadOnlySpan<byte> NameBytes => NativeWrapperHelpers.AsByteSpan(_ptr->name);
public string Name => NativeWrapperHelpers.GetString(_ptr->name);
public Props Props => new((ufbx_props*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->props));
public uint ElementId => _ptr->element_id;
public uint TypedId => _ptr->typed_id;
internal ufbx_constraint* GetUnsafePtr() => _ptr;
}

View File

@@ -1,52 +0,0 @@
namespace Ghost.Ufbx;
public unsafe readonly ref struct ConstraintList
{
private readonly ufbx_constraint** _data;
public int Count { get; }
internal ConstraintList(ufbx_constraint** data, nuint count)
{
_data = data;
Count = checked((int)count);
}
public Constraint this[int index]
{
get
{
NativeWrapperHelpers.ThrowIfOutOfRange(index, Count);
return new(_data[index]);
}
}
public Enumerator GetEnumerator() => new(_data, Count);
public unsafe ref struct Enumerator
{
private readonly ufbx_constraint** _data;
private readonly int _count;
private int _index;
internal Enumerator(ufbx_constraint** data, int count)
{
_data = data;
_count = count;
_index = -1;
}
public Constraint Current => new(_data[_index]);
public bool MoveNext()
{
var next = _index + 1;
if (next >= _count)
{
return false;
}
_index = next;
return true;
}
}
}

View File

@@ -1,22 +0,0 @@
namespace Ghost.Ufbx;
public unsafe struct ConstraintTarget
{
private ufbx_constraint_target* _ptr;
internal ConstraintTarget(ufbx_constraint_target* ptr)
{
_ptr = ptr;
}
public bool IsNull => _ptr == null;
public bool HasNode => _ptr->node != null;
public Node Node => _ptr->node != null ? new(_ptr->node) : throw new InvalidOperationException("Node is null.");
public float Weight => _ptr->weight;
public Transform Transform => new((ufbx_transform*)System.Runtime.CompilerServices.Unsafe.AsPointer(ref _ptr->transform));
internal ufbx_constraint_target* GetUnsafePtr() => _ptr;
}

Some files were not shown because too many files have changed in this diff Show More