Пример #1
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            this.NameJP = PMXParser.ReadString(br, importSettings.TextEncoding);
            this.NameEN = PMXParser.ReadString(br, importSettings.TextEncoding);

            byte flag = br.ReadByte(); //Ignored will be automatically generated on export.

            int refCount = br.ReadInt32();

            for (int i = 0; i < refCount; i++)
            {
                byte refType = br.ReadByte();
                switch (refType)
                {
                case PMXDisplaySlot.REF_IDENTIFY_BONE:
                    int boneIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
                    this.References.Add(this.Model.Bones[boneIndex]);
                    break;

                case PMXDisplaySlot.REF_IDENTIFY_MORPH:
                    int morphIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.MorphIndexLength);
                    this.References.Add(this.Model.Morphs[morphIndex]);
                    break;
                }
            }
        }
Пример #2
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameJP);
            PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameEN);

            bool isImportant = (this.Model.DisplaySlots.IndexOf(this) <= 1); //Root and EXP Displays

            if (isImportant)
            {
                bw.Write((byte)1);
            }
            else
            {
                bw.Write((byte)0);
            }

            bw.Write((Int32)this.References.Count);
            foreach (PMXBasePart rfr in this.References)
            {
                if (rfr is PMXBone)
                {
                    bw.Write((byte)PMXDisplaySlot.REF_IDENTIFY_BONE);
                    PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel((PMXBone)rfr, exportSettings, false));
                }
                else if (rfr is PMXMorph)
                {
                    bw.Write((byte)PMXDisplaySlot.REF_IDENTIFY_MORPH);
                    PMXParser.WriteIndex(bw, exportSettings.BitSettings.MorphIndexLength, PMXMorph.CheckIndexInModel((PMXMorph)rfr, exportSettings, false));
                }
                else
                {
                    throw new InvalidDataException("Invalid reference in display slots. Only bones and morphs are supported!");
                }
            }
        }
Пример #3
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int mtIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.MaterialIndexLength);

            if (mtIndex < 0)
            {
                this.Material = null;
            }
            else
            {
                this.Material = this.Model.Materials[mtIndex];
            }

            this.Type = (MaterialMorphOffsetType)(int)br.ReadByte();

            this.Diffuse  = PMXColorRGBA.LoadFromStreamStatic(br);
            this.Specular = PMXColorRGBA.LoadFromStreamStatic(br);
            this.Ambient  = PMXColorRGB.LoadFromStreamStatic(br);

            this.EdgeColor = PMXColorRGBA.LoadFromStreamStatic(br);
            this.EdgeSize  = br.ReadSingle();

            this.TextureFactor       = PMXColorRGBA.LoadFromStreamStatic(br);
            this.SphereTextureFactor = PMXColorRGBA.LoadFromStreamStatic(br);
            this.ToonTextureFactor   = PMXColorRGBA.LoadFromStreamStatic(br);
        }
Пример #4
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            PMXParser.WriteIndex(bw, exportSettings.BitSettings.VertexIndexLength, PMXVertex.CheckIndexInModel(this.Vertex, exportSettings));

            this.UVTranslation.WriteToStream(bw);
            this.UVTranslation2.WriteToStream(bw);
        }
Пример #5
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            {
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameJP);
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameEN);

                bw.Write((byte)(int)this.Type);

                PMXParser.WriteIndex(bw, exportSettings.BitSettings.RigidBodyIndexLength, PMXRigidBody.CheckIndexInModel(this.RigidBodyA, exportSettings));
                PMXParser.WriteIndex(bw, exportSettings.BitSettings.RigidBodyIndexLength, PMXRigidBody.CheckIndexInModel(this.RigidBodyB, exportSettings));
            }
            else
            {
                PMDParser.WriteString(bw, 20, exportSettings.TextEncoding, this.NameJP);

                PMXParser.WriteIndex(bw, 4, PMXRigidBody.CheckIndexInModel(this.RigidBodyA, exportSettings));
                PMXParser.WriteIndex(bw, 4, PMXRigidBody.CheckIndexInModel(this.RigidBodyB, exportSettings));
            }


            this.Position.WriteToStream(bw);
            this.Rotation.WriteToStream(bw);
            this.TranslationLimitMin.WriteToStream(bw);
            this.TranslationLimitMax.WriteToStream(bw);
            this.RotationLimitMin.WriteToStream(bw);
            this.RotationLimitMax.WriteToStream(bw);
            this.SpringConstantTranslation.WriteToStream(bw);
            this.SpringConstantRotation.WriteToStream(bw);
        }
Пример #6
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            {
                base.WriteToStream(bw, exportSettings);

                PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.Bone2, exportSettings));
                bw.Write(this.Bone1Weight);
            }
            else
            {
                int b1i = PMXBone.CheckIndexInModel(this.Bone1, exportSettings);
                int b2i = PMXBone.CheckIndexInModel(this.Bone2, exportSettings);

                List <KeyValuePair <int, float> > sortKeys = new List <KeyValuePair <int, float> >();
                if (b1i >= 0)
                {
                    sortKeys.Add(new KeyValuePair <int, float>(b1i, this.Bone1Weight));
                }
                if (b2i >= 0)
                {
                    sortKeys.Add(new KeyValuePair <int, float>(b2i, 1.0f - this.Bone1Weight));
                }

                this.ExportToPMDBase(sortKeys, bw);
            }
        }
Пример #7
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int vtxIndex;

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            { //PMX
                vtxIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.VertexIndexLength);
            }
            else
            { //PMD
                vtxIndex = br.ReadInt32();

                if (importSettings.BaseMorph != null)
                {
                    if (vtxIndex < importSettings.BaseMorph.Offsets.Count)
                    {
                        PMXMorphOffsetVertex mov = (PMXMorphOffsetVertex)importSettings.BaseMorph.Offsets[vtxIndex];
                        vtxIndex = this.Model.Vertices.IndexOf(mov.Vertex);
                    }
                }
            }

            this.Vertex      = this.Model.Vertices[vtxIndex];
            this.Translation = PMXVector3.LoadFromStreamStatic(br);
        }
