private void InitializeFoundFilesObjects(IEnumerable <string> paths)
 {
     FilesFound = new ModelFileData[paths.Count()];
     for (int i = 0; i < paths.Count(); i++)
     {
         string path = paths.ElementAt(i);
         FilesFound[i] = new ModelFileData(path);
     }
     ReadyToCacheCheckList = new ConcurrentQueue <ModelFileData>(FilesFound);
     FilesToProcess        = FilesFound.Length;
 }
        public bool LoadDirectories(IEnumerable <string> paths)
        {
            IsLoading               = false;
            MainDispatcher          = Dispatcher.CurrentDispatcher;
            cancellationTokenSource = new CancellationTokenSource();
            cancellationToken       = cancellationTokenSource.Token;

            cache        = DefaultFactory.GetDefaultThumbnailCache();
            userSettings = DefaultFactory.GetDefaultUserSettings();
            renderType   = (RenderAspectEnum)userSettings.GetSettingInt(UserSettingEnum.Thumbnails3DAspect);

            logger.Info("Loading paths: Received: [{0}]", string.Join("] [", paths));
            paths = paths.Where(p1 => !paths.Any(p2 => !p1.Equals(p2) && p1.Contains(p2))).ToArray(); // Remove selected subdirectories of other selected paths.
            logger.Info("Loading paths: After removed subdirs: [{0}]", string.Join("] [", paths));

            try
            {
                IEnumerable <string> pathsFound = new List <string>();
                for (int i = 0; i < SupportedExtensionsFilter.Length; i++)
                {
                    foreach (string path in paths)
                    {
                        pathsFound = pathsFound.Concat(UtilMethods.EnumerateFiles(path, SupportedExtensionsFilter[i], SearchOption.AllDirectories, cancellationToken));
                    }
                }
                pathsFound = pathsFound.ToArray();

                if (cancellationToken.IsCancellationRequested)
                {
                    return(false);
                }

                if (pathsFound.Count() > 0)
                {
                    CalculateThumnailSizes(pathsFound.Count());
                    InitializeFoundFilesObjects(pathsFound);
                    return(true);
                }
                else
                {
                    FilesFound = new ModelFileData[0];
                }
            }
            catch (Exception ex)
            {
                logger.Trace(ex, "Unable to load: {ex}", ex.Message);
            }
            return(false);
        }
Exemple #3
0
        public View3D(HelixViewport3D viewport)
        {
            this.Viewport = viewport;

            _originalCameraPosition = new Point3D(100f, -100f, 135f);
            _modelCameraPosition    = _originalCameraPosition;
            _modelHeightPosition    = (float)(_originalCameraPosition.Z / 2d);

            viewport.Camera.UpDirection   = new Vector3D(0, 0, 1);
            viewport.Camera.Position      = _originalCameraPosition;
            viewport.Camera.LookDirection = new Vector3D(-1, 1, -1);

            Viewport.ShowCameraInfo             = false;
            Viewport.ShowViewCube               = false;
            Viewport.ShowCameraTarget           = false;
            Viewport.ZoomAroundMouseDownPoint   = false;
            Viewport.RotateAroundMouseDownPoint = false;
            Viewport.SnapMouseDownPoint         = true;
            Viewport.FixedRotationPointEnabled  = true;
            Viewport.FixedRotationPoint         = new Point3D(0f, 0f, 30f);
            Viewport.IsZoomEnabled              = false;

            Viewport.MouseWheel    += Viewport_MouseWheel;
            Viewport.CameraChanged += Viewport_CameraChanged;

            Viewport.IsMoveEnabled         = false;
            Viewport.IsPanEnabled          = true;
            Viewport.IsManipulationEnabled = false;
            Viewport.IsHeadLightEnabled    = false;

            Viewport.RotationSensitivity = 1;
            Viewport.ClipToBounds        = true;

            Viewport.LimitFPS      = true;
            Viewport.ShowFrameRate = false;
            Viewport.SubTitleSize  = 18d;

            ModelAutoRotationEnabled = true;

            GridLinesVisual3D FloorGridLines;

            FloorGridLines               = new GridLinesVisual3D();
            FloorGridLines.Fill          = Brushes.Gray;
            FloorGridLines.Width         = 15000;
            FloorGridLines.Thickness     = 1;
            FloorGridLines.Length        = FloorGridLines.Width;
            FloorGridLines.MajorDistance = 100;
            FloorGridLines.MinorDistance = 10;
            FloorGridLines.Center        = new Point3D(0, 0, 0);

            UpdateLights();
            Viewport.Children.Add(FloorGridLines);

            Viewport.IsVisibleChanged += (sender, e) =>
            {
                if (ModelDataToLoadWhenVisible != null && this.Viewport.IsVisible)
                {
                    SetModel(ModelDataToLoadWhenVisible);
                    ModelDataToLoadWhenVisible = null;
                }
            };

            Viewport.SizeChanged += (sender, e) =>
            {
                if (e.NewSize.Width < 5 && this.Viewport.IsVisible)
                {
                    Viewport.Visibility = Visibility.Hidden;
                }
                else if (e.NewSize.Width >= 5 && !this.Viewport.IsVisible)
                {
                    Viewport.Visibility = Visibility.Visible;
                }
            };
        }
