コード例 #1
0
ファイル: MLOD.cs プロジェクト: Onebeld/Regul
            public Mesh(EventHandler handler, MLOD owner)
                : base(handler)
            {
                mOwner = owner;

                mMaterialIndex       = new GenericRCOLResource.GenericRCOLResource.ChunkReference(handler, 0);
                mVertexFormatIndex   = new GenericRCOLResource.GenericRCOLResource.ChunkReference(handler, 0);
                mVertexBufferIndex   = new GenericRCOLResource.GenericRCOLResource.ChunkReference(handler, 0);
                mIndexBufferIndex    = new GenericRCOLResource.GenericRCOLResource.ChunkReference(handler, 0);
                mBounds              = new BoundingBox(handler);
                mSkinControllerIndex = new GenericRCOLResource.GenericRCOLResource.ChunkReference(handler, 0);
                mJointReferences     = new UIntList(handler);
                mGeometryStates      = new GeometryStateList(handler);
                mScaleOffsetIndex    = new GenericRCOLResource.GenericRCOLResource.ChunkReference(handler, 0);
                mMirrorPlane         = new Vector4(handler);//mOwner.Version > 0x00000201
            }
コード例 #2
0
            private void Parse(Stream s)
            {
                BinaryReader br           = new BinaryReader(s);
                long         expectedSize = br.ReadUInt32();
                long         start        = s.Position;

                mName              = br.ReadUInt32();
                mMaterialIndex     = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, s);
                mVertexFormatIndex = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, s);
                mVertexBufferIndex = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, s);
                mIndexBufferIndex  = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, s);
                uint val = br.ReadUInt32();

                mPrimitiveType       = (ModelPrimitiveType)(val & 0x000000FF);
                mFlags               = (MeshFlags)(val >> 8);
                mStreamOffset        = br.ReadUInt32();
                mStartVertex         = br.ReadInt32();
                mStartIndex          = br.ReadInt32();
                mMinVertexIndex      = br.ReadInt32();
                mVertexCount         = br.ReadInt32();
                mPrimitiveCount      = br.ReadInt32();
                mBounds              = new BoundingBox(0, handler, s);
                mSkinControllerIndex = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, s);
                mJointReferences     = new UIntList(handler, s);
                mScaleOffsetIndex    = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, s);
                mGeometryStates      = new GeometryStateList(handler, s);
                if (mOwner.Version > 0x00000201)
                {
                    mParentName  = br.ReadUInt32();
                    mMirrorPlane = new Vector4(0, handler, s);
                }
                if (mOwner.Version > 0x00000203)
                {
                    mUnknown1 = br.ReadUInt32();
                }
                long actualSize = s.Position - start;

                if (checking && actualSize != expectedSize)
                {
                    throw new Exception(String.Format("Expected end at {0}, actual end was {1}", expectedSize,
                                                      actualSize));
                }
            }
コード例 #3
0
            public Mesh(int apiVersion, EventHandler handler, MLOD owner,
                        uint name,
                        GenericRCOLResource.ChunkReference materialIndex, GenericRCOLResource.ChunkReference vertexFormatIndex,
                        GenericRCOLResource.ChunkReference vertexBufferIndex, GenericRCOLResource.ChunkReference indexBufferIndex,
                        ModelPrimitiveType primitiveType, MeshFlags flags,
                        uint streamOffset, int startVertex, int startIndex, int minVertexIndex, int vertexCount, int primitiveCount,
                        BoundingBox bounds, GenericRCOLResource.ChunkReference skinControllerIndex,
                        UIntList jointReferences, GeometryStateList geometryStates, GenericRCOLResource.ChunkReference scaleOffsetIndex,
                        uint parentName, Vector4 mirrorPlane, uint unknown1
                        )
                : base(apiVersion, handler)
            {
                mOwner = owner;

                mName                = name;
                mMaterialIndex       = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, materialIndex);
                mVertexFormatIndex   = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, vertexFormatIndex);
                mVertexBufferIndex   = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, vertexBufferIndex);
                mIndexBufferIndex    = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, indexBufferIndex);
                mPrimitiveType       = primitiveType;
                mFlags               = flags;
                mStreamOffset        = streamOffset;
                mStartVertex         = startVertex;
                mStartIndex          = startIndex;
                mMinVertexIndex      = minVertexIndex;
                mVertexCount         = vertexCount;
                mPrimitiveCount      = primitiveCount;
                mBounds              = new BoundingBox(requestedApiVersion, handler, bounds);
                mSkinControllerIndex = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, skinControllerIndex);
                mJointReferences     = jointReferences == null ? null : new UIntList(handler, jointReferences);
                mGeometryStates      = geometryStates == null ? null : new GeometryStateList(handler, geometryStates);
                mScaleOffsetIndex    = new GenericRCOLResource.ChunkReference(requestedApiVersion, handler, scaleOffsetIndex);
                if (mOwner.Version > 0x00000201)
                {
                    mParentName  = parentName;
                    mMirrorPlane = new Vector4(requestedApiVersion, handler, mirrorPlane);
                }
                if (mOwner.Version > 0x00000203)
                {
                    mUnknown1 = unknown1;
                }
            }