Пример #8
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int linkCount;

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            { //PMX IK
                this.boneTargetIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
                this.Loop            = br.ReadInt32();
                this.RadianLimit     = br.ReadSingle();

                linkCount = br.ReadInt32();
            }
            else
            { //PMD IK
                this.boneTargetIndex = br.ReadUInt16();
                linkCount            = (int)br.ReadByte();

                this.Loop        = br.ReadUInt16();
                this.RadianLimit = br.ReadSingle();
            }

            for (int i = 0; i < linkCount; i++)
            {
                PMXIKLink link = new PMXIKLink(this.Model, this);
                link.LoadFromStream(br, importSettings);
                this.IKLinks.Add(link);
            }
        }
Пример #9
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            byte indexLength = ((exportSettings.Format == MMDExportSettings.ModelFormat.PMX) ? exportSettings.BitSettings.VertexIndexLength : (byte)2);

            PMXParser.WriteIndex(bw, indexLength, PMXVertex.CheckIndexInModel(this.Vertex1, exportSettings));
            PMXParser.WriteIndex(bw, indexLength, PMXVertex.CheckIndexInModel(this.Vertex2, exportSettings));
            PMXParser.WriteIndex(bw, indexLength, PMXVertex.CheckIndexInModel(this.Vertex3, exportSettings));
        }
Пример #10
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int boneIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);

            this.Bone        = this.Model.Bones[boneIndex];
            this.Translation = PMXVector3.LoadFromStreamStatic(br);
            this.Rotation    = PMXQuaternion.LoadFromStreamStatic(br);
        }
Пример #11
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int vtxIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.VertexIndexLength);

            this.Vertex         = this.Model.Vertices[vtxIndex];
            this.UVTranslation  = PMXVector2.LoadFromStreamStatic(br);
            this.UVTranslation2 = PMXVector2.LoadFromStreamStatic(br);
        }
Пример #12
0
 public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
 {
     this.bone1Index  = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
     this.bone2Index  = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
     this.bone3Index  = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
     this.bone4Index  = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
     this.Bone1Weight = br.ReadSingle();
     this.Bone2Weight = br.ReadSingle();
     this.Bone3Weight = br.ReadSingle();
     this.Bone4Weight = br.ReadSingle();
 }
Пример #13
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            { //PMX
                PMXParser.WriteIndex(bw, exportSettings.BitSettings.VertexIndexLength, PMXVertex.CheckIndexInModel(this.Vertex, exportSettings));
            }
            else
            { //PMD
                PMXParser.WriteIndex(bw, 4, exportSettings.BaseMorphVertices.IndexOf(this.Vertex));
            }

            this.Translation.WriteToStream(bw);
        }
Пример #14
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int boneIndex;

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            {
                this.NameJP = PMXParser.ReadString(br, importSettings.TextEncoding);
                this.NameEN = PMXParser.ReadString(br, importSettings.TextEncoding);

                boneIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
            }
            else
            {
                this.NameJP = PMDParser.ReadString(br, 20, importSettings.TextEncoding);
                this.NameEN = this.NameJP;

                boneIndex = br.ReadInt16();
            }

            if (boneIndex < 0)
            {
                this.Bone = null;
            }
            else
            {
                this.Bone = this.Model.Bones[boneIndex];
            }

            this.CollissionGroup = br.ReadByte();
            this.NoCollissionGroups.LoadFromStream(br, importSettings);

            this.Shape      = (BodyShape)(int)br.ReadByte();
            this._shapeSize = PMXVector3.LoadFromStreamStatic(br);

            this.Position = PMXVector3.LoadFromStreamStatic(br);
            this.Rotation = PMXVector3.LoadFromStreamStatic(br);

            this.Mass           = br.ReadSingle();
            this.LinearDamping  = br.ReadSingle();
            this.AngularDamping = br.ReadSingle();
            this.Repulsion      = br.ReadSingle();
            this.Friction       = br.ReadSingle();

            this.Type = (BodyType)(int)br.ReadByte();

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMD && this.Bone != null)
            { //PMD location fix
                this.Position += this.Bone.Position;
            }
        }
Пример #15
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            PMXParser.WriteIndex(bw, exportSettings.BitSettings.MaterialIndexLength, PMXMaterial.CheckIndexInModel(this.Material, exportSettings, true));

            bw.Write((byte)(int)this.Type);

            this.Diffuse.WriteToStream(bw);
            this.Specular.WriteToStream(bw);
            this.Ambient.WriteToStream(bw);

            this.EdgeColor.WriteToStream(bw);
            bw.Write(this.EdgeSize);

            this.TextureFactor.WriteToStream(bw);
            this.SphereTextureFactor.WriteToStream(bw);
            this.ToonTextureFactor.WriteToStream(bw);
        }
Пример #16
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            { //PMX format
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameJP);
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameEN);

                bw.Write((byte)(int)this.Panel);

                if (this.Offsets.Count == 0)
                {
                    bw.Write((byte)PMXMorph.MORPH_IDENTIFY_VERTEX);
                    bw.Write((Int32)0);
                }
                else
                {
                    byte morphTypeId = this.Offsets[0].MorphTargetType;
                    bw.Write((byte)morphTypeId);
                    bw.Write((Int32)this.Offsets.Count);

                    foreach (PMXMorphOffsetBase offset in this.Offsets)
                    {
                        if (offset.MorphTargetType != morphTypeId)
                        {
                            throw new InvalidDataException("Morph offset types mustn't be mixed types");
                        }
                        offset.WriteToStream(bw, exportSettings);
                    }
                }
            } //PMD format
            else
            {
                PMDParser.WriteString(bw, 20, exportSettings.TextEncoding, this.NameJP);
                bw.Write((Int32)this.Offsets.Count);
                bw.Write((byte)(int)this.Panel);
                foreach (PMXMorphOffsetBase offset in this.Offsets)
                {
                    if (!(offset is PMXMorphOffsetVertex))
                    {
                        throw new InvalidDataException("PMD only supports vertex morphs.");
                    }
                    offset.WriteToStream(bw, exportSettings);
                }
            }
        }