Exemple #4
0
        private void SetModelTask(ModelFileData modelData)
        {
            if (CurrentModelVisual != null)
            {
                this.Viewport.Children.Remove(CurrentModelVisual);
                CurrentModelVisual = null;
                GC.Collect(0, GCCollectionMode.Forced);
            }

            if (!this.Viewport.IsVisible)
            {
                this.ModelDataToLoadWhenVisible = modelData;
                return;
            }

            Model3DGroup  modelGroup  = new Model3DGroup();
            ModelVisual3D modelVisual = new ModelVisual3D();

            try
            {
                if (modelData != null)
                {
                    ModelFileData newModelData = new ModelFileData(modelData.FileFullPath);
                    this.ModelData    = newModelData;
                    Viewport.SubTitle = modelData.FileName;

                    newModelData.LoadBasicFileData();

                    if (userSettings.GetSettingBool(UserSettingEnum.EnableMaxSizeMBToLoadMeshInView) && modelData.FileSizeMB > userSettings.GetSettingInt(UserSettingEnum.MaxSizeMBToLoadMeshInView))
                    {
                        // TODO: Load generic model.
                        Viewport.SubTitle  = Loc.GetTextFormatted("FileSizeTooBigToLoadMB", modelData.FileSizeMB, userSettings.GetSettingInt(UserSettingEnum.MaxSizeMBToLoadMeshInView));
                        CurrentModelVisual = null;
                        return;
                    }

                    if (!newModelData.HasBytes())
                    {
                        newModelData.LoadFileBytes(newModelData.FileSizeMB < 50f);
                    }
                    if (newModelData.Mesh == null)
                    {
                        newModelData.ParseFile();
                    }
                    newModelData.ReleaseData(true, false);

                    if (newModelData.Mesh == null)
                    {
                        newModelData.ReleaseData(true, false);
                        SetModel(null);
                        return;
                    }

                    LoadModelInfoAvailableEvent?.Invoke(newModelData.FileName, newModelData.Mesh.TriangleCount, newModelData.Mesh.Vertices.Length, (int)newModelData.FileSizeKB);

                    float modelScale         = newModelData.Mesh.Scale / 4f;
                    float modelScaleMultiply = (newModelData.Mesh.Scale < 0.001f ? 0.1f : (newModelData.Mesh.Scale > 0.1 ? 10f : 1));


                    var transformTranslate           = new TranslateTransform3D(-newModelData.Mesh.OffsetX, -newModelData.Mesh.OffsetY, -newModelData.Mesh.OffsetZ);
                    AxisAngleRotation3D axisRotation = new AxisAngleRotation3D(new Vector3D(0, 0, 1), 0);
                    transformObjectRotation = new RotateTransform3D(axisRotation, new Point3D(newModelData.Mesh.OffsetX, newModelData.Mesh.OffsetY, 0));
                    ScaleTransform3D transformScale = new ScaleTransform3D(modelScaleMultiply, modelScaleMultiply, modelScaleMultiply);

                    Transform3DGroup transforms = new Transform3DGroup();
                    transforms.Children.Add(transformObjectRotation);
                    transforms.Children.Add(transformTranslate);
                    transforms.Children.Add(transformScale);

                    Mesh3D mesh;

                    // Mesh decimation if enabled
                    if (userSettings.GetSettingBool(UserSettingEnum.EnableMeshDecimation) && newModelData.Mesh.TriangleCount > userSettings.GetSettingInt(UserSettingEnum.MinTrianglesForMeshDecimation))
                    {
                        MeshDecimator.Math.Vector3d[] vectors3D = newModelData.Mesh.Vertices.Select(v => new MeshDecimator.Math.Vector3d(v.x, v.y, v.z)).ToArray();
                        Mesh decimatorMesh = new Mesh(vectors3D, newModelData.Mesh.Triangles.ToArray());

                        Mesh decimatedMesh = MeshDecimation.DecimateMeshLossless(decimatorMesh);
                        mesh = new Mesh3D(decimatedMesh.Vertices.Select(v => new Point3D(v.x, v.y, v.z)), decimatedMesh.Indices);

                        // TODO: Possibly cache the decimated models to avoid re-processing.
                    }
                    else
                    {
                        mesh = new Mesh3D(Point3DFromLinearCoordinates(newModelData.Mesh.Vertices), newModelData.Mesh.Triangles);
                    }
                    GeometryModel3D geometryModel = new GeometryModel3D(mesh.ToMeshGeometry3D(), GetMaterial());
                    geometryModel.Freeze();

                    modelGroup.Children.Add(geometryModel);
                    modelGroup.Freeze();

                    _modelHeightPosition = newModelData.Mesh.Height * modelScaleMultiply;
                    newModelData.ReleaseData(true, true);

                    // Animation
                    if (ModelAutoRotationEnabled)
                    {
                        DoubleAnimation animation1 = new DoubleAnimation(-90, 395d, TimeSpan.FromMilliseconds(1000));
                        animation1.EasingFunction = new ExponentialEase();

                        DoubleAnimation animation2 = new DoubleAnimation(36d, 395d, TimeSpan.FromMilliseconds(7000));
                        animation2.RepeatBehavior = RepeatBehavior.Forever;

                        animation1.Completed += (o, e) => axisRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, animation2);
                        axisRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, animation1);
                    }

                    // Camera animation
                    var nomalizedOriginalPosition = _originalCameraPosition.ToVector3D();
                    nomalizedOriginalPosition.Normalize();
                    _modelCameraPosition = new Point3D(nomalizedOriginalPosition.X / modelScale * modelScaleMultiply, nomalizedOriginalPosition.Y / modelScale * modelScaleMultiply, nomalizedOriginalPosition.Z / modelScale * modelScaleMultiply);

                    Point3D targetCameraPosition = _modelCameraPosition;
                    if (_CurrentCameraPosition == CameraPositionEnum.Default)
                    {
                        var normalizedPosition = Viewport.Camera.Position.ToVector3D();
                        normalizedPosition.Normalize();
                        targetCameraPosition = new Point3D(normalizedPosition.X / modelScale * modelScaleMultiply, normalizedPosition.Y / modelScale * modelScaleMultiply, normalizedPosition.Z / modelScale * modelScaleMultiply);

                        Viewport.Camera.AnimateTo(targetCameraPosition, Viewport.Camera.LookDirection, Viewport.Camera.UpDirection, 500d);
                    }
                    else
                    {
                        ResetCamera(CameraPositionEnum.Current);
                    }

                    minZoom = targetCameraPosition.Multiply(0.5d).DistanceTo(new Point3D());
                    maxZoom = minZoom * 4d;

                    this.CurrentAxisRotation = axisRotation;
                    modelVisual.Transform    = transforms;
                }
                modelVisual.Content = modelGroup;
                this.Viewport.Children.Add(modelVisual);

                this.CurrentModelVisual = modelVisual;
            }
            catch (Exception ex)
            {
                if (CurrentModelVisual != null)
                {
                    this.Viewport.Children.Add(CurrentModelVisual);
                    this.CurrentModelVisual = null;
                }
            }
            if (modelData == null)
            {
                _modelCameraPosition = _originalCameraPosition;
                ResetCamera(CameraPositionEnum.Default, true);
                LoadModelInfoAvailableEvent?.Invoke("", 0, 0, 0);
                _modelHeightPosition = (float)(_originalCameraPosition.Z / 2d);
                Viewport.SubTitle    = string.Empty;
            }
            GC.Collect();
        }