コード例 #4
0
ファイル: Import.cs プロジェクト: yakoder/sims3tools
        //--


        public void Import_Mesh(StreamReader r, MLOD.Mesh mesh, GenericRCOLResource rcolResource, MLOD mlod, IResourceKey defaultRK, out meshExpImp.ModelBlocks.Vertex[] mverts, out List <meshExpImp.ModelBlocks.Vertex[]> lverts)
        {
            #region Import VRTF
            bool isDefaultVRTF  = false;
            VRTF defaultForMesh = VRTF.CreateDefaultForMesh(mesh);

            VRTF vrtf = new VRTF(rcolResource.RequestedApiVersion, null)
            {
                Version = 2, Layouts = null,
            };
            r.Import_VRTF(mpb, vrtf);

            IResourceKey vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.VertexFormatIndex);
            if (vrtfRK == null)
            {
                vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex);
                if (vrtfRK == null)
                {
                    vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.ScaleOffsetIndex);
                }
                if (vrtfRK == null)
                {
                    vrtfRK = new TGIBlock(0, null, 0, 0,
                                          System.Security.Cryptography.FNV64.GetHash(DateTime.UtcNow.ToString() + defaultRK.ToString()));
                }
                vrtfRK = new TGIBlock(0, null, vrtfRK)
                {
                    ResourceType = vrtf.ResourceType,
                };
            }

            if (vrtf.Equals(defaultForMesh))
            {
                isDefaultVRTF          = true;
                mesh.VertexFormatIndex = new GenericRCOLResource.ChunkReference(0, null, 0);//Clear the reference
            }
            else
            {
                rcolResource.ReplaceChunk(mesh, "VertexFormatIndex", vrtfRK, vrtf);
            }
            #endregion

            #region Import SKIN
            // we need to read the data in the file...
            SKIN skin = new SKIN(rcolResource.RequestedApiVersion, null)
            {
                Version = 1, Bones = null,
            };
            r.Import_SKIN(mpb, skin);

            // However, we do *NOT* want to update the RCOL with what we read - we are not replacing the object skeleton here
#if UNDEF
            if (skin.Bones != null)
            {
                IResourceKey skinRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex);
                if (skinRK == null)
                {
                    skinRK = new TGIBlock(0, null, vrtfRK)
                    {
                        ResourceType = skin.ResourceType,
                    }
                }
                ;

                rcolResource.ReplaceChunk(mesh, "SkinControllerIndex", skinRK, skin);
            }