Пример #17
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            { //PMX format
                this.boneIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);

                this.HasLimits = (br.ReadByte() == 1);
                if (this.HasLimits)
                {
                    this.Minimum = PMXVector3.LoadFromStreamStatic(br);
                    this.Maximum = PMXVector3.LoadFromStreamStatic(br);
                }
            }
            else
            {
                this.boneIndex = br.ReadUInt16();
            }
        }
Пример #18
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            {
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameJP);
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameEN);

                PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.Bone, exportSettings, true));
            }
            else
            {
                PMDParser.WriteString(bw, 20, exportSettings.TextEncoding, this.NameEN);

                PMXParser.WriteIndex(bw, 2, PMXBone.CheckIndexInModel(this.Bone, exportSettings, true));
            }

            bw.Write((byte)this.CollissionGroup);
            this.NoCollissionGroups.WriteToStream(bw, exportSettings);

            bw.Write((byte)(int)this.Shape);
            this._shapeSize.WriteToStream(bw);

            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMD && this.Bone != null)
            { //PMD location fix
                PMXVector3 pos = new PMXVector3(this.Position.X, this.Position.Y, this.Position.Z);
                pos -= this.Bone.Position;
                pos.WriteToStream(bw);
            }
            else
            {
                this.Position.WriteToStream(bw);
            }

            this.Rotation.WriteToStream(bw);

            bw.Write(this.Mass);
            bw.Write(this.LinearDamping);
            bw.Write(this.AngularDamping);
            bw.Write(this.Repulsion);
            bw.Write(this.Friction);

            bw.Write((byte)(int)this.Type);
        }
Пример #19
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int index1, index2, index3;

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            { //PMX
                index1 = PMXParser.ReadIndex(br, importSettings.BitSettings.VertexIndexLength);
                index2 = PMXParser.ReadIndex(br, importSettings.BitSettings.VertexIndexLength);
                index3 = PMXParser.ReadIndex(br, importSettings.BitSettings.VertexIndexLength);
            }
            else
            { //PMD
                index1 = (int)br.ReadUInt16();
                index2 = (int)br.ReadUInt16();
                index3 = (int)br.ReadUInt16();
            }

            this.Vertex1 = this.Model.Vertices[index1];
            this.Vertex2 = this.Model.Vertices[index2];
            this.Vertex3 = this.Model.Vertices[index3];
        }
Пример #20
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            { //PMX IK
                PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.Bone, exportSettings, true));

                if (this.HasLimits)
                {
                    bw.Write((byte)1);
                    this.Minimum.WriteToStream(bw);
                    this.Maximum.WriteToStream(bw);
                }
                else
                {
                    bw.Write((byte)0);
                }
            }
            else
            { //PMD IK
                PMXParser.WriteIndex(bw, 2, PMXBone.CheckIndexInModel(this.Bone, exportSettings, true));
            }
        }
Пример #21
0
        public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
        {
            int rigidBodyIndexA, rigidBodyIndexB;

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            {
                this.NameJP = PMXParser.ReadString(br, importSettings.TextEncoding);
                this.NameEN = PMXParser.ReadString(br, importSettings.TextEncoding);

                this.Type = (JointType)(int)br.ReadByte();

                rigidBodyIndexA = PMXParser.ReadIndex(br, importSettings.BitSettings.RigidBodyIndexLength);
                rigidBodyIndexB = PMXParser.ReadIndex(br, importSettings.BitSettings.RigidBodyIndexLength);
            }
            else
            {
                this.NameJP = PMDParser.ReadString(br, 20, importSettings.TextEncoding);
                this.NameEN = this.NameJP;

                this.Type = JointType.SpringSixDOF;

                rigidBodyIndexA = br.ReadInt32();
                rigidBodyIndexB = br.ReadInt32();
            }


            this.RigidBodyA = this.Model.RigidBodies[rigidBodyIndexA];
            this.RigidBodyB = this.Model.RigidBodies[rigidBodyIndexB];

            this.Position                  = PMXVector3.LoadFromStreamStatic(br);
            this.Rotation                  = PMXVector3.LoadFromStreamStatic(br);
            this.TranslationLimitMin       = PMXVector3.LoadFromStreamStatic(br);
            this.TranslationLimitMax       = PMXVector3.LoadFromStreamStatic(br);
            this.RotationLimitMin          = PMXVector3.LoadFromStreamStatic(br);
            this.RotationLimitMax          = PMXVector3.LoadFromStreamStatic(br);
            this.SpringConstantTranslation = PMXVector3.LoadFromStreamStatic(br);
            this.SpringConstantRotation    = PMXVector3.LoadFromStreamStatic(br);
        }
Пример #22
0
        public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            { //PMX IK
                PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.Target, exportSettings, true));
                bw.Write((Int32)this.Loop);
                bw.Write(this.RadianLimit);
                bw.Write((Int32)this.IKLinks.Count);
            }
            else
            { //PMD
                PMXParser.WriteIndex(bw, 2, PMXBone.CheckIndexInModel(this.Target, exportSettings, true));
                bw.Write((byte)this.IKLinks.Count);

                bw.Write((UInt16)this.Loop);
                bw.Write(this.RadianLimit);
            }

            foreach (PMXIKLink link in this.IKLinks)
            {
                link.WriteToStream(bw, exportSettings);
            }
        }
Пример #23
0
 public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
 {
     PMXParser.WriteIndex(bw, exportSettings.BitSettings.MorphIndexLength, PMXMorph.CheckIndexInModel(this.MorphTarget, exportSettings, false));
     bw.Write(this.Strength);
 }
Пример #24
0
 public override void LoadFromStream(BinaryReader br, MMDImportSettings importSettings)
 {
     this.morphTargetIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.MorphIndexLength);
     this.Strength         = br.ReadSingle();
 }
