Add overloads that does not use byte[] to the public API

This commit is contained in:
hadashiA 2026-07-30 10:35:53 +09:00
parent 3bdc4ce988
commit e75112ff77
3 changed files with 168 additions and 19 deletions

View File

@ -0,0 +1,59 @@
using System.IO;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.IO.LowLevel.Unsafe;
namespace UniGLTF
{
/// <summary>
/// Read a file directly into a NativeArray via AsyncReadManager without a managed byte[].
/// Ported from Unio (https://github.com/hadashiA/Unio) MIT License.
/// </summary>
public static class NativeFile
{
public static unsafe NativeArray<byte> ReadAllBytes(string filePath)
{
FileInfoResult fileInfoResult;
var fileInfoHandle = AsyncReadManager.GetFileInfo(filePath, &fileInfoResult);
fileInfoHandle.JobHandle.Complete();
if (fileInfoResult.FileState == FileState.Absent)
{
throw new FileNotFoundException(filePath);
}
var size = fileInfoResult.FileSize;
var buffer = (byte*)UnsafeUtility.Malloc(size, 16, Allocator.Persistent);
var readCommand = new ReadCommand
{
Offset = 0,
Size = size,
Buffer = buffer,
};
var readHandle = AsyncReadManager.Read(filePath, &readCommand, 1);
try
{
readHandle.JobHandle.Complete();
if (readHandle.Status != ReadStatus.Complete)
{
UnsafeUtility.Free(buffer, Allocator.Persistent);
throw new IOException($"Read operation failed ({readHandle.Status}). {filePath}");
}
}
finally
{
if (readHandle.IsValid())
{
readHandle.Dispose();
}
}
var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(buffer, (int)size, Allocator.Persistent);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, AtomicSafetyHandle.Create());
#endif
return array;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5b957f0aa4fb4d05b57882560f2d778
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +1,8 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using UniGLTF;
using Unity.Collections;
using UnityEngine;
namespace UniVRM10
@ -53,23 +53,34 @@ namespace UniVRM10
? new RuntimeOnlyAwaitCaller()
: new ImmediateCaller();
using var gltfData = await awaitCaller.Run(() =>
NativeArray<byte> bytes = default;
try
{
var bytes = File.ReadAllBytes(path);
return new GlbLowLevelParser(path, bytes).Parse();
});
return await LoadAsync(
gltfData,
canLoadVrm0X,
controlRigGenerationOption,
showMeshes,
awaitCaller,
textureDeserializer,
materialGenerator,
vrmMetaInformationCallback,
ct,
importerContextSettings,
springboneRuntime);
using var gltfData = await awaitCaller.Run(() =>
{
bytes = NativeFile.ReadAllBytes(path);
return GlbLowLevelParser.Parse(path, bytes);
});
return await LoadAsync(
gltfData,
canLoadVrm0X,
controlRigGenerationOption,
showMeshes,
awaitCaller,
textureDeserializer,
materialGenerator,
vrmMetaInformationCallback,
ct,
importerContextSettings,
springboneRuntime);
}
finally
{
if (bytes.IsCreated)
{
bytes.Dispose();
}
}
}
/// <summary>
@ -89,7 +100,7 @@ namespace UniVRM10
/// <param name="ct">CancellationToken</param>
/// <param name="importerContextSettings">Importer context settings.</param>
/// <returns>vrm-1.0 instance. Maybe return null if unexpected error was raised.</returns>
public static async Task<Vrm10Instance> LoadBytesAsync(
public static Task<Vrm10Instance> LoadBytesAsync(
byte[] bytes,
bool canLoadVrm0X = true,
ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate,
@ -101,12 +112,80 @@ namespace UniVRM10
CancellationToken ct = default,
ImporterContextSettings importerContextSettings = null,
IVrm10SpringBoneRuntime springboneRuntime = null)
{
return LoadBytesAsync(
bytes.AsMemory(),
canLoadVrm0X,
controlRigGenerationOption,
showMeshes,
awaitCaller,
textureDeserializer,
materialGenerator,
vrmMetaInformationCallback,
ct,
importerContextSettings,
springboneRuntime);
}
/// <summary>
/// Load the VRM file from the NativeArray.
///
/// The caller is responsible for disposing `bytes`. Do not dispose it until this task completes.
/// You should call this on Unity main thread.
/// This will throw Exceptions (include OperationCanceledException).
/// </summary>
public static Task<Vrm10Instance> LoadBytesAsync(
NativeArray<byte> bytes,
bool canLoadVrm0X = true,
ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate,
bool showMeshes = true,
IAwaitCaller awaitCaller = null,
ITextureDeserializer textureDeserializer = null,
IMaterialDescriptorGenerator materialGenerator = null,
VrmMetaInformationCallback vrmMetaInformationCallback = null,
CancellationToken ct = default,
ImporterContextSettings importerContextSettings = null,
IVrm10SpringBoneRuntime springboneRuntime = null)
{
return LoadBytesAsync(
bytes.AsMemory(),
canLoadVrm0X,
controlRigGenerationOption,
showMeshes,
awaitCaller,
textureDeserializer,
materialGenerator,
vrmMetaInformationCallback,
ct,
importerContextSettings,
springboneRuntime);
}
/// <summary>
/// Load the VRM file from the memory.
///
/// The caller is responsible for keeping the underlying memory alive until this task completes.
/// You should call this on Unity main thread.
/// This will throw Exceptions (include OperationCanceledException).
/// </summary>
public static async Task<Vrm10Instance> LoadBytesAsync(
ReadOnlyMemory<byte> bytes,
bool canLoadVrm0X = true,
ControlRigGenerationOption controlRigGenerationOption = ControlRigGenerationOption.Generate,
bool showMeshes = true,
IAwaitCaller awaitCaller = null,
ITextureDeserializer textureDeserializer = null,
IMaterialDescriptorGenerator materialGenerator = null,
VrmMetaInformationCallback vrmMetaInformationCallback = null,
CancellationToken ct = default,
ImporterContextSettings importerContextSettings = null,
IVrm10SpringBoneRuntime springboneRuntime = null)
{
awaitCaller ??= Application.isPlaying
? new RuntimeOnlyAwaitCaller()
: new ImmediateCaller();
using var gltfData = await awaitCaller.Run(() => new GlbLowLevelParser(string.Empty, bytes).Parse());
using var gltfData = await awaitCaller.Run(() => GlbLowLevelParser.Parse("", bytes));
return await LoadAsync(
gltfData,
canLoadVrm0X,