#endif
            #endregion

            mverts = Import_VBUF_Main(r, mlod, mesh, vrtf, isDefaultVRTF);

            #region Import IBUF
            IBUF ibuf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF;
            if (ibuf == null)
            {
                ibuf = new IBUF(rcolResource.RequestedApiVersion, null)
                {
                    Version = 2, Flags = IBUF.FormatFlags.DifferencedIndices, DisplayListUsage = 0,
                }
            }
            ;
            Import_IBUF_Main(r, mlod, mesh, ibuf);

            IResourceKey ibufRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.IndexBufferIndex);
            if (ibufRK == null)
            {
                ibufRK = new TGIBlock(0, null, defaultRK)
                {
                    ResourceType = ibuf.ResourceType,
                }
            }
            ;

            rcolResource.ReplaceChunk(mesh, "IndexBufferIndex", ibufRK, ibuf);
            #endregion

            // This reads both VBUF Vertex[]s and the ibufs; but the ibufs just go straight in quite happily
            lverts = Import_MeshGeoStates(r, mlod, mesh, vrtf, isDefaultVRTF, ibuf);

            #region Update the JointReferences
            UIntList joints = CreateJointReferences(mesh, mverts, lverts ?? new List <meshExpImp.ModelBlocks.Vertex[]>(), skin);

            List <uint> added   = new List <uint>(joints);
            List <uint> removed = new List <uint>();
            foreach (var j in mesh.JointReferences)
            {
                if (joints.Contains(j))
                {
                    added.Remove(j);
                }
                else
                {
                    removed.Add(j);
                }
            }

            // Remove root
            removed.Remove(0xCD68F001);

            if (added.Count != 0)
            {
                mesh.JointReferences.AddRange(added);

                System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with newly assigned (via BlendIndex) vertex: {1}\n({2})",
                                                                           mesh.Name,
                                                                           added.Count,
                                                                           String.Join(", ", added.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())),
                                                             "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning);
            }

// with the 20120601 change to export, this warning on import has lost its severity... and been dropped.
#if UNDEF
            if (removed.Count != 0)
            {
//#if UNDEF
                // http://dino.drealm.info/den/denforum/index.php?topic=394.msg3876#msg3876
                removed.ForEach(j => mesh.JointReferences[mesh.JointReferences.IndexOf(j)] = 0);
//#endif
                // However, OM felt more comfortable if there was some indication something a little odd was going on.
                System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with no assigned (via BlendIndex) vertex: {1}\n({2})",
                                                                           mesh.Name,
                                                                           removed.Count,
                                                                           String.Join(", ", removed.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())),
                                                             "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning);
            }