Пример #25
0
        /// <summary>
        /// Saves to a stream as PMD.
        /// </summary>
        /// <param name="fs"></param>
        public void SaveToStreamPMD(Stream stream)
        {
            List <string> requiredToons = new List <string>(); //List of textures to export

            string[] defaultToons = new string[]
            {
                "toon01.bmp", "toon02.bmp", "toon03.bmp", "toon04.bmp", "toon05.bmp",
                "toon06.bmp", "toon07.bmp", "toon08.bmp", "toon09.bmp", "toon10.bmp"
            };

            int triangleCount = 0;

            foreach (PMXMaterial mat in this.Materials)
            {
                //this.AddToListIfRequired(requiredToons, mat.DiffuseTexture);

                if (mat.StandardToon)
                {
                    this.AddToListIfRequired(requiredToons, defaultToons[mat.StandardToonIndex]);
                }
                else
                {
                    this.AddToListIfRequired(requiredToons, mat.NonStandardToonTexture);
                }

                triangleCount += mat.Triangles.Count;
            }

            string[] toonFiles = new string[10];
            for (int i = 0; i < 10; i++)
            {
                if (i < requiredToons.Count)
                {
                    toonFiles[i] = requiredToons[i];
                }
                else
                {
                    toonFiles[i] = defaultToons[i];
                }
            }

            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);

            byte[] magic = Encoding.ASCII.GetBytes("Pmd");
            ms.Write(magic, 0, 3);

            Random rnd          = new Random();
            int    randomNumber = rnd.Next();

            MMDExportSettings settings = new MMDExportSettings(MMDExportSettings.ModelFormat.PMD);

            settings.Model        = this;
            settings.ExportHash   = randomNumber;
            settings.TextEncoding = Encoding.GetEncoding(932);

            float version = 1.0f;

            bw.Write(version);

            PMDParser.WriteString(bw, 20, settings.TextEncoding, this.NameJP);
            PMDParser.WriteString(bw, 256, settings.TextEncoding, this.DescriptionJP);

            //Vertices
            bw.Write((int)this.Vertices.Count);

            int vtxIndex = 0;

            foreach (PMXVertex v in this.Vertices)
            {
                v.AddIndexForExport(settings, vtxIndex);
                v.WriteToStream(bw, settings);
                vtxIndex++;
            }

            //Triangles
            bw.Write((Int32)(triangleCount * 3));

            foreach (PMXMaterial mat in this.Materials)
            {
                foreach (PMXTriangle t in mat.Triangles)
                {
                    t.WriteToStream(bw, settings);
                }
            }

            //Materials
            bw.Write((Int32)this.Materials.Count);
            foreach (PMXMaterial mat in this.Materials)
            {
                mat.WriteToStream(bw, settings, toonFiles, defaultToons);
            }

            //Bones
            bw.Write((Int16)this.Bones.Count);
            List <PMXBone> ikBonesList = new List <PMXBone>();

            foreach (PMXBone bn in this.Bones)
            {
                if (bn.IK != null)
                {
                    ikBonesList.Add(bn);
                }
            }
            PMXBone[] ikBones = ikBonesList.ToArray();

            foreach (PMXBone bn in this.Bones)
            {
                bn.WriteToStream(bw, settings, ikBones);
            }

            //PMD IKs
            bw.Write((Int16)ikBones.Length);
            foreach (PMXBone bn in ikBones)
            {
                PMXParser.WriteIndex(bw, 2, PMXBone.CheckIndexInModel(bn, settings, true));
                bn.IK.WriteToStream(bw, settings);
            }

            //PMD Morphs
            List <PMXMorph>  exportableMorphs = new List <PMXMorph>();
            List <PMXVertex> baseVertices     = new List <PMXVertex>();

            foreach (PMXMorph mrph in this.Morphs)
            {
                bool exportable = true;
                foreach (PMXMorphOffsetBase mofb in mrph.Offsets)
                {
                    if (!(mofb is PMXMorphOffsetVertex))
                    {
                        exportable = false;
                    }
                }

                if (exportable)
                {
                    exportableMorphs.Add(mrph);
                    foreach (PMXMorphOffsetBase mofb in mrph.Offsets)
                    {
                        PMXMorphOffsetVertex mofv = (PMXMorphOffsetVertex)mofb;
                        if (!baseVertices.Contains(mofv.Vertex))
                        {
                            baseVertices.Add(mofv.Vertex);
                        }
                    }
                }
            }
            settings.BaseMorphVertices = baseVertices;

            bw.Write((Int16)(exportableMorphs.Count + 1));
            PMDParser.WriteString(bw, 20, settings.TextEncoding, "base");
            bw.Write((Int32)baseVertices.Count);
            bw.Write((byte)0);
            foreach (PMXVertex vtx in baseVertices)
            {
                PMXParser.WriteIndex(bw, 4, PMXVertex.CheckIndexInModel(vtx, settings));
                vtx.Position.WriteToStream(bw);
            }

            foreach (PMXMorph mrph in exportableMorphs)
            {
                mrph.WriteToStream(bw, settings);
            }

            //Display groups - kinda insanely set up for PMD

            //PMD doesn't have a root slot

            //Expression display slots
            List <PMXMorph> morphs = new List <PMXMorph>(); //List of facial expressions

            foreach (PMXDisplaySlot ds in this.DisplaySlots)
            {
                foreach (PMXBasePart reference in ds.References)
                {
                    if (reference is PMXMorph)
                    {
                        morphs.Add((PMXMorph)reference);
                    }
                }
            }
            bw.Write((byte)morphs.Count);
            foreach (PMXMorph mrph in morphs)
            {
                int morphId = this.Morphs.IndexOf(mrph) + 1;
                bw.Write((UInt16)morphId);
            }

            //Bone display slots
            bw.Write((byte)(this.DisplaySlots.Count - 2));
            for (int dsidx = 2; dsidx < this.DisplaySlots.Count; dsidx++)
            {
                PMDParser.WriteString(bw, 50, settings.TextEncoding, this.DisplaySlots[dsidx].NameJP);
            }

            //We've got the names - now let's put the bones in
            uint totalBoneRefCount = 0;

            for (int dsidx = 2; dsidx < this.DisplaySlots.Count; dsidx++)
            {
                PMXDisplaySlot ds = this.DisplaySlots[dsidx];
                foreach (PMXBasePart reference in ds.References)
                {
                    if (reference is PMXBone)
                    {
                        totalBoneRefCount++;
                    }
                }
            }
            bw.Write((uint)totalBoneRefCount);
            for (int dsidx = 2; dsidx < this.DisplaySlots.Count; dsidx++)
            {
                PMXDisplaySlot ds = this.DisplaySlots[dsidx];
                foreach (PMXBasePart reference in ds.References)
                {
                    if (reference is PMXBone)
                    {
                        PMXBone bref = (PMXBone)reference;
                        bw.Write((UInt16)this.Bones.IndexOf(bref));
                        bw.Write((byte)(dsidx - 1));
                    }
                }
            }

            //Always write english names
            bw.Write((byte)1);
            PMDParser.WriteString(bw, 20, settings.TextEncoding, this.NameEN);
            PMDParser.WriteString(bw, 256, settings.TextEncoding, this.DescriptionEN);
            foreach (PMXBone bn in this.Bones)
            {
                PMDParser.WriteString(bw, 20, settings.TextEncoding, bn.NameEN);
            }

            foreach (PMXMorph mrph in exportableMorphs)
            {
                PMDParser.WriteString(bw, 20, settings.TextEncoding, mrph.NameEN);
            }
            for (int i = 2; i < this.DisplaySlots.Count; i++)
            {
                PMDParser.WriteString(bw, 50, settings.TextEncoding, this.DisplaySlots[i].NameEN);
            }

            //Toon files
            foreach (string toon in toonFiles)
            {
                PMDParser.WriteString(bw, 100, settings.TextEncoding, toon);
            }

            //Rigid bodies
            bw.Write((uint)this.RigidBodies.Count);

            foreach (PMXRigidBody rb in this.RigidBodies)
            {
                rb.WriteToStream(bw, settings);
            }

            //Joints
            bw.Write((uint)this.Joints.Count);

            foreach (PMXJoint jt in this.Joints)
            {
                jt.WriteToStream(bw, settings);
            }

            //Vertex restore
            foreach (PMXVertex v in this.Vertices)
            {
                v.RemoveIndexForExport(settings);
            }

            long length = ms.Position;

            ms.Seek(0, SeekOrigin.Begin);

            ms.CopyTo(stream);

            ms.Close();
            ms = null;
        }
