// SPDX-FileCopyrightText: 2023 Unity Technologies and the glTFast authors // SPDX-License-Identifier: Apache-2.0 using System; using AOT; using GLTFast.Vertex; using UnityEngine; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Burst; using Unity.Jobs; using Unity.Mathematics; using static Unity.Mathematics.math; namespace GLTFast.Jobs { using Schema; [BurstCompile] static unsafe class CachedFunction { public delegate int GetIndexDelegate(void* baseAddress, int index); public delegate void GetFloat3Delegate(float3* destination, void* src); // Cached function pointers static FunctionPointer s_GetIndexValueInt8Method; static FunctionPointer s_GetIndexValueUInt8Method; static FunctionPointer s_GetIndexValueInt16Method; static FunctionPointer s_GetIndexValueUInt16Method; static FunctionPointer s_GetIndexValueUInt32Method; static FunctionPointer s_GetFloat3FloatMethod; static FunctionPointer s_GetFloat3Int8Method; static FunctionPointer s_GetFloat3UInt8Method; static FunctionPointer s_GetFloat3Int16Method; static FunctionPointer s_GetFloat3UInt16Method; static FunctionPointer s_GetFloat3UInt32Method; static FunctionPointer s_GetFloat3Int8NormalizedMethod; static FunctionPointer s_GetFloat3UInt8NormalizedMethod; static FunctionPointer s_GetFloat3Int16NormalizedMethod; static FunctionPointer s_GetFloat3UInt16NormalizedMethod; static FunctionPointer s_GetFloat3UInt32NormalizedMethod; /// /// Returns Burst compatible function that retrieves an index value /// /// Data type of index /// Burst Function Pointer to correct conversion function /// public static FunctionPointer GetIndexConverter(GltfComponentType format) { switch (format) { case GltfComponentType.UnsignedByte: if (!s_GetIndexValueUInt8Method.IsCreated) { s_GetIndexValueUInt8Method = BurstCompiler.CompileFunctionPointer(GetIndexValueUInt8); } return s_GetIndexValueUInt8Method; case GltfComponentType.Byte: if (!s_GetIndexValueInt8Method.IsCreated) { s_GetIndexValueInt8Method = BurstCompiler.CompileFunctionPointer(GetIndexValueInt8); } return s_GetIndexValueInt8Method; case GltfComponentType.UnsignedShort: if (!s_GetIndexValueUInt16Method.IsCreated) { s_GetIndexValueUInt16Method = BurstCompiler.CompileFunctionPointer(GetIndexValueUInt16); } return s_GetIndexValueUInt16Method; case GltfComponentType.Short: if (!s_GetIndexValueInt16Method.IsCreated) { s_GetIndexValueInt16Method = BurstCompiler.CompileFunctionPointer(GetIndexValueInt16); } return s_GetIndexValueInt16Method; case GltfComponentType.UnsignedInt: if (!s_GetIndexValueUInt32Method.IsCreated) { s_GetIndexValueUInt32Method = BurstCompiler.CompileFunctionPointer(GetIndexValueUInt32); } return s_GetIndexValueUInt32Method; default: throw new ArgumentOutOfRangeException(nameof(format), format, null); } } public static FunctionPointer GetPositionConverter( GltfComponentType format, bool normalized ) { if (normalized) { switch (format) { case GltfComponentType.Float: // Floats cannot be normalized. // Fall back to non-normalized below break; case GltfComponentType.Byte: if (!s_GetFloat3Int8NormalizedMethod.IsCreated) { s_GetFloat3Int8NormalizedMethod = BurstCompiler.CompileFunctionPointer(GetFloat3Int8Normalized); } return s_GetFloat3Int8NormalizedMethod; case GltfComponentType.UnsignedByte: if (!s_GetFloat3UInt8NormalizedMethod.IsCreated) { s_GetFloat3UInt8NormalizedMethod = BurstCompiler.CompileFunctionPointer(GetFloat3UInt8Normalized); } return s_GetFloat3UInt8NormalizedMethod; case GltfComponentType.Short: if (!s_GetFloat3Int16NormalizedMethod.IsCreated) { s_GetFloat3Int16NormalizedMethod = BurstCompiler.CompileFunctionPointer(GetFloat3Int16Normalized); } return s_GetFloat3Int16NormalizedMethod; case GltfComponentType.UnsignedShort: if (!s_GetFloat3UInt16NormalizedMethod.IsCreated) { s_GetFloat3UInt16NormalizedMethod = BurstCompiler.CompileFunctionPointer(GetFloat3UInt16Normalized); } return s_GetFloat3UInt16NormalizedMethod; case GltfComponentType.UnsignedInt: if (!s_GetFloat3UInt32NormalizedMethod.IsCreated) { s_GetFloat3UInt32NormalizedMethod = BurstCompiler.CompileFunctionPointer(GetFloat3UInt32Normalized); } return s_GetFloat3UInt32NormalizedMethod; } } switch (format) { case GltfComponentType.Float: if (!s_GetFloat3FloatMethod.IsCreated) { s_GetFloat3FloatMethod = BurstCompiler.CompileFunctionPointer(GetFloat3Float); } return s_GetFloat3FloatMethod; case GltfComponentType.Byte: if (!s_GetFloat3Int8Method.IsCreated) { s_GetFloat3Int8Method = BurstCompiler.CompileFunctionPointer(GetFloat3Int8); } return s_GetFloat3Int8Method; case GltfComponentType.UnsignedByte: if (!s_GetFloat3UInt8Method.IsCreated) { s_GetFloat3UInt8Method = BurstCompiler.CompileFunctionPointer(GetFloat3UInt8); } return s_GetFloat3UInt8Method; case GltfComponentType.Short: if (!s_GetFloat3Int16Method.IsCreated) { s_GetFloat3Int16Method = BurstCompiler.CompileFunctionPointer(GetFloat3Int16); } return s_GetFloat3Int16Method; case GltfComponentType.UnsignedShort: if (!s_GetFloat3UInt16Method.IsCreated) { s_GetFloat3UInt16Method = BurstCompiler.CompileFunctionPointer(GetFloat3UInt16); } return s_GetFloat3UInt16Method; case GltfComponentType.UnsignedInt: if (!s_GetFloat3UInt32Method.IsCreated) { s_GetFloat3UInt32Method = BurstCompiler.CompileFunctionPointer(GetFloat3UInt32); } return s_GetFloat3UInt32Method; } throw new ArgumentOutOfRangeException(nameof(format), format, null); } [BurstCompile, MonoPInvokeCallback(typeof(GetIndexDelegate))] static int GetIndexValueUInt8(void* baseAddress, int index) { return *((byte*)baseAddress + index); } [BurstCompile, MonoPInvokeCallback(typeof(GetIndexDelegate))] static int GetIndexValueInt8(void* baseAddress, int index) { return *(((sbyte*)baseAddress) + index); } [BurstCompile, MonoPInvokeCallback(typeof(GetIndexDelegate))] static int GetIndexValueUInt16(void* baseAddress, int index) { return *(((ushort*)baseAddress) + index); } [BurstCompile, MonoPInvokeCallback(typeof(GetIndexDelegate))] static int GetIndexValueInt16(void* baseAddress, int index) { return *(((short*)baseAddress) + index); } [BurstCompile, MonoPInvokeCallback(typeof(GetIndexDelegate))] static int GetIndexValueUInt32(void* baseAddress, int index) { return (int)*(((uint*)baseAddress) + index); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3Float(float3* destination, void* src) { destination->x = -*(float*)src; destination->y = *((float*)src + 1); destination->z = *((float*)src + 2); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3Int8(float3* destination, void* src) { destination->x = -*(sbyte*)src; destination->y = *((sbyte*)src + 1); destination->z = *((sbyte*)src + 2); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3UInt8(float3* destination, void* src) { destination->x = -*(byte*)src; destination->y = *((byte*)src + 1); destination->z = *((byte*)src + 2); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3Int16(float3* destination, void* src) { destination->x = -*(short*)src; destination->y = *((short*)src + 1); destination->z = *((short*)src + 2); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3UInt16(float3* destination, void* src) { destination->x = -*(ushort*)src; destination->y = *((ushort*)src + 1); destination->z = *((ushort*)src + 2); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3UInt32(float3* destination, void* src) { destination->x = -*(uint*)src; destination->y = *((uint*)src + 1); destination->z = *((uint*)src + 2); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3Int8Normalized(float3* destination, void* src) { destination->x = -max(*(sbyte*)src / 127f, -1); destination->y = max(*((sbyte*)src + 1) / 127f, -1); destination->z = max(*((sbyte*)src + 2) / 127f, -1); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3UInt8Normalized(float3* destination, void* src) { destination->x = -*(byte*)src / 255f; destination->y = *((byte*)src + 1) / 255f; destination->z = *((byte*)src + 2) / 255f; } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3Int16Normalized(float3* destination, void* src) { destination->x = -max(*(short*)src / (float)short.MaxValue, -1f); destination->y = max(*((short*)src + 1) / (float)short.MaxValue, -1f); destination->z = max(*((short*)src + 2) / (float)short.MaxValue, -1f); } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3UInt16Normalized(float3* destination, void* src) { destination->x = -*(ushort*)src / (float)ushort.MaxValue; destination->y = *((ushort*)src + 1) / (float)ushort.MaxValue; destination->z = *((ushort*)src + 2) / (float)ushort.MaxValue; } [BurstCompile, MonoPInvokeCallback(typeof(GetFloat3Delegate))] static void GetFloat3UInt32Normalized(float3* destination, void* src) { destination->x = -*(uint*)src / (float)uint.MaxValue; destination->y = *((uint*)src + 1) / (float)uint.MaxValue; destination->z = *((uint*)src + 2) / (float)uint.MaxValue; } } [BurstCompile] struct CreateIndicesInt32Job : IJobParallelFor { [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = index; } } [BurstCompile] struct CreateIndicesInt32FlippedJob : IJobParallelFor { [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = index - 2 * (index % 3 - 1); } } [BurstCompile] struct CreateIndicesForTriangleStripJob : IJobParallelFor { [WriteOnly] public NativeArray result; public void Execute(int index) { // Source https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html // Triangle Strips // One triangle primitive is defined by each vertex and the two vertices that follow it, according to the equation: // pi = { vi, vi + (1 + i % 2), vi + (2 - i % 2)} // We change first and second indices for Unity var triangleIndex = index / 3; result[index] = (index % 3) switch { 0 => triangleIndex + (1 + triangleIndex % 2), 1 => triangleIndex, 2 => triangleIndex + (2 - triangleIndex % 2), _ => result[index] }; } } [BurstCompile] struct CreateIndicesForTriangleFanJob : IJobParallelFor { [WriteOnly] public NativeArray result; public void Execute(int index) { // Source https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html // Triangle Fans // Triangle primitives are defined around a shared common vertex, according to the equation: // pi = {vi+1, vi+2, v0} // We change first and second indices for Unity var triangleIndex = index / 3; result[index] = (index % 3) switch { 0 => triangleIndex + 2, 1 => triangleIndex + 1, _ => 0 }; } } [BurstCompile] struct RecalculateIndicesForTriangleStripJob : IJobParallelFor { [ReadOnly] public NativeArray input; [WriteOnly, NativeDisableParallelForRestriction] public NativeArray result; public void Execute(int index) { // Source https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html // Triangle Strips // One triangle primitive is defined by each vertex and the two vertices that follow it, according to the equation: // pi = { vi, vi + (1 + i % 2), vi + (2 - i % 2)} // We change first and second indices for Unity var triangleIndex = index * 3; result[triangleIndex + 1] = input[index]; result[triangleIndex] = input[index + (1 + index % 2)]; result[triangleIndex + 2] = input[index + (2 - index % 2)]; } } [BurstCompile] struct RecalculateIndicesForTriangleFanJob : IJobParallelFor { [ReadOnly] public NativeArray input; [WriteOnly, NativeDisableParallelForRestriction] public NativeArray result; public void Execute(int index) { // Source https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html // Triangle Fans // Triangle primitives are defined around a shared common vertex, according to the equation: // pi = {vi+1, vi+2, v0} // We change first and second indices for Unity var triangleIndex = index * 3; result[triangleIndex + 1] = input[index + 1]; result[triangleIndex] = input[index + 2]; result[triangleIndex + 2] = 0; } } [BurstCompile] struct ConvertIndicesUInt8ToInt32Job : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index]; } } [BurstCompile] struct ConvertIndicesUInt8ToInt32FlippedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index].GltfToUnityTriangleIndies(); } } [BurstCompile] struct ConvertIndicesUInt16ToInt32FlippedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index].GltfToUnityTriangleIndies(); } } [BurstCompile] struct ConvertIndicesUInt16ToInt32Job : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index]; } } [BurstCompile] struct ConvertIndicesUInt32ToInt32Job : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = (int)input[index]; } } [BurstCompile] struct ConvertIndicesUInt32ToInt32FlippedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { var idx = input[index]; result[index] = new int3((int)idx.x, (int)idx.z, (int)idx.y); } } [BurstCompile] unsafe struct ConvertUVsUInt8ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var off = input + (startIndex * inputByteStride); for (var index = 0; index < count; index++) { *resultV = new float2(off[0], 1 - off[1]); resultV = (float2*)((byte*)resultV + outputByteStride); off += inputByteStride; } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var off = input + inputByteStride * index; *resultV = new float2(off[0], 1 - off[1]); } #endif } [BurstCompile] unsafe struct ConvertUVsUInt8ToFloatInterleavedNormalizedJob : IJobParallelFor { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var off = input + inputByteStride * index; var tmp = new float2( off[0], off[1] ) / 255f; tmp.y = 1 - tmp.y; *resultV = tmp; } } [BurstCompile] unsafe struct ConvertUVsUInt16ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var uv = (ushort*)(input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { *resultV = new float2(uv[0], 1 - uv[1]); resultV = (float2*)((byte*)resultV + outputByteStride); uv = (ushort*)((byte*)uv + inputByteStride); } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var uv = (ushort*)(input + inputByteStride * index); *resultV = new float2(uv[0], 1 - uv[1]); } #endif } [BurstCompile] unsafe struct ConvertUVsUInt16ToFloatInterleavedNormalizedJob : IJobParallelFor { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var uv = (ushort*)(input + inputByteStride * index); var tmp = new float2( uv[0], uv[1] ) / ushort.MaxValue; tmp.y = 1 - tmp.y; *resultV = tmp; } } [BurstCompile] unsafe struct ConvertUVsInt16ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public short* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var uv = (short*)((byte*)input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { *resultV = new float2(uv[0], 1 - uv[1]); resultV = (float2*)((byte*)resultV + outputByteStride); uv = (short*)((byte*)uv + inputByteStride); } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var uv = (short*)((byte*)input + inputByteStride * index); *resultV = new float2(uv[0], 1 - uv[1]); } #endif } [BurstCompile] unsafe struct ConvertUVsInt16ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public short* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var uv = (short*)((byte*)input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { var tmp = new float2(uv[0], uv[1]) / short.MaxValue; var tmp2 = max(tmp, -1f); tmp2.y = 1 - tmp2.y; *resultV = tmp2; resultV = (float2*)((byte*)resultV + outputByteStride); uv = (short*)((byte*)uv + inputByteStride); } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var uv = (short*)((byte*)input + inputByteStride * index); var tmp = new float2(uv[0], uv[1]) / short.MaxValue; var tmp2 = max(tmp, -1f); tmp2.y = 1 - tmp2.y; *resultV = tmp2; } #endif } [BurstCompile] unsafe struct ConvertUVsInt8ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public sbyte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var off = input + startIndex * inputByteStride; for (var index = 0; index < count; index++) { *resultV = new float2(off[0], 1 - off[1]); resultV = (float2*)((byte*)resultV + outputByteStride); off += inputByteStride; } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var off = input + inputByteStride * index; *resultV = new float2(off[0], 1 - off[1]); } #endif } [BurstCompile] unsafe struct ConvertUVsInt8ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public sbyte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var off = input + startIndex * inputByteStride; for (var index = 0; index < count; index++) { var tmp = new float2(off[0], off[1]) / 127f; var tmp2 = max(tmp, -1f); tmp2.y = 1 - tmp2.y; *resultV = tmp2; resultV = (float2*)((byte*)resultV + outputByteStride); off += inputByteStride; } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var off = input + inputByteStride * index; var tmp = new float2(off[0], off[1]) / 127f; var tmp2 = max(tmp, -1f); tmp2.y = 1 - tmp2.y; *resultV = tmp2; } #endif } [BurstCompile] unsafe struct ConvertColorsRGBFloatToRGBAFloatJob : IJobParallelFor { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [WriteOnly] public NativeArray result; public void Execute(int index) { var src = (float3*)(input + (index * inputByteStride)); result[index] = new float4(*src, 1f); } } [BurstCompile] unsafe struct ConvertColorsRgbUInt8ToRGBAFloatJob : IJobParallelFor { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [WriteOnly] public NativeArray result; public void Execute(int index) { var src = input + (index * inputByteStride); result[index] = new float4( new float3(src[0], src[1], src[2]) / byte.MaxValue, 1f ); } } [BurstCompile] unsafe struct ConvertColorsRgbUInt16ToRGBAFloatJob : IJobParallelFor { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public ushort* input; [WriteOnly] public NativeArray result; public void Execute(int index) { var src = (ushort*)(((byte*)input) + (index * inputByteStride)); result[index] = new float4( new float3(src[0], src[1], src[2]) / ushort.MaxValue, 1f ); } } [BurstCompile] unsafe struct ConvertColorsRgbaUInt16ToRGBAFloatJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public ushort* input; [WriteOnly] public NativeArray result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var src = (ushort*)((byte*)input + startIndex * inputByteStride); var endIndex = startIndex + count; for (var index = startIndex; index < endIndex; index++) { result[index] = new float4( src[0] / (float)ushort.MaxValue, src[1] / (float)ushort.MaxValue, src[2] / (float)ushort.MaxValue, src[3] / (float)ushort.MaxValue ); src = (ushort*)((byte*)src + inputByteStride); } } #else public void Execute(int index) { var src = (ushort*)(((byte*)input) + (index * inputByteStride)); result[index] = new float4( src[0] / (float)ushort.MaxValue, src[1] / (float)ushort.MaxValue, src[2] / (float)ushort.MaxValue, src[3] / (float)ushort.MaxValue ); } #endif } [BurstCompile] unsafe struct ConvertColorsRGBAFloatToRGBAFloatJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [WriteOnly] public NativeArray result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var src = (float4*)(input + startIndex * inputByteStride); var endIndex = startIndex + count; for (var index = startIndex; index < endIndex; index++) { result[index] = *src; src = (float4*)((byte*)src + inputByteStride); } } #else public void Execute(int index) { var src = (float4*)(input + (index * inputByteStride)); result[index] = *src; } #endif } [BurstCompile] unsafe struct ConvertColorsRgbaUInt8ToRGBAFloatJob : IJobParallelFor { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [WriteOnly] public NativeArray result; public void Execute(int index) { var src = input + (index * inputByteStride); result[index] = new float4( src[0] / (float)byte.MaxValue, src[1] / (float)byte.MaxValue, src[2] / (float)byte.MaxValue, src[3] / (float)byte.MaxValue ); } } [BurstCompile] unsafe struct MemCopyJob : IJob { [ReadOnly] public long bufferSize; [ReadOnly] [NativeDisableUnsafePtrRestriction] public void* input; [ReadOnly] [NativeDisableUnsafePtrRestriction] public void* result; public void Execute() { UnsafeUtility.MemCpy(result, input, bufferSize); } } /// /// General purpose vector 3 (position or normal) conversion /// [BurstCompile] struct ConvertVector3FloatToFloatJob : IJobParallelFor { [ReadOnly] public ReadOnlyNativeStridedArray input; [WriteOnly] public NativeArray result; public void Execute(int index) { var tmp = input[index]; tmp.x *= -1; result[index] = tmp; } } [BurstCompile] struct ConvertRotationsFloatToFloatJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { var tmp = input[index]; tmp.y *= -1; tmp.z *= -1; result[index] = tmp; } } [BurstCompile] struct ConvertRotationsInt16ToFloatJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index].GltfToUnityRotation(); } } /// /// Converts an array of glTF space quaternions (normalized, signed bytes) to /// Quaternions in Unity space (floats). /// [BurstCompile] struct ConvertRotationsInt8ToFloatJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index].GltfToUnityRotation(); } } [BurstCompile] unsafe struct ConvertUVsFloatToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float2* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float2*)((byte*)result + startIndex * outputByteStride); var off = (float2*)(input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { var tmp = *off; tmp.y = 1 - tmp.y; *resultV = tmp; resultV = (float2*)((byte*)resultV + outputByteStride); off = (float2*)((byte*)off + inputByteStride); } } #else public void Execute(int index) { var resultV = (float2*)(((byte*)result) + (index * outputByteStride)); var off = (float2*)(input + (index * inputByteStride)); var tmp = *off; tmp.y = 1 - tmp.y; *resultV = tmp; } #endif } /// /// General purpose vector 3 (position or normal) conversion /// [BurstCompile] unsafe struct ConvertVector3FloatToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { var tmp = input[index]; tmp.x *= -1; *resultV = tmp; resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); var tmp = input[index]; tmp.x *= -1; *resultV = tmp; } #endif } /// /// General purpose sparse vector 3 (position or normal) conversion /// [BurstCompile] unsafe struct ConvertVector3SparseJob : IJobParallelFor { [ReadOnly] [NativeDisableUnsafePtrRestriction] public void* indexBuffer; public FunctionPointer indexConverter; [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public void* input; public FunctionPointer valueConverter; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; public void Execute(int index) { var resultIndex = indexConverter.Invoke(indexBuffer, index); var resultV = (float3*)(((byte*)result) + (resultIndex * outputByteStride)); valueConverter.Invoke(resultV, (byte*)input + index * inputByteStride); } } [BurstCompile] unsafe struct ConvertTangentsFloatToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float4* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float4*)((byte*)result + startIndex * outputByteStride); var off = (float4*)(input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { var tmp = *off; tmp.z *= -1; *resultV = tmp; resultV = (float4*)((byte*)resultV + outputByteStride); off = (float4*)((byte*)off + inputByteStride); } } #else public void Execute(int index) { var resultV = (float4*)(((byte*)result) + (index * outputByteStride)); var off = input + (index * inputByteStride); var tmp = *((float4*)off); tmp.z *= -1; *resultV = tmp; } #endif } [BurstCompile] unsafe struct ConvertBoneWeightsFloatToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float4* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float4*)((byte*)result + startIndex * outputByteStride); var off = (float4*)(input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { *resultV = *off; resultV = (float4*)((byte*)resultV + outputByteStride); off = (float4*)((byte*)off + inputByteStride); } } #else public void Execute(int index) { var resultV = (float4*)(((byte*)result) + (index * outputByteStride)); var off = input + (index * inputByteStride); *resultV = *((float4*)off); } #endif } [BurstCompile] unsafe struct ConvertBoneWeightsUInt8ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float4* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float4*)((byte*)result + startIndex * outputByteStride); var off = input + startIndex * inputByteStride; for (var index = 0; index < count; index++) { *resultV = new float4( off[0] / 255f, off[1] / 255f, off[2] / 255f, off[3] / 255f ); resultV = (float4*)((byte*)resultV + outputByteStride); off += inputByteStride; } } #else public void Execute(int index) { var resultV = (float4*)(((byte*)result) + (index * outputByteStride)); var off = input + (index * inputByteStride); *resultV = new float4( off[0] / 255f, off[1] / 255f, off[2] / 255f, off[3] / 255f ); } #endif } [BurstCompile] unsafe struct ConvertBoneWeightsUInt16ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float4* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float4*)((byte*)result + startIndex * outputByteStride); var off = (ushort*)(input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { *resultV = new float4( off[0] / (float)ushort.MaxValue, off[1] / (float)ushort.MaxValue, off[2] / (float)ushort.MaxValue, off[3] / (float)ushort.MaxValue ); resultV = (float4*)((byte*)resultV + outputByteStride); off = (ushort*)((byte*)off + inputByteStride); } } #else public void Execute(int index) { var resultV = (float4*)(((byte*)result) + (index * outputByteStride)); var off = (ushort*)(input + index * inputByteStride); *resultV = new float4( off[0] / (float)ushort.MaxValue, off[1] / (float)ushort.MaxValue, off[2] / (float)ushort.MaxValue, off[3] / (float)ushort.MaxValue ); } #endif } [BurstCompile] unsafe struct ConvertTangentsInt16ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public short* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float4* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float4*)((byte*)result + startIndex * outputByteStride); var off = (short*)((byte*)input + startIndex * inputByteStride); for (var index = 0; index < count; index++) { var tmp = new float4(off[0], off[1], off[2], off[3]) / short.MaxValue; var tmp2 = max(tmp, -1f); tmp2.z *= -1; *resultV = normalize(tmp2); resultV = (float4*)((byte*)resultV + outputByteStride); off = (short*)((byte*)off + inputByteStride); } } #else public void Execute(int index) { var resultV = (float4*)(((byte*)result) + (index * outputByteStride)); var off = (short*)(((byte*)input) + (index * inputByteStride)); var tmp = new float4(off[0], off[1], off[2], off[3]) / short.MaxValue; var tmp2 = max(tmp, -1f); tmp2.z *= -1; *resultV = normalize(tmp2); } #endif } [BurstCompile] unsafe struct ConvertTangentsInt8ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public int inputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public sbyte* input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float4* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float4*)((byte*)result + startIndex * outputByteStride); var off = input + startIndex * inputByteStride; for (var index = 0; index < count; index++) { var tmp = new float4(off[0], off[1], off[2], off[3]) / 127f; var tmp2 = max(tmp, -1f); tmp2.z *= -1; *resultV = normalize(tmp2); resultV = (float4*)((byte*)resultV + outputByteStride); off += inputByteStride; } } #else public void Execute(int index) { var resultV = (float4*)(((byte*)result) + (index * outputByteStride)); var off = input + (index * inputByteStride); var tmp = new float4(off[0], off[1], off[2], off[3]) / 127f; var tmp2 = max(tmp, -1f); tmp2.z *= -1; *resultV = normalize(tmp2); } #endif } [BurstCompile] unsafe struct ConvertPositionsUInt16ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityFloat3(); } #endif } [BurstCompile] unsafe struct ConvertPositionsUInt16ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityNormalizedFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityNormalizedFloat3(); } #endif } [BurstCompile] unsafe struct ConvertPositionsInt16ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; [ReadOnly] public int outputByteStride; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityFloat3(); } #endif } /// /// General purpose (position / morph target delta normal) /// Result is not normalized (scaled to unit length) /// [BurstCompile] unsafe struct ConvertVector3Int16ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityNormalizedFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityNormalizedFloat3(); } #endif } /// /// Normal conversion /// Result is normalized (scaled to unit length) /// [BurstCompile] unsafe struct ConvertNormalsInt16ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfNormalToUnityFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfNormalToUnityFloat3(); } #endif } [BurstCompile] unsafe struct ConvertPositionsInt8ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityFloat3(); } #endif } /// /// General purpose conversion (positions or morph target delta normals) /// Result is not normalized (scaled to unit length) /// [BurstCompile] unsafe struct ConvertVector3Int8ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityNormalizedFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityNormalizedFloat3(); } #endif } /// /// Normal conversion /// Result is normalized (scaled to unit length) /// [BurstCompile] unsafe struct ConvertNormalsInt8ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfNormalToUnityFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfNormalToUnityFloat3(); } #endif } [BurstCompile] unsafe struct ConvertPositionsUInt8ToFloatInterleavedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityFloat3(); } #endif } [BurstCompile] unsafe struct ConvertPositionsUInt8ToFloatInterleavedNormalizedJob : #if UNITY_COLLECTIONS IJobParallelForBatch #else IJobParallelFor #endif { [ReadOnly] public ReadOnlyNativeStridedArray input; [ReadOnly] public int outputByteStride; [ReadOnly] [NativeDisableUnsafePtrRestriction] public float3* result; #if UNITY_COLLECTIONS public void Execute(int startIndex, int count) { var resultV = (float3*)((byte*)result + startIndex * outputByteStride); var end = startIndex + count; for (var index = startIndex; index < end; index++) { *resultV = input[index].GltfToUnityNormalizedFloat3(); resultV = (float3*)((byte*)resultV + outputByteStride); } } #else public void Execute(int index) { var resultV = (float3*)(((byte*)result) + (index * outputByteStride)); *resultV = input[index].GltfToUnityNormalizedFloat3(); } #endif } [BurstCompile] unsafe struct ConvertBoneJointsUInt8ToUInt32Job : IJobParallelFor { [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int inputByteStride; [WriteOnly] [NativeDisableUnsafePtrRestriction] public uint4* result; [ReadOnly] public int outputByteStride; public void Execute(int index) { var resultV = (uint4*)(((byte*)result) + (index * outputByteStride)); var off = input + (index * inputByteStride); *resultV = new uint4(off[0], off[1], off[2], off[3]); } } [BurstCompile] unsafe struct ConvertBoneJointsUInt16ToUInt32Job : IJobParallelFor { [ReadOnly] [NativeDisableUnsafePtrRestriction] public byte* input; [ReadOnly] public int inputByteStride; [WriteOnly] [NativeDisableUnsafePtrRestriction] public uint4* result; [ReadOnly] public int outputByteStride; public void Execute(int index) { var resultV = (uint4*)(((byte*)result) + (index * outputByteStride)); var off = (ushort*)(input + (index * inputByteStride)); *resultV = new uint4(off[0], off[1], off[2], off[3]); } } [BurstCompile] struct SortAndNormalizeBoneWeightsJob : IJobParallelFor { public NativeArray bones; /// /// Number of skin weights that are taken into account (project quality setting) /// public int skinWeights; public unsafe void Execute(int index) { var v = bones[index]; // Most joints/weights are already sorted by weight // Detect and early return if true var sortedAndNormalized = true; for (var i = 0; i < 3; i++) { var a = v.weights[i]; var b = v.weights[i + 1]; if (a < b) { sortedAndNormalized = false; break; } } // Sort otherwise if (!sortedAndNormalized) { for (var i = 0; i < skinWeights; i++) { var max = v.weights[i]; var maxI = i; for (var j = i + 1; j < 4; j++) { var value = v.weights[j]; if (v.weights[j] > max) { max = value; maxI = j; } } if (maxI > i) { Swap(ref v, maxI, i); } } } // Calculate the sum of weights var weightSum = 0f; for (var i = 0; i < skinWeights; i++) { weightSum += v.weights[i]; } if (abs(weightSum - 1.0f) > 2e-7f && weightSum > 0) { sortedAndNormalized = false; // Re-normalize the weight sum for (var i = 0; i < skinWeights; i++) { v.weights[i] /= weightSum; } } if (!sortedAndNormalized) { bones[index] = v; } } static unsafe void Swap(ref VBones v, int a, int b) { (v.weights[a], v.weights[b]) = (v.weights[b], v.weights[a]); (v.joints[a], v.joints[b]) = (v.joints[b], v.joints[a]); } } #if GLTFAST_SAFE [BurstCompile] struct RenormalizeBoneWeightsJob : IJobParallelFor { public NativeArray bones; public unsafe void Execute(int index) { var v = bones[index]; // Calculate the sum of weights var weightSum = v.weights[0] + v.weights[1] + v.weights[2] + v.weights[3]; if (abs(weightSum - 1.0f) > 2e-7f && weightSum > 0) { // Re-normalize the weight sum for (var i = 0; i < 4; i++) { v.weights[i] /= weightSum; } } bones[index] = v; } } #endif [BurstCompile] struct ConvertMatricesJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { var tmp = input[index]; result[index] = new float4x4( tmp.c0.x, -tmp.c1.x, -tmp.c2.x, -tmp.c3.x, -tmp.c0.y, tmp.c1.y, tmp.c2.y, tmp.c3.y, -tmp.c0.z, tmp.c1.z, tmp.c2.z, tmp.c3.z, tmp.c0.w, tmp.c1.w, tmp.c2.w, tmp.c3.w ); } } [BurstCompile] struct ConvertScalarInt8ToFloatNormalizedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = max(input[index] / 127f, -1.0f); } } [BurstCompile] struct ConvertScalarUInt8ToFloatNormalizedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index] / 255f; } } [BurstCompile] struct ConvertScalarInt16ToFloatNormalizedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = max(input[index] / (float)short.MaxValue, -1.0f); } } [BurstCompile] struct ConvertScalarUInt16ToFloatNormalizedJob : IJobParallelFor { [ReadOnly] public NativeArray.ReadOnly input; [WriteOnly] public NativeArray result; public void Execute(int index) { result[index] = input[index] / (float)ushort.MaxValue; } } }