#endif
            #endregion
        }

        meshExpImp.ModelBlocks.Vertex[] Import_VBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, bool isDefaultVRTF)
        {
            string tagLine = r.ReadTag();

            string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 2)
            {
                throw new InvalidDataException("Invalid tag line read for 'vbuf'.");
            }
            if (split[0] != "vbuf")
            {
                throw new InvalidDataException("Expected line tag 'vbuf' not found.");
            }
            int count;

            if (!int.TryParse(split[1], out count))
            {
                throw new InvalidDataException("'vbuf' line has invalid count.");
            }

            return(r.Import_VBUF(mpb, count, vrtf));
        }

        void Import_IBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, IBUF ibuf)
        {
            string tagLine = r.ReadTag();

            string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 2)
            {
                throw new InvalidDataException("Invalid tag line read for 'ibuf'.");
            }
            if (split[0] != "ibuf")
            {
                throw new InvalidDataException("Expected line tag 'ibuf' not found.");
            }
            int count;

            if (!int.TryParse(split[1], out count))
            {
                throw new InvalidDataException("'ibuf' line has invalid count.");
            }

            ibuf.SetIndices(mlod, mesh, r.Import_IBUF(mpb, IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), count));
        }

        List <meshExpImp.ModelBlocks.Vertex[]> Import_MeshGeoStates(StreamReader r, MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, bool isDefaultVRTF, IBUF ibuf)
        {
            MLOD.GeometryStateList oldGeos = new MLOD.GeometryStateList(null, mesh.GeometryStates);
            r.Import_GEOS(mpb, mesh);
            if (mesh.GeometryStates.Count <= 0)
            {
                return(null);
            }

            List <meshExpImp.ModelBlocks.Vertex[]> lverts = new List <meshExpImp.ModelBlocks.Vertex[]>();

            for (int g = 0; g < mesh.GeometryStates.Count; g++)
            {
                lverts.Add(Import_VBUF_Geos(r, mlod, mesh, g, vrtf, isDefaultVRTF));
                Import_IBUF_Geos(r, mlod, mesh, g, ibuf);
            }
            return(lverts);
        }

        UIntList CreateJointReferences(MLOD.Mesh mesh, meshExpImp.ModelBlocks.Vertex[] mverts, List <meshExpImp.ModelBlocks.Vertex[]> lverts, SKIN skin)
        {
            if (skin == null || skin.Bones == null)
            {
                return(new UIntList(null));
            }

            int maxReference = -1;

            lverts.Insert(0, mverts);
            foreach (var vertices in lverts)
            {
                if (vertices != null)
                {
                    foreach (var vert in vertices)
                    {
                        if (vert.BlendIndices != null)
                        {
                            foreach (var reference in vert.BlendIndices)
                            {
                                if ((sbyte)reference > maxReference)
                                {
                                    maxReference = reference;
                                }
                            }
                        }
                    }
                }
            }
            lverts.Remove(mverts);

            return(maxReference > -1 ? new UIntList(null, skin.Bones.GetRange(0, maxReference + 1).ConvertAll <uint>(x => x.NameHash)) : new UIntList(null));
        }

        meshExpImp.ModelBlocks.Vertex[] Import_VBUF_Geos(StreamReader r, MLOD mlod, MLOD.Mesh mesh, int geoStateIndex, VRTF vrtf, bool isDefaultVRTF)
        {
            //w.WriteLine(string.Format("vbuf {0} {1} {2}", geoStateIndex, mesh.GeometryStates[geoStateIndex].MinVertexIndex, mesh.GeometryStates[geoStateIndex].VertexCount));
            string tagLine = r.ReadTag();

            string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 4)
            {
                throw new InvalidDataException(string.Format("Invalid tag line read for geoState {0} 'vbuf'.", geoStateIndex));
            }
            if (split[0] != "vbuf")
            {
                throw new InvalidDataException("Expected line tag 'vbuf' not found.");
            }
            int lineIndex;

            if (!int.TryParse(split[1], out lineIndex))
            {
                throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has invalid geoStateIndex.", geoStateIndex));
            }
            if (lineIndex != geoStateIndex)
            {
                throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has incorrect geoStateIndex value {1}.", geoStateIndex, lineIndex));
            }
            int minVertexIndex;

            if (!int.TryParse(split[2], out minVertexIndex))
            {
                throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has invalid MinVertexIndex.", geoStateIndex));
            }
            int vertexCount;

            if (!int.TryParse(split[3], out vertexCount))
            {
                throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has invalid VertexCount.", geoStateIndex));
            }

            if (minVertexIndex + vertexCount <= mesh.MinVertexIndex + mesh.VertexCount)
            {
                mesh.GeometryStates[geoStateIndex].MinVertexIndex = minVertexIndex;
                mesh.GeometryStates[geoStateIndex].VertexCount    = vertexCount;
                return(null);
            }

            if (minVertexIndex != mesh.GeometryStates[geoStateIndex].MinVertexIndex)
            {
                throw new InvalidDataException(string.Format("geoState {0} 'vbuf' line has unexpected MinVertexIndex {1}; expected {2}.", geoStateIndex, minVertexIndex, mesh.GeometryStates[geoStateIndex].MinVertexIndex));
            }
            return(r.Import_VBUF(mpb, vertexCount, vrtf));
        }

        void Import_IBUF_Geos(StreamReader r, MLOD mlod, MLOD.Mesh mesh, int geoStateIndex, IBUF ibuf)
        {
            //w.WriteLine(string.Format("ibuf {0} {1} {2}", geoStateIndex, mesh.GeometryStates[geoStateIndex].StartIndex, mesh.GeometryStates[geoStateIndex].PrimitiveCount));
            string tagLine = r.ReadTag();

            string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 4)
            {
                throw new InvalidDataException("Invalid tag line read for 'ibuf'.");
            }
            if (split[0] != "ibuf")
            {
                throw new InvalidDataException("Expected line tag 'ibuf' not found.");
            }
            int lineIndex;

            if (!int.TryParse(split[1], out lineIndex))
            {
                throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has invalid geoStateIndex.", geoStateIndex));
            }
            if (lineIndex != geoStateIndex)
            {
                throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has incorrect geoStateIndex value {1}.", geoStateIndex, lineIndex));
            }
            int startIndex;

            if (!int.TryParse(split[2], out startIndex))
            {
                throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has invalid StartIndex.", geoStateIndex));
            }
            int primitiveCount;

            if (!int.TryParse(split[3], out primitiveCount))
            {
                throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has invalid PrimitiveCount.", geoStateIndex));
            }

            int sizePerPrimitive = IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType);

            if (startIndex + primitiveCount * sizePerPrimitive <= mesh.StartIndex + mesh.PrimitiveCount * sizePerPrimitive)
            {
                mesh.GeometryStates[geoStateIndex].StartIndex     = startIndex;
                mesh.GeometryStates[geoStateIndex].PrimitiveCount = primitiveCount;
                return;
            }

            if (startIndex != mesh.GeometryStates[geoStateIndex].StartIndex)
            {
                throw new InvalidDataException(string.Format("geoState {0} 'ibuf' line has unexpected StartIndex {1}; expected {2}.", geoStateIndex, startIndex, mesh.GeometryStates[geoStateIndex].StartIndex));
            }
            ibuf.SetIndices(mlod, mesh, geoStateIndex, r.Import_IBUF(mpb, IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), primitiveCount));
        }