Пример #26
0
        public static PMXModel LoadFromPMXFile(string pmxFile, PMXModelDescriptor modelDescriptor)
        {
            FileStream fs = new FileStream(pmxFile, FileMode.Open, FileAccess.Read, FileShare.Read);

            byte[] buffer = new byte[3];
            fs.Read(buffer, 0, 3);
            string head = Encoding.ASCII.GetString(buffer);

            fs.Seek(1, SeekOrigin.Current);

            if (head != "PMX")
            {
                throw new Exception("Not a PMX file!");
            }

            BinaryReader br = new BinaryReader(fs);

            float PMXVersion = br.ReadSingle();

            if (PMXVersion != 2.0f && PMXVersion != 2.1f)
            {
                throw new Exception("Unsupported PMX Version!");
            }

            byte flags = br.ReadByte();

            if (flags != 8)
            {
                throw new Exception("Invalid PMX bytes version!");
            }

            MMDImportSettings  settings = new MMDImportSettings(MMDImportSettings.ModelFormat.PMX);
            List <PMXBasePart> allParts = new List <PMXBasePart>();

            byte text_encoding = br.ReadByte();

            settings.TextEncoding =
                (text_encoding == 1 ? Encoding.UTF8 :
                 (text_encoding == 0 ? Encoding.Unicode : Encoding.GetEncoding(932)));

            settings.ExtendedUV      = br.ReadByte();
            settings.ClassDescriptor = modelDescriptor;

            PMXModel md = new PMXModel();

            settings.BitSettings.VertexIndexLength    = br.ReadByte();
            settings.BitSettings.TextureIndexLength   = br.ReadByte();
            settings.BitSettings.MaterialIndexLength  = br.ReadByte();
            settings.BitSettings.BoneIndexLength      = br.ReadByte();
            settings.BitSettings.MorphIndexLength     = br.ReadByte();
            settings.BitSettings.RigidBodyIndexLength = br.ReadByte();

            md.NameJP        = PMXParser.ReadString(br, settings.TextEncoding);
            md.NameEN        = PMXParser.ReadString(br, settings.TextEncoding);
            md.DescriptionJP = PMXParser.ReadString(br, settings.TextEncoding);
            md.DescriptionEN = PMXParser.ReadString(br, settings.TextEncoding);


            //Vertices
            uint vertexCount = br.ReadUInt32();

            for (int i = 0; i < vertexCount; i++)
            {
                PMXVertex v = (PMXVertex)Activator.CreateInstance(modelDescriptor.VertexType.StoredType, new object[] { md });
                v.LoadFromStream(br, settings);
                md.Vertices.Add(v);
                allParts.Add(v);
            }

            //Triangles
            uint vertexRefCount = br.ReadUInt32();

            if (vertexRefCount % 3 != 0)
            {
                throw new Exception("Invalid triangle count!");
            }

            uint triangleCount = vertexRefCount / 3;
            List <PMXTriangle> importTriangles = new List <PMXTriangle>();

            for (int i = 0; i < triangleCount; i++)
            {
                PMXTriangle t = (PMXTriangle)Activator.CreateInstance(modelDescriptor.TriangleType.StoredType, new object[] { md });
                t.LoadFromStream(br, settings);
                importTriangles.Add(t);
                allParts.Add(t);
            }

            //Textures
            uint textureCount = br.ReadUInt32();

            List <string> importTextures = new List <string>();

            for (int i = 0; i < textureCount; i++)
            {
                string tex = PMXParser.ReadString(br, settings.TextEncoding);
                importTextures.Add(tex);
            }
            string[] textures = importTextures.ToArray();

            //Materials
            uint materialCount = br.ReadUInt32();

            for (int i = 0; i < materialCount; i++)
            {
                PMXMaterial mt = (PMXMaterial)Activator.CreateInstance(modelDescriptor.MaterialType.StoredType, new object[] { md });
                mt.LoadFromStream(br, settings, textures, importTriangles);
                md.Materials.Add(mt);
                allParts.Add(mt);
            }

            if (importTriangles.Count > 0)
            {
                throw new InvalidDataException("Model materials don't cover all triangles!");
            }

            //Bones
            uint boneCount = br.ReadUInt32();

            for (int i = 0; i < boneCount; i++)
            {
                PMXBone bn = (PMXBone)Activator.CreateInstance(modelDescriptor.BoneType.StoredType, new object[] { md });
                bn.LoadFromStream(br, settings);
                md.Bones.Add(bn);
                allParts.Add(bn);
            }

            //Morphs
            uint morphCount = br.ReadUInt32();

            for (int i = 0; i < morphCount; i++)
            {
                PMXMorph mrph = (PMXMorph)Activator.CreateInstance(modelDescriptor.MorphType.StoredType, new object[] { md });
                mrph.LoadFromStream(br, settings);
                md.Morphs.Add(mrph);
                allParts.Add(mrph);
            }

            //Display frames
            md.DisplaySlots.Clear();
            uint displayCount = br.ReadUInt32();

            for (int i = 0; i < displayCount; i++)
            {
                PMXDisplaySlot ds = new PMXDisplaySlot(md);
                ds.LoadFromStream(br, settings);
                md.DisplaySlots.Add(ds);
                allParts.Add(ds);
            }

            //Rigid bodies
            uint rigidBodyCount = br.ReadUInt32();

            for (int i = 0; i < rigidBodyCount; i++)
            {
                PMXRigidBody rb = (PMXRigidBody)Activator.CreateInstance(modelDescriptor.RigidBodyType.StoredType, new object[] { md });
                rb.LoadFromStream(br, settings);
                md.RigidBodies.Add(rb);
                allParts.Add(rb);
            }

            //Joints
            uint jointsCount = br.ReadUInt32();

            for (int i = 0; i < jointsCount; i++)
            {
                PMXJoint jt = (PMXJoint)Activator.CreateInstance(modelDescriptor.JointType.StoredType, new object[] { md });
                jt.LoadFromStream(br, settings);
                md.Joints.Add(jt);
                allParts.Add(jt);
            }

            br.BaseStream.Close();

            br = null;
            fs = null;

            foreach (PMXBasePart part in allParts)
            {
                part.FinaliseAfterImport();
            }

            return(md);
        }
