Exemple #1
0
        public static void RecalculateNormal(ReadOnlySpan <Vector3> positions, ReadOnlySpan <int> indices, Span <Vector3> normals)
        {
            if (indices.Length % 3 != 0)
            {
                ThrowArgumentIndicesLengthInvalid();
            }

            // [NOTE]
            // Sharp edge is not supported.

            normals.Clear();

            using var countsBuf = new ValueTypeRentMemory <int>(positions.Length, true);
            var counts = countsBuf.AsSpan();

            var faces = indices.MarshalCast <int, Face>();

            foreach (var f in faces)
            {
                var n = Vector3.Cross(positions[f.I1] - positions[f.I0], positions[f.I2] - positions[f.I0]).Normalized();
                normals[f.I0] += n;
                normals[f.I1] += n;
                normals[f.I2] += n;
                counts[f.I0]  += 1;
                counts[f.I1]  += 1;
                counts[f.I2]  += 1;
            }
            for (int i = 0; i < positions.Length; i++)
            {
                normals[i] /= counts[i];
            }
        }
Exemple #2
0
        public static void RecalculateNormal(Span <Vertex> vertices, ReadOnlySpan <int> indices)  // TODO: something wrong
        {
            if (indices.Length % 3 != 0)
            {
                ThrowArgumentIndicesLengthInvalid();
            }

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Normal = default;
            }

            using var counts = new ValueTypeRentMemory <int>(vertices.Length, true);
            var faces = indices.MarshalCast <int, Face>();

            foreach (var f in faces)
            {
                var n = Vector3.Cross(vertices[f.I1].Position - vertices[f.I0].Position, vertices[f.I2].Position - vertices[f.I0].Position).Normalized();
                vertices[f.I0].Normal += n;
                vertices[f.I1].Normal += n;
                vertices[f.I2].Normal += n;
                counts[f.I0]          += 1;
                counts[f.I1]          += 1;
                counts[f.I2]          += 1;
            }

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Normal /= counts[i];
            }
        }
 public void LargeRent(int length)
 {
     using (var memory = new ValueTypeRentMemory <int>(length, true)) {
         var span = memory.AsSpan();
         Assert.Equal(length, span.Length);
     }
 }
 public void RentEmpty()
 {
     using (var memory = new ValueTypeRentMemory <int>(0, true)) {
         Assert.True(memory.AsSpan().IsEmpty);
         Assert.Equal(0, memory.Length);
     }
 }
 public void RentMultiParallel()
 {
     Parallel.For(0, 100, i =>
     {
         using var mem = new ValueTypeRentMemory <int>(1000, false);
         Assert.Equal(1000, mem.Length);
         Assert.Equal(1000, mem.AsSpan().Length);
     });
 }
 public void Rent(int length)
 {
     using (var memory = new ValueTypeRentMemory <byte>(length, true)) {
         var span = memory.AsSpan();
         Assert.Equal(length, span.Length);
         foreach (var item in span)
         {
             Assert.Equal(0, item);
         }
     }
 }
Exemple #7
0
 internal FbxSemanticsUnsafe([MaybeNull] ref FbxObject fbx,
                             ref UnsafeRawArray <int> indices,
                             ref UnsafeRawArray <TVertex> vertices,
                             ref ValueTypeRentMemory <RawString> texture,
                             ref SkeletonDataList skeletons)
 {
     (_fbx, fbx)             = (fbx, default);
     (_textures, texture)    = (texture, default);
     (_indices, indices)     = (indices, default);
     (_vertices, vertices)   = (vertices, default);
     (_skeletons, skeletons) = (skeletons, default);
 }
Exemple #8
0
        public ModelList(FbxNode objectsNode)
        {
            var meshDic = new BufferPooledDictionary <long, MeshModel>();
            var limbDic = new BufferPooledDictionary <long, LimbNode>();
            var nullDic = new BufferPooledDictionary <long, NullModel>();

            try {
                using var indexBuf = new ValueTypeRentMemory <int>(objectsNode.Children.Count, false);
                var modelCount = objectsNode.FindChildIndexAll(FbxConstStrings.Model(), indexBuf.AsSpan());
                foreach (var i in indexBuf.AsSpan(0, modelCount))
                {
                    var modelNode = objectsNode.Children[i];
                    var modelType = modelNode.Properties[2].AsString().ToModelType();

                    switch (modelType)
                    {
                    case ModelType.LimbNode: {
                        var limb = new LimbNode(modelNode);
                        limbDic.Add(limb.ID, limb);
                        break;
                    }

                    case ModelType.Mesh: {
                        var meshModel = new MeshModel(modelNode);
                        meshDic.Add(meshModel.ID, meshModel);
                        break;
                    }

                    case ModelType.Null: {
                        var nullModel = new NullModel(modelNode);
                        nullDic.Add(nullModel.ID, nullModel);
                        break;
                    }

                    case ModelType.Unknown:
                    default:
                        break;
                    }
                }
                _meshDic = meshDic;
                _limbDic = limbDic;
                _nullDic = nullDic;
            }
            catch {
                meshDic.Dispose();
                limbDic.Dispose();
                nullDic.Dispose();
                throw;
            }
        }
 public void Load(ReadOnlySpan <T> data, bool asPowerOfTwoTexture = true)
 {
     ThrowIfNotMultipleOfFour(data.GetByteLength());
     if (asPowerOfTwoTexture)
     {
         _textureCore.LoadAsPOT(data.MarshalCast <T, Color4>());
     }
     else
     {
         _textureCore.Load(data.MarshalCast <T, Color4>());
     }
     _memory = new ValueTypeRentMemory <T>(data.Length, false);
     data.CopyTo(_memory.AsSpan());
 }
        public void RentMulti()
        {
            const int Count = 100;

            using var list = new Disposables <ValueTypeRentMemory <int> >();
            for (int i = 0; i < Count; i++)
            {
                var mem = new ValueTypeRentMemory <int>(1000, false);
                list.Add(mem);
            }
            for (int i = 0; i < Count; i++)
            {
                Assert.Equal(1000, list[i].Length);
                Assert.Equal(1000, list[i].AsSpan().Length);
            }
        }
