private static async UniTask Build(StateObject state, Model3D model, Model3DLoadMeshDelegate load) { var(file, ct) = state; var screen = model.GetValidScreen(); ct.ThrowIfCancellationRequested(); await UniTask.SwitchToThreadPool(); ct.ThrowIfCancellationRequested(); using var verticesBuffer = new UnsafeBufferWriter <Vertex>(); using var indicesBuffer = new UnsafeBufferWriter <int>(); ParseFromFile(file, verticesBuffer, indicesBuffer); await screen.TimingPoints.Update.Next(ct); load.Invoke(verticesBuffer.WrittenSpan, indicesBuffer.WrittenSpan); }
private static async UniTask Build(StateObject state, Model3D model, Model3DLoadMeshDelegate load) { //var (resourceLoader, name, token) = obj; var(file, token) = state; var screen = model.GetValidScreen(); var timingPoints = screen.TimingPoints; token.ThrowIfCancellationRequested(); await UniTask.SwitchToThreadPool(); // ↓ thread pool -------------------------------------- token.ThrowIfCancellationRequested(); // Parse fbx file using var fbx = FbxSemanticParser <SkinnedVertex> .ParseUnsafe(file.GetStream(), false, token); await timingPoints.Update.Next(token); // ↓ main thread -------------------------------------- await CreateTexture(file, fbx, model); // Create a skeleton component if (fbx.Skeletons.IsEmpty == false) { var skeletonIndex = 0; var skeleton = new HumanoidSkeleton(); model.AddComponent(skeleton); using var bones = new ValueTypeRentMemory <Bone>(fbx.Skeletons[skeletonIndex].BoneCount, false); fbx.Skeletons[skeletonIndex].CreateBones(bones.AsSpan()); await skeleton.LoadAsync(bones, timingPoints, cancellationToken : token); } load.Invoke(fbx.Vertices, fbx.Indices); await UniTask.SwitchToThreadPool(); // ↓ thread pool -------------------------------------- // 'using' scope ends here. Dispose resources on a thread pool. // Nobody knows the thread if exceptions are thrown in this method, // but I don't care about that. }
private static async UniTask LoadToModel(PMXObject pmx, Model3D model, Model3DLoadMeshDelegate load, ModelState obj) { // ------------------------------ // ↓ thread pool Debug.Assert(Engine.IsThreadMain == false); var screen = model.GetValidScreen(); // Don't make the followings parallel like UniTask.WhenAll. // ModelData will be disposed when an exception is throw, but another parallel code could not know that. using var vertices = GetVertices(pmx); using var bones = GetBones(pmx); await BuildTexture(pmx, obj.File, model, vertices, obj.CancellationToken); await UniTask.SwitchToThreadPool(); var skeleton = new HumanoidSkeleton(); model.AddComponent(skeleton); await skeleton.LoadAsync(bones.AsSpanLike(), screen.TimingPoints, obj.CancellationToken); // ↑ thread pool // ------------------------------ await screen.TimingPoints.Update.NextOrNow(obj.CancellationToken); // ------------------------------ // ↓ main thread Debug.Assert(Engine.CurrentContext == screen); Debug.Assert(model.LifeState == LifeState.Activating); model.Shader ??= new PmxModelShader(); // load vertices and indices load.Invoke(vertices.AsSpan().AsReadOnly(), pmx.SurfaceList.AsSpan().MarshalCast <Surface, int>()); // ↑ main thread // ------------------------------ }