Пример #27
0
 public override void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings)
 {
     PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.Bone, exportSettings, false));
     this.Translation.WriteToStream(bw);
     this.Rotation.WriteToStream(bw);
 }
Пример #28
0
        public void WriteToStream(BinaryWriter bw, MMDExportSettings exportSettings, PMXBone[] ikBones)
        {
            if (exportSettings.Format == MMDExportSettings.ModelFormat.PMX)
            { //PMX export
                short flags = 0x0000;

                flags |= (short)(this.HasChildBone ? PMXBone.BONE_TAILPOS_IS_BONE : 0x0000);

                flags |= (short)(this.Rotatable ? PMXBone.BONE_CAN_ROTATE : 0x0000);
                flags |= (short)(this.Translatable ? PMXBone.BONE_CAN_TRANSLATE : 0x0000);
                flags |= (short)(this.Visible ? PMXBone.BONE_IS_VISIBLE : 0x0000);
                flags |= (short)(this.Operating ? PMXBone.BONE_CAN_MANIPULATE : 0x0000);

                flags |= (short)((this.ExternalModificationType == BoneExternalModificationType.Both || this.ExternalModificationType == BoneExternalModificationType.Rotation) ? PMXBone.BONE_IS_EXTERNAL_ROTATION : 0x0000);
                flags |= (short)((this.ExternalModificationType == BoneExternalModificationType.Both || this.ExternalModificationType == BoneExternalModificationType.Translation) ? PMXBone.BONE_IS_EXTERNAL_TRANSLATION : 0x0000);

                flags |= (short)(this.FixedAxis ? PMXBone.BONE_HAS_FIXED_AXIS : 0x0000);
                flags |= (short)(this.LocalCoordinates ? PMXBone.BONE_HAS_LOCAL_COORDINATE : 0x0000);
                flags |= (short)(this.HasExternalParent ? PMXBone.BONE_IS_EXTERNAL_PARENT_DEFORM : 0x0000);

                flags |= (short)(this.TransformPhysicsFirst ? PMXBone.BONE_IS_AFTER_PHYSICS_DEFORM : 0x0000);

                flags |= (short)((this.IK != null) ? PMXBone.BONE_IS_IK : 0x0000);

                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameJP);
                PMXParser.WriteString(bw, exportSettings.TextEncoding, this.NameEN);

                this.Position.WriteToStream(bw);

                PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.Parent, exportSettings, true));

                bw.Write((Int32)this.Layer);
                bw.Write((Int16)flags);

                if (this.HasChildBone)
                {
                    PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.ChildBone, exportSettings, true));
                }
                else
                {
                    this.ChildVector.WriteToStream(bw);
                }

                if (this.ExternalModificationType != BoneExternalModificationType.None)
                {
                    PMXParser.WriteIndex(bw, exportSettings.BitSettings.BoneIndexLength, PMXBone.CheckIndexInModel(this.ExternalBone, exportSettings, true));
                    bw.Write(this.ExternalBoneEffect);
                }

                if (this.FixedAxis)
                {
                    this.AxisLimit.WriteToStream(bw);
                }

                if (this.LocalCoordinates)
                {
                    this.LocalCoordinatesX.WriteToStream(bw);
                    this.LocalCoordinatesZ.WriteToStream(bw);
                }

                if (this.HasExternalParent)
                {
                    bw.Write((Int32)this.ExternalParentKey);
                }

                if (this.IK != null)
                {
                    this.IK.WriteToStream(bw, exportSettings);
                }
            }
            else
            { //PMD format
                PMDParser.WriteString(bw, 20, exportSettings.TextEncoding, this.NameJP);
                bw.Write((Int16)PMXBone.CheckIndexInModel(this.Parent, exportSettings, true));

                if (this.HasChildBone)
                {
                    bw.Write((Int16)PMXBone.CheckIndexInModel(this.ChildBone, exportSettings, true));
                }
                else
                {
                    bw.Write((Int16)(-1));
                }

                byte  type    = PMD_BONE_TYPE_ROTATE;
                short ikIndex = 0;

                if (this.Translatable)
                {
                    type = PMD_BONE_TYPE_ROTATE_MOVE;
                }

                if (this.IK != null)
                {
                    type = PMD_BONE_TYPE_IK;
                }

                if (this.IK != null)
                {
                    bool isIkTarget = false;
                    foreach (PMXBone ikBone in ikBones)
                    {
                        foreach (PMXIKLink link in ikBone.IK.IKLinks)
                        {
                            if (link.Bone == this)
                            {
                                ikIndex    = (Int16)PMXBone.CheckIndexInModel(ikBone, exportSettings, true);
                                isIkTarget = true;
                                break;
                            }
                        }
                        if (isIkTarget)
                        {
                            break;
                        }
                    }

                    if (isIkTarget)
                    {
                        type = (this.Visible ? PMD_BONE_TYPE_IK_CHILD:PMD_BONE_TYPE_IK_TARGET);
                    }
                    else if (!this.Visible)
                    {
                        type = PMD_BONE_TYPE_INVISIBLE;
                    }
                    else if (this.FixedAxis)
                    {
                        type = (this.Visible ? PMD_BONE_TYPE_TWIST : PMD_BONE_TYPE_TWIST_INVISIBLE);
                    }
                    else if (this.ExternalModificationType != BoneExternalModificationType.Both)
                    {
                        type    = PMD_BONE_TYPE_EXTERNAL_ROTATOR;
                        ikIndex = (Int16)PMXBone.CheckIndexInModel(this.ExternalBone, exportSettings, true);
                    }
                }

                bw.Write(type);
                bw.Write(ikIndex);

                this.Position.WriteToStream(bw);
            }
        }