コード例 #5
0
ファイル: Import.cs プロジェクト: yakoder/sims3tools
        //--


        public void Import_Mesh(StreamReader r, MLOD.Mesh mesh, GenericRCOLResource rcolResource, MLOD mlod, IResourceKey defaultRK, out meshExpImp.ModelBlocks.Vertex[] mverts)
        {
            #region Import VRTF
            bool isDefaultVRTF  = false;
            VRTF defaultForMesh = VRTF.CreateDefaultForMesh(mesh);

            VRTF vrtf = new VRTF(rcolResource.RequestedApiVersion, null)
            {
                Version = 2, Layouts = null,
            };
            r.Import_VRTF(mpb, vrtf);

            IResourceKey vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.VertexFormatIndex);
            if (vrtfRK == null)
            {
                vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex);
                if (vrtfRK == null)
                {
                    vrtfRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.ScaleOffsetIndex);
                }
                if (vrtfRK == null)
                {
                    vrtfRK = new TGIBlock(0, null, 0, 0,
                                          System.Security.Cryptography.FNV64.GetHash(DateTime.UtcNow.ToString() + defaultRK.ToString()));
                }
                vrtfRK = new TGIBlock(0, null, vrtfRK)
                {
                    ResourceType = vrtf.ResourceType,
                };
            }

            if (vrtf.Equals(defaultForMesh))
            {
                isDefaultVRTF          = true;
                mesh.VertexFormatIndex = new GenericRCOLResource.ChunkReference(0, null, 0);//Clear the reference
            }
            else
            {
                rcolResource.ReplaceChunk(mesh, "VertexFormatIndex", vrtfRK, vrtf);
            }
            #endregion

            #region Import SKIN
            // we need to read the data in the file...
            SKIN skin = new SKIN(rcolResource.RequestedApiVersion, null)
            {
                Version = 1, Bones = null,
            };
            r.Import_SKIN(mpb, skin);

            // However, we do *NOT* want to update the RCOL with what we read - we are not replacing the object skeleton here
#if UNDEF
            if (skin.Bones != null)
            {
                IResourceKey skinRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.SkinControllerIndex);
                if (skinRK == null)
                {
                    skinRK = new TGIBlock(0, null, vrtfRK)
                    {
                        ResourceType = skin.ResourceType,
                    }
                }
                ;

                rcolResource.ReplaceChunk(mesh, "SkinControllerIndex", skinRK, skin);
            }