Exemple #5
0
 public void SetModel(ModelFileData modelData)
 {
     // TODO: Run in a cancellable task.
     SetModelTask(modelData);
 }
Exemple #6
0
        public void Load(System.IO.Stream stream)
        {
            DrawableContainer.Name = FileName;
            Renderer = new PunchOutWii_Renderer();
            DrawableContainer.Drawables.Add(Renderer);

            Text = FileName;

            HeaderFile = new DictionaryFile();
            HeaderFile.Read(new FileReader(stream), FilePath);

            var HashList = NLG_Common.HashNames;

            string DataFile = $"{FilePath.Replace(".dict", ".data")}";

            if (System.IO.File.Exists(DataFile))
            {
                using (var reader = new FileReader(DataFile, true))
                {
                    reader.SetByteOrder(true);

                    TreeNode blocks      = new TreeNode("Blocks");
                    TreeNode chunks      = new TreeNode("Chunks");
                    TreeNode modelFolder = new TreeNode("Models");

                    foreach (var blockInfo in HeaderFile.Blocks)
                    {
                        ChunkViewer chunkNode = new ChunkViewer("block");
                        if (blockInfo.Size > 0)
                        {
                            blocks.Nodes.Add(chunkNode);
                        }

                        chunkNode.FileData = new SubStream(reader.BaseStream, blockInfo.Offset, blockInfo.Size);
                    }

                    List <PO_Texture> currentTextures = new List <PO_Texture>();

                    List <ModelFileData> modelData = new List <ModelFileData>();

                    ModelFileData currentModel = null;

                    STTextureFolder textureFolder = new STTextureFolder("Textures");
                    Nodes.Add(blocks);
                    Nodes.Add(chunks);

                    Nodes.Add(textureFolder);
                    Nodes.Add(modelFolder);

                    foreach (var chunk in HeaderFile.DataChunks)
                    {
                        if (chunk.BlockIndex == -1)
                        {
                            continue;
                        }

                        ChunkViewer chunkNode = new ChunkViewer(chunk.Type.ToString("") + " " + chunk.Type.ToString("X"));
                        chunks.Nodes.Add(chunkNode);

                        var blockInfo = HeaderFile.Blocks[chunk.BlockIndex];
                        if (blockInfo.Offset + chunk.Offset + chunk.Size > reader.BaseStream.Length)
                        {
                            continue;
                        }

                        chunkNode.FileData = new SubStream(reader.BaseStream, blockInfo.Offset + chunk.Offset, chunk.Size);

                        uint chunkPos = blockInfo.Offset + chunk.Offset;

                        reader.SeekBegin(chunkPos);
                        switch (chunk.Type)
                        {
                        case SectionMagic.MaterialData:
                            currentModel = new ModelFileData();
                            currentModel.MaterialOffset = chunkPos;
                            modelData.Add(currentModel);
                            break;

                        case SectionMagic.TextureHeaders:
                            uint numTextures = chunk.Size / 96;
                            for (int i = 0; i < numTextures; i++)
                            {
                                var tex = new PO_Texture();
                                tex.ImageKey         = "texture";
                                tex.SelectedImageKey = "texture";

                                tex.Read(reader);
                                tex.Text = tex.HashID.ToString("X");
                                if (HashList.ContainsKey(tex.HashID))
                                {
                                    tex.Text = HashList[tex.HashID];
                                }

                                currentTextures.Add(tex);
                                Renderer.TextureList.Add(tex.Text, tex);

                                textureFolder.Nodes.Add(tex);
                            }
                            break;

                        case SectionMagic.TextureData:
                            for (int i = 0; i < currentTextures.Count; i++)
                            {
                                reader.SeekBegin(chunkPos + currentTextures[i].DataOffset);
                                currentTextures[i].ImageData = reader.ReadBytes((int)currentTextures[i].ImageSize);
                            }
                            break;

                        case SectionMagic.IndexData:
                            currentModel.indexBufferOffset = chunkPos;
                            break;

                        case SectionMagic.VertexData:
                            currentModel.vertexBufferOffset = chunkPos;
                            break;

                        case SectionMagic.MeshData:
                            uint numMeshes = chunk.Size / 52;
                            for (int i = 0; i < numMeshes; i++)
                            {
                                reader.SeekBegin(chunkPos + (i * 52));
                                PO_Mesh mesh = new PO_Mesh(reader);
                                currentModel.meshes.Add(mesh);
                            }
                            break;

                        case SectionMagic.VertexAttributePointerData:
                            uint numAttributes = chunk.Size / 8;
                            for (int i = 0; i < numAttributes; i++)
                            {
                                PO_VertexAttribute att = new PO_VertexAttribute();
                                att.Offset = reader.ReadUInt32();
                                att.Type   = reader.ReadByte();
                                att.Stride = reader.ReadByte();
                                reader.ReadUInt16();
                                currentModel.attributes.Add(att);
                            }
                            break;

                        case SectionMagic.ModelData:
                            uint numModels = chunk.Size / 12;
                            Console.WriteLine($"numModels {numModels}");
                            for (int i = 0; i < numModels; i++)
                            {
                                PO_Model mdl = new PO_Model();
                                mdl.ParentDictionary = this;
                                mdl.HashID           = reader.ReadUInt32();
                                mdl.NumMeshes        = reader.ReadUInt32();
                                reader.ReadUInt32();     //0
                                currentModel.models.Add(mdl);
                            }
                            break;

                        case SectionMagic.BoneData:
                            STSkeleton Skeleton = new STSkeleton();
                            DrawableContainer.Drawables.Add(Skeleton);

                            uint numBones = chunk.Size / 68;
                            for (int i = 0; i < numBones; i++)
                            {
                                reader.SeekBegin(chunkPos + (i * 68));

                                uint HashID = reader.ReadUInt32();
                                reader.ReadUInt32();     //unk
                                reader.ReadUInt32();     //unk
                                reader.ReadUInt32();     //unk
                                reader.ReadSingle();     //0

                                STBone bone  = new STBone(Skeleton);
                                var    Scale = new OpenTK.Vector3(
                                    reader.ReadSingle(),
                                    reader.ReadSingle(),
                                    reader.ReadSingle());
                                reader.ReadSingle();     //0
                                bone.EulerRotation = new OpenTK.Vector3(
                                    reader.ReadSingle(),
                                    reader.ReadSingle(),
                                    reader.ReadSingle());
                                reader.ReadSingle();     //0
                                bone.Position = new OpenTK.Vector3(
                                    reader.ReadSingle(),
                                    reader.ReadSingle(),
                                    reader.ReadSingle());
                                reader.ReadSingle();     //1

                                bone.Text = HashID.ToString("X");
                                if (NLG_Common.HashNames.ContainsKey(HashID))
                                {
                                    bone.Text = NLG_Common.HashNames[HashID];
                                }
                                else
                                {
                                    Console.WriteLine($"bone hash {HashID}");
                                }

                                bone.Scale = new Vector3(0.2f, 0.2f, 0.2f);

                                bone.RotationType = STBone.BoneRotationType.Euler;
                                Skeleton.bones.Add(bone);
                            }

                            Skeleton.reset();
                            Skeleton.update();
                            break;
                        }
                    }

                    foreach (var modelFile in modelData)
                    {
                        int pointerIndex = 0;
                        foreach (var model in modelFile.models)
                        {
                            model.Text = model.HashID.ToString("X");
                            if (HashList.ContainsKey(model.HashID))
                            {
                                model.Text = HashList[model.HashID];
                            }

                            modelFolder.Nodes.Add(model);
                            for (int i = 0; i < model.NumMeshes; i++)
                            {
                                var mesh = modelFile.meshes[i];

                                RenderableMeshWrapper genericMesh = new RenderableMeshWrapper();
                                model.Nodes.Add(genericMesh);
                                model.RenderedMeshes.Add(genericMesh);
                                Renderer.Meshes.Add(genericMesh);

                                genericMesh.Text = mesh.HashID.ToString("X");
                                if (HashList.ContainsKey(mesh.HashID))
                                {
                                    genericMesh.Text = HashList[mesh.HashID];
                                }

                                string material = mesh.MaterialHashID.ToString("X");
                                if (HashList.ContainsKey(mesh.MaterialHashID))
                                {
                                    material = HashList[mesh.MaterialHashID];
                                }
                                genericMesh.Nodes.Add(material);


                                genericMesh.Material = new STGenericMaterial();

                                reader.SeekBegin(modelFile.MaterialOffset + mesh.MaterialOffset);
                                switch (mesh.MaterailPreset)
                                {
                                case MaterailPresets.EnvDiffuseDamage:
                                {
                                    uint diffuseMapHashID    = reader.ReadUInt32();
                                    uint diffuseMapParam     = reader.ReadUInt32();
                                    uint envSpecMapHashID    = reader.ReadUInt32();
                                    uint envSpecMapParam     = reader.ReadUInt32();
                                    uint specMapHashID       = reader.ReadUInt32();
                                    uint specMapParam        = reader.ReadUInt32();
                                    uint megaStrikeMapHashID = reader.ReadUInt32();
                                    uint megaStrikeMapParam  = reader.ReadUInt32();
                                    uint dirtMapHashID       = reader.ReadUInt32();
                                    uint dirtMapParam        = reader.ReadUInt32();
                                    uint iceMapHashID        = reader.ReadUInt32();
                                    uint iceMapParam         = reader.ReadUInt32();

                                    string diffuseName = diffuseMapHashID.ToString("X");
                                    if (HashList.ContainsKey(diffuseMapHashID))
                                    {
                                        diffuseName = HashList[diffuseMapHashID];
                                    }

                                    var texUnit = 1;
                                    genericMesh.Material.TextureMaps.Add(new STGenericMatTexture()
                                        {
                                            textureUnit = texUnit++,
                                            Type        = STGenericMatTexture.TextureType.Diffuse,
                                            Name        = diffuseName,
                                        });
                                }
                                break;

                                default:
                                {
                                    uint   diffuseMapHashID = reader.ReadUInt32();
                                    string diffuseName      = diffuseMapHashID.ToString("X");
                                    if (HashList.ContainsKey(diffuseMapHashID))
                                    {
                                        diffuseName = HashList[diffuseMapHashID];
                                    }

                                    Console.WriteLine($"diffuseName {diffuseName}");

                                    var texUnit = 1;
                                    genericMesh.Material.TextureMaps.Add(new STGenericMatTexture()
                                        {
                                            textureUnit = texUnit++,
                                            Type        = STGenericMatTexture.TextureType.Diffuse,
                                            Name        = diffuseName,
                                        });
                                }
                                break;
                                }

                                Console.WriteLine($"mesh {i}");

                                STGenericPolygonGroup polyGroup = new STGenericPolygonGroup();
                                genericMesh.PolygonGroups.Add(polyGroup);
                                reader.SeekBegin(modelFile.indexBufferOffset + mesh.IndexStartOffset);

                                List <int> faces = new List <int>();
                                for (int f = 0; f < mesh.IndexCount; f++)
                                {
                                    if (mesh.IndexFormat == 0)
                                    {
                                        polyGroup.faces.Add(reader.ReadUInt16());
                                    }
                                    else
                                    {
                                        polyGroup.faces.Add(reader.ReadByte());
                                    }
                                }

                                if (mesh.FaceType == PO_Mesh.PolygonType.TriangleStrips)
                                {
                                    polyGroup.PrimativeType = STPrimitiveType.TrangleStrips;
                                }
                                else
                                {
                                    polyGroup.PrimativeType = STPrimitiveType.Triangles;
                                }


                                for (int a = 0; a < mesh.NumAttributePointers; a++)
                                {
                                    Console.WriteLine($"pointer {genericMesh.Text} { modelFile.vertexBufferOffset + modelFile.attributes[pointerIndex + a].Offset}");
                                }

                                for (int v = 0; v < mesh.VertexCount; v++)
                                {
                                    Vertex vert = new Vertex();
                                    genericMesh.vertices.Add(vert);

                                    int attributeIndex = 0;
                                    for (int a = 0; a < mesh.NumAttributePointers; a++)
                                    {
                                        var pointer = modelFile.attributes[pointerIndex + a];
                                        reader.SeekBegin(modelFile.vertexBufferOffset + pointer.Offset + (pointer.Stride * v));

                                        if (attributeIndex == 0)
                                        {
                                            if (pointer.Stride == 12)
                                            {
                                                vert.pos = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                                            }
                                        }
                                        if (attributeIndex == 1)
                                        {
                                            if (pointer.Stride == 12)
                                            {
                                                vert.nrm = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                                            }
                                        }
                                        if (attributeIndex == 2)
                                        {
                                            if (pointer.Stride == 4)
                                            {
                                                vert.uv0 = new Vector2(reader.ReadUInt16() / 1024f, reader.ReadUInt16() / 1024f);
                                            }
                                        }

                                        /*     if (pointer.Type == 0xD4)
                                         *   {
                                         *       vert.boneIds = new List<int>() { reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte() };
                                         *   }
                                         *   if (pointer.Type == 0xB0)
                                         *   {
                                         *       vert.boneWeights = new List<float>() { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
                                         *   }*/

                                        attributeIndex++;
                                    }
                                }

                                genericMesh.TransformPosition(new Vector3(0), new Vector3(-90, 0, 0), new Vector3(1));

                                pointerIndex += mesh.NumAttributePointers;
                            }
                        }
                    }
                }
            }
        }