Пример #29
0
        public void LoadFromStream(BinaryReader br, MMDImportSettings importSettings, out int pmdIKIndex)
        {
            pmdIKIndex = -1;

            if (importSettings.Format == MMDImportSettings.ModelFormat.PMX)
            { //PMX
                this.NameJP = PMXParser.ReadString(br, importSettings.TextEncoding);
                this.NameEN = PMXParser.ReadString(br, importSettings.TextEncoding);

                this.Position = PMXVector3.LoadFromStreamStatic(br);

                this.parentIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);

                this.Layer = br.ReadInt32();

                short flags = br.ReadInt16();

                this.HasChildBone = ((flags & PMXBone.BONE_TAILPOS_IS_BONE) != 0);
                if (this.HasChildBone)
                {
                    this.childBoneIndex = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
                }
                else
                {
                    this.ChildVector = PMXVector3.LoadFromStreamStatic(br);
                }

                this.Rotatable    = ((flags & PMXBone.BONE_CAN_ROTATE) != 0);
                this.Translatable = ((flags & PMXBone.BONE_CAN_TRANSLATE) != 0);
                this.Visible      = ((flags & PMXBone.BONE_IS_VISIBLE) != 0);
                this.Operating    = ((flags & PMXBone.BONE_CAN_MANIPULATE) != 0);

                bool extRotation    = ((flags & PMXBone.BONE_IS_EXTERNAL_ROTATION) != 0);
                bool extTranslation = ((flags & PMXBone.BONE_IS_EXTERNAL_TRANSLATION) != 0);

                int rotFlag = 0;
                if (extRotation)
                {
                    rotFlag |= 1;
                }
                if (extTranslation)
                {
                    rotFlag |= 2;
                }
                this.ExternalModificationType = (BoneExternalModificationType)rotFlag;
                if (this.ExternalModificationType != BoneExternalModificationType.None)
                {
                    this.externalBoneIndex  = PMXParser.ReadIndex(br, importSettings.BitSettings.BoneIndexLength);
                    this.ExternalBoneEffect = br.ReadSingle();
                }

                this.FixedAxis = ((flags & PMXBone.BONE_HAS_FIXED_AXIS) != 0);
                if (this.FixedAxis)
                {
                    this.AxisLimit = PMXVector3.LoadFromStreamStatic(br);
                }

                this.LocalCoordinates = ((flags & PMXBone.BONE_HAS_LOCAL_COORDINATE) != 0);
                if (this.LocalCoordinates)
                {
                    this.LocalCoordinatesX = PMXVector3.LoadFromStreamStatic(br);
                    this.LocalCoordinatesZ = PMXVector3.LoadFromStreamStatic(br);
                }

                this.HasExternalParent = ((flags & PMXBone.BONE_IS_EXTERNAL_PARENT_DEFORM) != 0);
                if (this.HasExternalParent)
                {
                    this.ExternalParentKey = br.ReadInt32();
                }

                this.TransformPhysicsFirst = ((flags & PMXBone.BONE_IS_AFTER_PHYSICS_DEFORM) != 0);

                bool isIKBone = ((flags & PMXBone.BONE_IS_IK) != 0);
                if (isIKBone)
                {
                    PMXIK ikData = new PMXIK(this.Model, this);
                    ikData.LoadFromStream(br, importSettings);
                    this.IK = ikData;
                }
                else
                {
                    this.IK = null;
                }
            }

            else
            { //PMD
                this.NameJP      = PMDParser.ReadString(br, 20, importSettings.TextEncoding);
                this.parentIndex = br.ReadInt16();

                this.HasChildBone   = true;
                this.childBoneIndex = br.ReadUInt16();

                byte type = br.ReadByte();

                ushort ikIndex = br.ReadUInt16();

                this.Position = PMXVector3.LoadFromStreamStatic(br);

                switch (type)
                {
                case PMD_BONE_TYPE_ROTATE:
                    //Default
                    break;

                case PMD_BONE_TYPE_ROTATE_MOVE:
                    this.Translatable = true;
                    break;

                case PMD_BONE_TYPE_IK:
                    //IK parameters will be initialised later
                    this.Translatable = true;
                    break;

                case PMD_BONE_TYPE_IK_CHILD:
                    //PMX doesn't even bother about these
                    break;

                case PMD_BONE_TYPE_EXTERNAL_ROTATOR:
                    this.ExternalModificationType = BoneExternalModificationType.Rotation;
                    this.externalBoneIndex        = (int)ikIndex;
                    break;

                case PMD_BONE_TYPE_IK_TARGET:
                    //PMX doesn't bother either
                    this.Visible = false;
                    break;

                case PMD_BONE_TYPE_INVISIBLE:
                    this.Visible = false;
                    break;

                case PMD_BONE_TYPE_TWIST:
                    //PMX handles these differently
                    this._isPMDTwist = true;
                    break;

                case PMD_BONE_TYPE_TWIST_INVISIBLE:
                    //PMX handles these differently
                    this._isPMDTwist = true;
                    this.Visible     = false;
                    break;
                }
            }
        }