Exemple #11
0
        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.
        }
Exemple #12
0
        internal static FbxSemanticsUnsafe <TVertex> ParseUnsafe(Stream stream, bool leaveStreamOpen = true, CancellationToken cancellationToken = default)
        {
            ValueTypeRentMemory <RawString> textures = default;
            FbxObject?fbx = null;

            try {
                var vertexCreator = SkinnedVertexCreator <TVertex> .Build();

                fbx = FbxParser.Parse(stream);
                using var resolver = new SemanticResolver(fbx);
                var objectsNode = resolver.ObjectsNode;
                var(meshes, skeletons) = ParseMeshAndSkeleton(resolver, vertexCreator, cancellationToken);
                try {
                    using (meshes) {
                        textures = ParseTexture(objectsNode, cancellationToken);
                        //ParseMaterial(objectsNode);
                        var(vertices, indices) = meshes.CreateCombined();
                        return(new FbxSemanticsUnsafe <TVertex>(ref fbx, ref indices, ref vertices, ref textures, ref skeletons));
                    }
                }
                catch {
                    skeletons.Dispose();
                    throw;
                }
            }
            catch {
                fbx?.Dispose();
                textures.Dispose();
                throw;
            }
            finally {
                if (leaveStreamOpen == false)
                {
                    stream?.Dispose();
                }
            }
        }
Exemple #13
0
 internal ValueTypeRentMemoryDebuggerTypeProxy(ValueTypeRentMemory <T> entity)
 {
     _entity = entity;
 }
Exemple #14
0
            static async UniTask BackToMainThread(ArrayTexture arrayTexture, Vector3i size, ValueTypeRentMemory <ColorByte> buffer, FrameTimingPoint timingPoint, CancellationToken ct)
            {
                try {
                    await timingPoint.Next(ct);

                    arrayTexture.Load(new(size.X, size.Y), size.Z, buffer.AsSpan());
                }
                finally {
                    buffer.Dispose();
                }
            }
Exemple #15
0
        private static UniTask BuildTexture(PMXObject pmx, ResourceFile pmxFile, Model3D model, UnsafeRawArray <SkinnedVertex> vertices, CancellationToken ct)
        {
            var arrayTexture = new ArrayTexture(TextureConfig.BilinearRepeat);

            model.AddComponent(arrayTexture);

            var dir             = ResourcePath.GetDirectoryName(pmxFile.Name);
            var textureNames    = pmx.TextureList.AsSpan();
            var resourcePackage = pmxFile.Package;

            var materials = pmx.MaterialList.AsSpan();

            using var matTexMem = new ValueTypeRentMemory <int>(materials.Length, true);
            var matTex = matTexMem.AsSpan();

            for (int i = 0; i < materials.Length; i++)
            {
                matTex[i] = materials[i].Texture;
            }
            matTex.Sort();
            var texCount = 0;

            if (matTex.Length > 0)
            {
                texCount = 1;
                for (int i = 1; i < matTex.Length; i++)
                {
                    if (matTex[i - 1] != matTex[i])
                    {
                        texCount++;
                    }
                }
            }

            using var textureUsed = new ValueTypeRentMemory <bool>(textureNames.Length, true);

            var size   = new Vector2i(1024, 1024);  // TODO:
            var count  = 0;
            var buffer = new ValueTypeRentMemory <ColorByte>(size.X * size.Y * texCount, false);

            try {
                for (int i = 0; i < textureNames.Length; i++)
                {
                    if (matTex.Contains(i) == false)
                    {
                        continue;
                    }

                    using var _ = GetTexturePath(dir, textureNames[i], out var texturePath, out var ext);
                    var path = texturePath.ToString();

                    // Some pmx have the texture paths that don't exist. (Nobody references them.)
                    // So skip them.
                    if (resourcePackage.TryGetStream(path, out var stream) == false)
                    {
                        continue;
                    }
                    textureUsed[i] = true;
                    var dest = buffer.AsSpan(count * size.X * size.Y);
                    try {
                        using var image = Image.LoadToImageSource(stream, Image.GetTypeFromExt(ext));
                        if (image.Width != size.X || image.Height != size.Y)
                        {
                            using var resized = Image.Resized(image, size);
                            resized.GetPixels().CopyTo(dest);
                        }
                        else
                        {
                            image.GetPixels().CopyTo(dest);
                        }
                        count++;
                    }
                    finally {
                        stream.Dispose();
                    }
                }

                // Calculate texture index of each vertex
                {
                    var indices = pmx.SurfaceList.AsSpan().MarshalCast <Surface, int>();
                    int i       = 0;
                    foreach (var mat in materials)
                    {
                        for (int j = 0; j < mat.VertexCount; j++)
                        {
                            var unusedCount = 0;
                            foreach (var isUsed in textureUsed.AsSpan(0, mat.Texture))
                            {
                                if (isUsed == false)
                                {
                                    unusedCount++;
                                }
                            }
                            vertices[indices[i++]].TextureIndex = mat.Texture - unusedCount;
                        }
                    }
                }
            }
            catch {
                buffer.Dispose();
                throw;
            }
            return(BackToMainThread(arrayTexture, new Vector3i(size.X, size.Y, count), buffer, model.Screen !.TimingPoints.Update, ct));