#endif
            #endregion

            mverts = Import_VBUF_Main(r, mlod, mesh, vrtf, isDefaultVRTF);

            #region Import IBUF
            IBUF ibuf = GenericRCOLResource.ChunkReference.GetBlock(rcolResource, mesh.IndexBufferIndex) as IBUF;
            if (ibuf == null)
            {
                ibuf = new IBUF(rcolResource.RequestedApiVersion, null)
                {
                    Version = 2, Flags = IBUF.FormatFlags.DifferencedIndices, DisplayListUsage = 0,
                }
            }
            ;
            Import_IBUF_Main(r, mlod, mesh, ibuf);

            IResourceKey ibufRK = GenericRCOLResource.ChunkReference.GetKey(rcolResource, mesh.IndexBufferIndex);
            if (ibufRK == null)
            {
                ibufRK = new TGIBlock(0, null, defaultRK)
                {
                    ResourceType = ibuf.ResourceType,
                }
            }
            ;

            rcolResource.ReplaceChunk(mesh, "IndexBufferIndex", ibufRK, ibuf);
            #endregion

            #region Update the JointReferences
            UIntList joints = CreateJointReferences(mesh, mverts, skin);

            List <uint> added   = new List <uint>(joints);
            List <uint> removed = new List <uint>();
            foreach (var j in mesh.JointReferences)
            {
                if (joints.Contains(j))
                {
                    added.Remove(j);
                }
                else
                {
                    removed.Add(j);
                }
            }

            // Remove root
            removed.Remove(0xCD68F001);

            if (added.Count != 0)
            {
                mesh.JointReferences.AddRange(added);

                System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with newly assigned (via BlendIndex) vertex: {1}\n({2})",
                                                                           mesh.Name,
                                                                           added.Count,
                                                                           String.Join(", ", added.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())),
                                                             "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning);
            }

            // with the 20120601 change to export, this warning on import has lost its severity... and been dropped.
#if UNDEF
            if (removed.Count != 0)
            {
//#if UNDEF
                // http://dino.drealm.info/den/denforum/index.php?topic=394.msg3876#msg3876
                removed.ForEach(j => mesh.JointReferences[mesh.JointReferences.IndexOf(j)] = 0);
//#endif
                // However, OM felt more comfortable if there was some indication something a little odd was going on.
                System.Windows.Forms.CopyableMessageBox.Show(String.Format("Mesh: 0x{0:X8}\nJointReferences with no assigned (via BlendIndex) vertex: {1}\n({2})",
                                                                           mesh.Name,
                                                                           removed.Count,
                                                                           String.Join(", ", removed.ConvertAll <string>(a => "0x" + a.ToString("X8")).ToArray())),
                                                             "Warning", System.Windows.Forms.CopyableMessageBoxButtons.OK, System.Windows.Forms.CopyableMessageBoxIcon.Warning);
            }
#endif
            #endregion
        }

        ModelBlocks.Vertex[] Import_VBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, VRTF vrtf, bool isDefaultVRTF)
        {
            string tagLine = r.ReadTag();

            string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 2)
            {
                throw new InvalidDataException("Invalid tag line read for 'vbuf'.");
            }
            if (split[0] != "vbuf")
            {
                throw new InvalidDataException("Expected line tag 'vbuf' not found.");
            }
            int count;

            if (!int.TryParse(split[1], out count))
            {
                throw new InvalidDataException("'vbuf' line has invalid count.");
            }

            //Wes's MilkShape plug-in sends back the first line in all subsequent lines of a dropShadow.
            return(r.Import_VBUF(mpb, count, vrtf, (mesh.Flags & MeshFlags.ShadowCaster) == 0));
        }

        void Import_IBUF_Main(StreamReader r, MLOD mlod, MLOD.Mesh mesh, IBUF ibuf)
        {
            string tagLine = r.ReadTag();

            string[] split = tagLine.Split(new char[] { ' ', }, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length != 2)
            {
                throw new InvalidDataException("Invalid tag line read for 'ibuf'.");
            }
            if (split[0] != "ibuf")
            {
                throw new InvalidDataException("Expected line tag 'ibuf' not found.");
            }
            int count;

            if (!int.TryParse(split[1], out count))
            {
                throw new InvalidDataException("'ibuf' line has invalid count.");
            }

            ibuf.SetIndices(mlod, mesh, r.Import_IBUF(mpb, IBUF.IndexCountFromPrimitiveType(mesh.PrimitiveType), count));
        }

        UIntList CreateJointReferences(MLOD.Mesh mesh, ModelBlocks.Vertex[] mverts, SKIN skin)
        {
            if (skin == null || skin.Bones == null)
            {
                return(new UIntList(null));
            }

            int maxReference = -1;

            foreach (var vert in mverts)
            {
                if (vert.BlendIndices != null)
                {
                    foreach (var reference in vert.BlendIndices)
                    {
                        if ((sbyte)reference > maxReference)
                        {
                            maxReference = reference;
                        }
                    }
                }
            }

            return(maxReference > -1 ? new UIntList(null, skin.Bones.GetRange(0, maxReference + 1).ConvertAll <uint>(x => x.NameHash)) : new UIntList(null));
        }