Пример #30
0
        /// <summary>
        /// Saves a model to a stream.
        /// </summary>
        /// <param name="stream"></param>
        public void SaveToStream(Stream stream)
        {
            List <string> requiredTextureList = new List <string>(); //List of textures to export
            int           triangleCount       = 0;

            foreach (PMXMaterial mat in this.Materials)
            {
                this.AddToListIfRequired(requiredTextureList, mat.DiffuseTexture);
                this.AddToListIfRequired(requiredTextureList, mat.SphereTexture);

                if (!mat.StandardToon)
                {
                    this.AddToListIfRequired(requiredTextureList, mat.NonStandardToonTexture);
                }

                triangleCount += mat.Triangles.Count;
            }

            int maxAddUV = 0;

            foreach (PMXVertex v in this.Vertices)
            {
                maxAddUV = Math.Max(v.AddedUVs.Count, maxAddUV);
            }
            if (maxAddUV > 4)
            {
                throw new InvalidDataException("Maximum Add UV data is 4");
            }

            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);

            byte[] magic = Encoding.ASCII.GetBytes("PMX ");
            stream.Write(magic, 0, 4);

            Random rnd          = new Random();
            int    randomNumber = rnd.Next();

            MMDExportSettings settings = new MMDExportSettings(MMDExportSettings.ModelFormat.PMX);

            settings.Model      = this;
            settings.ExportHash = randomNumber;
            settings.ExtendedUV = (byte)maxAddUV;

            float version = 2.0f;

            foreach (PMXJoint j in this.Joints)
            {
                if (j.Type != PMXJoint.JointType.SpringSixDOF)
                {
                    version = 2.1f;
                    break;
                }
            }

            bw.Write(version);

            //Flag length
            bw.Write((byte)8);

            //Encoding (UTF-16 LE only)
            settings.TextEncoding = Encoding.Unicode;
            bw.Write((byte)0);
            bw.Write((byte)settings.ExtendedUV);

            settings.BitSettings.VertexIndexLength    = this.DetermineRequiredBitLength(this.Vertices.Count);
            settings.BitSettings.TextureIndexLength   = this.DetermineRequiredBitLength(requiredTextureList.Count);
            settings.BitSettings.MaterialIndexLength  = this.DetermineRequiredBitLength(this.Materials.Count);
            settings.BitSettings.BoneIndexLength      = this.DetermineRequiredBitLength(this.Bones.Count);
            settings.BitSettings.MorphIndexLength     = this.DetermineRequiredBitLength(this.Morphs.Count);
            settings.BitSettings.RigidBodyIndexLength = this.DetermineRequiredBitLength(this.RigidBodies.Count);

            bw.Write(settings.BitSettings.VertexIndexLength);
            bw.Write(settings.BitSettings.TextureIndexLength);
            bw.Write(settings.BitSettings.MaterialIndexLength);
            bw.Write(settings.BitSettings.BoneIndexLength);
            bw.Write(settings.BitSettings.MorphIndexLength);
            bw.Write(settings.BitSettings.RigidBodyIndexLength);

            PMXParser.WriteString(bw, settings.TextEncoding, this.NameJP);
            PMXParser.WriteString(bw, settings.TextEncoding, this.NameEN);
            PMXParser.WriteString(bw, settings.TextEncoding, this.DescriptionJP);
            PMXParser.WriteString(bw, settings.TextEncoding, this.DescriptionEN);

            //Vertices
            bw.Write((Int32)this.Vertices.Count);
            int vtxIndex = 0;

            foreach (PMXVertex v in this.Vertices)
            {
                v.AddIndexForExport(settings, vtxIndex);
                v.WriteToStream(bw, settings);
                vtxIndex++;
            }

            //Triangles
            bw.Write((Int32)(triangleCount * 3));

            foreach (PMXMaterial mat in this.Materials)
            {
                foreach (PMXTriangle t in mat.Triangles)
                {
                    t.WriteToStream(bw, settings);
                }
            }

            //Textures
            string[] textures = requiredTextureList.ToArray();
            bw.Write((Int32)textures.Length);

            foreach (string textureFile in textures)
            {
                PMXParser.WriteString(bw, settings.TextEncoding, textureFile);
            }

            //Materials
            bw.Write((Int32)this.Materials.Count);

            foreach (PMXMaterial mat in this.Materials)
            {
                mat.WriteToStream(bw, settings, textures);
            }

            //Bones
            bw.Write((Int32)this.Bones.Count);

            foreach (PMXBone bn in this.Bones)
            {
                bn.WriteToStream(bw, settings);
            }

            //Morphs
            bw.Write((Int32)this.Morphs.Count);

            foreach (PMXMorph mrph in this.Morphs)
            {
                mrph.WriteToStream(bw, settings);
            }

            //Displays
            bw.Write((Int32)this.DisplaySlots.Count);

            foreach (PMXDisplaySlot dsp in this.DisplaySlots)
            {
                dsp.WriteToStream(bw, settings);
            }

            //Rigid bodies
            bw.Write((Int32)this.RigidBodies.Count);

            foreach (PMXRigidBody bdy in this.RigidBodies)
            {
                bdy.WriteToStream(bw, settings);
            }

            //Joints
            bw.Write((Int32)this.Joints.Count);
            foreach (PMXJoint jt in this.Joints)
            {
                jt.WriteToStream(bw, settings);
            }

            //Reset triangles
            foreach (PMXVertex v in this.Vertices)
            {
                v.RemoveIndexForExport(settings);
            }


            long length = ms.Position;

            ms.Seek(0, SeekOrigin.Begin);

            ms.CopyTo(stream);

            ms.Close();
            ms = null;
        }