예제 #1
0
        public M2Array <M2Sequence> GetSequences()
        {
            M2Array <M2Sequence> sequences = new M2Array <M2Sequence>();

            foreach (var s in _model.Get <SEQS>())
            {
                M2Sequence sequence = new M2Sequence()
                {
                    AnimationId        = 0, //Todo match animation ids
                    Length             = (uint)(s.MaxTime - s.MinTime),
                    MovingSpeed        = s.MoveSpeed,
                    BlendTimeStart     = (ushort)s.BlendTime,
                    BlendTimeEnd       = (ushort)s.BlendTime,
                    Probability        = (short)(short.MaxValue * (1f - s.Frequency)),
                    MinimumRepetitions = (uint)s.MinReplay,
                    MaximumRepetitions = (uint)s.MaxReplay,
                    Bounds             = s.Bounds.Extent.ToCAaBox,
                };

                if (!s.NonLooping)
                {
                    sequence.Flags |= M2Sequence.SequenceFlags.Looped;
                }

                sequences.Add(sequence);
            }

            return(sequences);
        }
예제 #2
0
        public M2Array <M2Color> GetColors()
        {
            M2Array <M2Color> colors = new M2Array <M2Color>();

            if (!_model.Has <GEOA>())
            {
                return(colors);
            }

            foreach (var geoa in _model.Get <GEOA>())
            {
                var color = new M2Color();

                //geoa.AlphaTrack?.PopulateM2Track(color.Alpha, _model.Get<SEQS>());

                if (geoa.ColorKeys != null)
                {
                    geoa.ColorKeys.PopulateM2Track(color.Color, _model.Get <SEQS>());
                }
                else
                {
                    color.Color.Timestamps.Add(new M2Array <uint>()
                    {
                        0
                    });
                    color.Color.Values.Add(new M2Array <C3Vector>()
                    {
                        geoa.Color.ToC3Vector
                    });
                }

                colors.Add(color);
            }
            return(colors);
        }
예제 #3
0
        public M2Array <M2TextureWeight> GetTextureWeights()
        {
            M2Array <M2TextureWeight> textureweights = new M2Array <M2TextureWeight>();

            if (!_model.Has <MTLS>())
            {
                return(textureweights);
            }

            foreach (var lay in _model.Get <MTLS>().SelectMany(x => x.Layers))
            {
                M2TextureWeight weight = new M2TextureWeight();
                if (lay.AlphaKeys != null)
                {
                    lay.AlphaKeys.PopulateM2Track(weight.Weight, _model.Get <SEQS>());
                }
                else
                {
                    weight.Weight.Timestamps.Add(new M2Array <uint>()
                    {
                        0
                    });
                    weight.Weight.Values.Add(new M2Array <FixedPoint_0_15>()
                    {
                        new FixedPoint_0_15(lay.Alpha.ToShort())
                    });
                }

                textureweights.Add(weight);
            }

            return(textureweights);
        }
예제 #4
0
        public M2Array <M2Attachment> GetAttachments()
        {
            M2Array <M2Attachment> attachments = new M2Array <M2Attachment>();

            if (!_model.Has <ATCH>())
            {
                return(attachments);
            }

            foreach (var a in _model.Get <ATCH>())
            {
                M2Attachment attach = new M2Attachment()
                {
                    Id       = (uint)a.AttachmentId,
                    Position = _model.Get <PIVT>().ElementAt(a.ObjectId).ToC3Vector,
                    Bone     = (uint)a.ParentId,
                };

                attach.AnimateAttached.Timestamps.Add(new M2Array <uint>()
                {
                    0
                });
                attach.AnimateAttached.Values.Add(new M2Array <bool>()
                {
                    true
                });

                attachments.Add(attach);
            }

            return(attachments);
        }
예제 #5
0
        public static M2Array <T> ToM2Array <T>(this IEnumerable <T> values) where T : new()
        {
            var array = new M2Array <T>();

            if (values != null)
            {
                array.AddRange(values);
            }
            return(array);
        }
예제 #6
0
    public M2Array ReadM2Array(MemoryStream stream)
    {
        M2Array m2array = new M2Array
        {
            size   = ReadLong(stream),
            offset = ReadLong(stream)
        };

        return(m2array);
    }
예제 #7
0
        public static M2Array ReadM2Array(this BinaryReader reader)
        {
            M2Array array = new M2Array()
            {
                Size   = reader.ReadInt32(),
                Offset = reader.ReadInt32()
            };

            return(array);
        }
예제 #8
0
        public M2(string path, bool fixHelm) : base(path)
        {
            FixHelmOffset = fixHelm;

            if (Read <uint>(0xC) <= 264)
            {
                NeedFix = false;
            }

            Reader.BaseStream.Position = 0;
            while (Reader.BaseStream.Position < Reader.BaseStream.Length)
            {
                var chunk = (M2Chunk)Read <uint>();
                var size  = Read <uint>();

                if (chunk != M2Chunk.MD21)
                {
                    Chunks.Add(chunk, size);
                }

                switch (chunk)
                {
                case M2Chunk.MD21:
                    // Skip to modelname Array
                    var modelName = Read <M2Array>(0x10);

                    // Read modelname
                    Reader.BaseStream.Position = modelName.Offset + 8;
                    ModelName = new string(Reader.ReadChars((int)modelName.Size));

                    // Read M2Array<Texture>.
                    Textures = Read <M2Array>(0x58);

                    // Skip entire MD20 chunk.
                    Reader.BaseStream.Position = 0x8 + size;
                    break;

                case M2Chunk.TXID:
                    ReadTXID(size);
                    break;

                default:
                    Reader.BaseStream.Position += size;
                    Console.WriteLine($"Skipping chunk: {chunk}");
                    break;
                }
            }

            DataSize    = Size - (int)CalculateChunksSize() - 8;
            TextureSize = CalculateTexturesSize();

            // Read the Particle M2 Array.
            Particles = Read <M2Array>(0x130);
        }
예제 #9
0
        public M2Array <M2Material> GetMaterials()
        {
            M2Array <M2Material> materials = new M2Array <M2Material>();

            if (!_model.Has <MTLS>())
            {
                return(materials);
            }

            var layers = _model.Get <MTLS>().SelectMany(x => x.Layers);

            foreach (var layer in layers)
            {
                M2Material material = new M2Material();

                if (layer.Flags.HasFlag(MDLGEO.MODEL_GEO_UNSHADED))
                {
                    material.Flags |= M2Material.RenderFlags.Unlit;
                }
                if (layer.Flags.HasFlag(MDLGEO.MODEL_GEO_TWOSIDED))
                {
                    material.Flags |= M2Material.RenderFlags.TwoSided;
                }
                if (layer.Flags.HasFlag(MDLGEO.MODEL_GEO_UNFOGGED))
                {
                    material.Flags |= M2Material.RenderFlags.Unfogged;
                }

                switch (layer.BlendMode)
                {
                case MDLTEXOP.TEXOP_ADD:
                    material.BlendMode |= M2Material.BlendingMode.Add;
                    break;

                case MDLTEXOP.TEXOP_TRANSPARENT:     // ??
                case MDLTEXOP.TEXOP_MODULATE:
                    material.BlendMode |= M2Material.BlendingMode.Mod;
                    break;

                case MDLTEXOP.TEXOP_MODULATE2X:
                    material.BlendMode |= M2Material.BlendingMode.Mod2X;
                    break;

                case MDLTEXOP.TEXOP_ADD_ALPHA:
                    material.BlendMode |= M2Material.BlendingMode.Decal;
                    break;
                }

                materials.Add(material);
            }

            return(materials);
        }
예제 #10
0
파일: M2Texture.cs 프로젝트: Koward/M2Lib
 public static M2Array<short> GenerateTexReplaceLookup(M2Array<M2Texture> textures)
 {
     var lookup = new M2Array<short>();
     if (textures.Count == 0) return lookup;
     var maxId = (short) textures.Max(x => x.Type);
     for (short i = 0; i <= maxId; i++) lookup.Add(-1);
     for (short i = 0; i < textures.Count; i++)
     {
         var id = (short) textures[i].Type;
         if (lookup[id] == -1) lookup[id] = i;
     }
     return lookup;
 }
예제 #11
0
 public static M2Array<short> GenerateLookup(M2Array<M2Attachment> attachments)
 {
     var lookup = new M2Array<short>();
     if (attachments.Count == 0) return lookup;
     var maxId = attachments.Max(x => x.Id);
     for (short i = 0; i <= maxId; i++) lookup.Add(-1);
     for (short i = 0; i < attachments.Count; i++)
     {
         var id = (short) attachments[i].Id;
         if (lookup[id] == -1) lookup[id] = i;
     }
     return lookup;
 }
예제 #12
0
        public M2Array <M2Bone> GetBones()
        {
            var keybones = Enum.GetNames(typeof(M2Bone.KeyBone)).Select(x => x.ToLower()).ToList();

            M2Array <M2Bone> bones = new M2Array <M2Bone>();

            for (int i = 0; i < _model.Get <PIVT>().Count; i++)
            {
                var    obj  = _model.Hierachy[i];
                M2Bone bone = new M2Bone()
                {
                    KeyBoneId  = (M2Bone.KeyBone)keybones.IndexOf(obj.Name.ToLower().Replace("_", "").TrimStart('$')), //Dirty but works
                    ParentBone = (short)obj.ParentId,
                    Pivot      = _model.Get <PIVT>().ElementAt(i).ToC3Vector,
                };

                obj.RotationKeys?.PopulateM2Track(bone.Rotation, _model.Get <SEQS>());
                obj.ScaleKeys?.PopulateM2Track(bone.Scale, _model.Get <SEQS>());
                obj.TranslationKeys?.PopulateM2Track(bone.Translation, _model.Get <SEQS>());

                if (obj.TranslationKeys != null)
                {
                    bone.Flags |= M2Bone.BoneFlags.Transformed;
                }

                if (obj is Bone b)
                {
                    if (b.Flags.HasFlag(GENOBJECTFLAGS.BILLBOARD_LOCK_X))
                    {
                        bone.Flags |= M2Bone.BoneFlags.CylindricalBillboardLockX;
                    }
                    if (b.Flags.HasFlag(GENOBJECTFLAGS.BILLBOARD_LOCK_Y))
                    {
                        bone.Flags |= M2Bone.BoneFlags.CylindricalBillboardLockY;
                    }
                    if (b.Flags.HasFlag(GENOBJECTFLAGS.BILLBOARD_LOCK_Z))
                    {
                        bone.Flags |= M2Bone.BoneFlags.CylindricalBillboardLockZ;
                    }
                }

                bones.Add(bone);
            }

            return(bones);
        }
예제 #13
0
        private void FixAnimations()
        {
            Animations      = Read <M2Array>(0x1C);
            AnimationLookup = Read <M2Array>(0x24);

            for (var i = 0; i < Animations.Size; ++i)
            {
                var offset = (int)Animations.Offset + i * 0x40;
                var AnimId = Read <ushort>(offset);

                if (AnimId > 505) //< Max TLK Anim Id
                {
                    var newAnimId = AnimId;
                    switch (AnimId)
                    {
                    case 564: newAnimId = 37; break;

                    case 548: newAnimId = 41; break;

                    case 556: newAnimId = 42; break;

                    case 552: newAnimId = 43; break;

                    case 554: newAnimId = 44; break;

                    case 562: newAnimId = 45; break;

                    case 572: newAnimId = 39; break;

                    case 574: newAnimId = 187; break;
                    }

                    if (AnimId != newAnimId)
                    {
                        ReplaceAnimLookup(AnimationIndex(newAnimId), newAnimId, (short)i);
                        Write <ushort>(newAnimId, offset);
                    }
                }

                offset += 0x1C;

                // Fix Animation Speed
                Write <uint>(Read <uint>(offset) & 0xFFFF, offset);
            }
        }
예제 #14
0
        public M2Array <M2Vertex> GetVertices()
        {
            M2Array <M2Vertex> vertices = new M2Array <M2Vertex>();

            Func <int, byte[]> GetWeights = (c) =>
            {
                byte[] w = new byte[4];
                for (int i = 0; i < c; i++)
                {
                    w[i] = (byte)Math.Ceiling(255f / c);
                }

                if ((255 % c) != 0)
                {
                    w[c - 1]--; //Must add up to 255
                }
                return(w);
            };

            foreach (var geo in _model.Get <GEOS>())
            {
                var indicies = geo.GetIndicies();

                for (int i = 0; i < geo.Vertices.Count; i++)
                {
                    //Calculate weights
                    int    count   = indicies[i].Skip(1).TakeWhile(x => x != 0).Count() + 1; //Count non-zero indicies excluding first
                    byte[] weights = GetWeights(count);                                      //Build weights

                    M2Vertex vertex = new M2Vertex()
                    {
                        BoneIndices = indicies[i],
                        BoneWeights = weights,
                        Normal      = geo.Normals[i].ToC3Vector,
                        Position    = geo.Vertices[i].ToC3Vector,
                        TexCoords   = new[] { geo.TexCoords[i].ToC2Vector, new C2Vector() }
                    };
                    vertices.Add(vertex);
                }
            }

            return(vertices);
        }
예제 #15
0
        public M2Array <short> GetBoneLookup()
        {
            List <short> Bones = new List <short>();

            foreach (var geo in _model.Get <GEOS>())
            {
                foreach (var triangle in geo.FaceVertices)
                {
                    var tri = triangle.ToArray();

                    short[] triBones = new short[12];
                    for (int i = 0; i < 3; i++) //Iterate triangle
                    {
                        byte[] vertexproperty = new byte[4];
                        var    vertex         = Model.GlobalVertexList[tri[i]];

                        for (int j = 0; j < 4; j++) //Iterate vertices
                        {
                            if (vertex.BoneWeights[j] != 0)
                            {
                                if (!Bones.Contains(vertex.BoneIndices[j]))
                                {
                                    Bones.Add(vertex.BoneIndices[j]);                           //Store Bone if new
                                }
                                vertexproperty[j] = (byte)Bones.IndexOf(vertex.BoneIndices[j]); //Build Vertex Property
                            }
                        }

                        Model.Views[0].Properties.Add(new VertexProperty(vertexproperty));
                    }
                }
            }

            var result = new M2Array <short>();

            for (int i = 0; i < 4; i++)
            {
                result.AddRange(Bones);
            }

            return(result);
        }
예제 #16
0
        public M2Array <M2TextureTransform> GetTextureTransform()
        {
            M2Array <M2TextureTransform> transforms = new M2Array <M2TextureTransform>();

            if (!_model.Has <TXAN>())
            {
                return(transforms);
            }

            foreach (var txan in _model.Get <TXAN>())
            {
                var anim = new M2TextureTransform();
                txan.RotationKeys?.PopulateM2Track(anim.Rotation, _model.Get <SEQS>());
                txan.ScaleKeys?.PopulateM2Track(anim.Scale, _model.Get <SEQS>());
                txan.TranslationKeys?.PopulateM2Track(anim.Translation, _model.Get <SEQS>());
                transforms.Add(anim);
            }

            return(transforms);
        }
예제 #17
0
        public M2Array <M2Event> GetEvents()
        {
            M2Array <M2Event> events = new M2Array <M2Event>();

            if (!_model.Has <EVTS>())
            {
                return(events);
            }

            foreach (var e in _model.Get <EVTS>())
            {
                events.Add(new M2Event()
                {
                    Identifier = e.Name,
                    Position   = _model.Get <PIVT>().ElementAt(e.ObjectId).ToC3Vector
                });
            }

            return(events);
        }
예제 #18
0
        public M2Array <M2Texture> GetTextures()
        {
            M2Array <M2Texture> textures = new M2Array <M2Texture>();

            if (!_model.Has <TEXS>())
            {
                return(textures);
            }

            foreach (var t in _model.Get <TEXS>())
            {
                M2Texture texture = new M2Texture()
                {
                    Flags = (M2Texture.TextureFlags)t.Flags,
                    Name  = t.Image,
                    Type  = (M2Texture.TextureType)t.ReplaceableId
                };
                textures.Add(texture);
            }

            return(textures);
        }
예제 #19
0
파일: M2Bone.cs 프로젝트: Koward/M2Lib
 public static M2Array<short> GenerateKeyBoneLookup(M2Array<M2Bone> bones)
 {
     var lookup = new M2Array<short>();
     var maxId = (int) bones.Max(x => x.KeyBoneId);
     for (short i = 0; i < maxId + 1; i++) lookup.Add(-1);
     for (short i = 0; i < bones.Count; i++)
     {
         var id = (int) bones[i].KeyBoneId;
         if (id >= 0 && lookup[id] == -1) lookup[id] = i;
     }
     return lookup;
 }
예제 #20
0
        /// <summary>
        /// Create data of a WoW M2 Bone with the values of this class.
        /// </summary>
        public M2Bone ToBone()
        {
            var bone = new M2Bone
            {
                KeyBoneId  = GetBoneType(),
                ParentBone = (short)(Parent?.GlobalIndex ?? -1),
                Pivot      = ConvertVector(AxisInvert(GetPivot()))
            };

            foreach (var list in Translation)
            {
                var timestamps = new M2Array <uint>();
                var values     = new M2Array <C3Vector>();
                foreach (var pair in list)
                {
                    timestamps.Add(pair.Item1);
                    values.Add(ConvertVector(AxisInvert(pair.Item2 - BaseTranslation)));
                }
                bone.Translation.Timestamps.Add(timestamps);
                bone.Translation.Values.Add(values);
            }
            foreach (var list in Rotation)
            {
                var timestamps = new M2Array <uint>();
                var values     = new M2Array <C4Quaternion>();
                foreach (var pair in list)
                {
                    timestamps.Add(pair.Item1);
                    values.Add(ConvertVector(AxisInvert(pair.Item2)));
                }
                bone.Rotation.Timestamps.Add(timestamps);
                bone.Rotation.Values.Add(values);
            }
            foreach (var list in Scale)
            {
                var timestamps = new M2Array <uint>();
                var values     = new M2Array <C3Vector>();
                foreach (var pair in list)
                {
                    timestamps.Add(pair.Item1);
                    values.Add(ConvertVector(ScaleAxisInvert(pair.Item2)));
                }
                bone.Scale.Timestamps.Add(timestamps);
                bone.Scale.Values.Add(values);
            }
            //TODO maybe bezier ?
            if (Translation.Count > 0)
            {
                bone.Translation.InterpolationType = M2Track <C3Vector> .InterpolationTypes.Linear;
            }
            if (Rotation.Count > 0)
            {
                bone.Rotation.InterpolationType = M2Track <C4Quaternion> .InterpolationTypes.Linear;
            }
            if (Scale.Count > 0)
            {
                bone.Scale.InterpolationType = M2Track <C3Vector> .InterpolationTypes.Linear;
            }
            if (Translation.Count > 0 || Rotation.Count > 0 || Scale.Count > 0)
            {
                bone.Flags |= M2Bone.BoneFlags.Transformed;
            }
            return(bone);
        }
예제 #21
0
    public static void ReadMD21(MemoryStream ms, M2Data m2Data, M2Texture m2Tex)
    {
        long md20position = ms.Position;

        StreamTools s                               = new StreamTools();
        int         MD20                            = s.ReadLong(ms);    // "MD20". Legion uses a chunked file format starting with MD21.
        int         version                         = s.ReadLong(ms);
        M2Array     name                            = s.ReadM2Array(ms); // should be globally unique, used to reload by name in internal clients
        var         flags                           = s.ReadLong(ms);
        M2Array     global_loops                    = s.ReadM2Array(ms); // Timestamps used in global looping animations.
        M2Array     sequences                       = s.ReadM2Array(ms); // Information about the animations in the model.
        M2Array     sequences_lookups               = s.ReadM2Array(ms); // Mapping of sequence IDs to the entries in the Animation sequences block.
        M2Array     bones                           = s.ReadM2Array(ms); // MAX_BONES = 0x100 => Creature\SlimeGiant\GiantSlime.M2 has 312 bones(Wrath)
        M2Array     key_bone_lookup                 = s.ReadM2Array(ms); // Lookup table for key skeletal bones.
        M2Array     vertices                        = s.ReadM2Array(ms);
        int         num_skin_profiles               = s.ReadLong(ms);
        M2Array     colors                          = s.ReadM2Array(ms); // Color and alpha animations definitions.
        M2Array     textures                        = s.ReadM2Array(ms);
        M2Array     texture_weights                 = s.ReadM2Array(ms); // Transparency of textures.
        M2Array     texture_transforms              = s.ReadM2Array(ms);
        M2Array     replaceable_texture_lookup      = s.ReadM2Array(ms);
        M2Array     materials                       = s.ReadM2Array(ms); // Blending modes / render flags.
        M2Array     bone_lookup_table               = s.ReadM2Array(ms);
        M2Array     texture_lookup_table            = s.ReadM2Array(ms);
        M2Array     tex_unit_lookup_table           = s.ReadM2Array(ms); // ≥ Cata: unused
        M2Array     transparency_lookup_table       = s.ReadM2Array(ms);
        M2Array     texture_transforms_lookup_table = s.ReadM2Array(ms);

        m2Data.bounding_box = s.ReadBoundingBox(ms);                    // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height
        float       bounding_sphere_radius  = s.ReadFloat(ms);          // detail doodad draw dist = clamp (bounding_sphere_radius * detailDoodadDensityFade * detailDoodadDist, …)
        BoundingBox collision_box           = s.ReadBoundingBox(ms);
        float       collision_sphere_radius = s.ReadFloat(ms);

        M2Array collision_triangles     = s.ReadM2Array(ms);
        M2Array collision_vertices      = s.ReadM2Array(ms);
        M2Array collision_normals       = s.ReadM2Array(ms);
        M2Array attachments             = s.ReadM2Array(ms);            // position of equipped weapons or effects
        M2Array attachment_lookup_table = s.ReadM2Array(ms);
        M2Array events              = s.ReadM2Array(ms);                // Used for playing sounds when dying and a lot else.
        M2Array lights              = s.ReadM2Array(ms);                // Lights are mainly used in loginscreens but in wands and some doodads too.
        M2Array cameras             = s.ReadM2Array(ms);                // The cameras are present in most models for having a model in the character tab.
        M2Array camera_lookup_table = s.ReadM2Array(ms);
        M2Array ribbon_emitters     = s.ReadM2Array(ms);                // Things swirling around. See the CoT-entrance for light-trails.
        M2Array particle_emitters   = s.ReadM2Array(ms);

        // Name //
        ms.Position = name.offset + md20position;
        for (int n = 0; n < name.size; n++)
        {
            m2Data.name += Convert.ToChar(ms.ReadByte());
        }


        // Bones //
        ms.Position = bones.offset + md20position;
        M2TrackBase[] translationM2track = new M2TrackBase[bones.size];
        M2TrackBase[] rotationM22track   = new M2TrackBase[bones.size];
        M2TrackBase[] scaleM22track      = new M2TrackBase[bones.size];
        for (int cb = 0; cb < bones.size; cb++)
        {
            M2CompBone m2CompBone = new M2CompBone();

            m2CompBone.key_bone_id      = s.ReadLong(ms);               // Back-reference to the key bone lookup table. -1 if this is no key bone.
            m2CompBone.flags            = s.ReadUint32(ms);
            m2CompBone.parent_bone      = s.ReadShort(ms);
            m2CompBone.submesh_id       = s.ReadUint16(ms);
            m2CompBone.uDistToFurthDesc = s.ReadUint16(ms);
            m2CompBone.uZRatioOfChain   = s.ReadUint16(ms);

            translationM2track[cb] = s.ReadM2Track(ms);
            rotationM22track[cb]   = s.ReadM2Track(ms);
            scaleM22track[cb]      = s.ReadM2Track(ms);

            Vector3 pivotRaw = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale);
            m2CompBone.pivot = new Vector3(-pivotRaw.x, pivotRaw.z, -pivotRaw.y);

            m2Data.m2CompBone.Add(m2CompBone);
        }


        // Animations //
        int numberOfAnimations = 0;

        for (int ab = 0; ab < bones.size; ab++)
        {
            List <Animation_Vector3>    bone_position_animations = new List <Animation_Vector3>();
            List <Animation_Quaternion> bone_rotation_animations = new List <Animation_Quaternion>();
            List <Animation_Vector3>    bone_scale_animations    = new List <Animation_Vector3>();

            // Position //
            int numberOfPositionAnimations = translationM2track[ab].Timestamps.size;
            if (numberOfAnimations < numberOfPositionAnimations)
            {
                numberOfAnimations = numberOfPositionAnimations;
            }
            for (int at = 0; at < numberOfPositionAnimations; at++)
            {
                Animation         bone_animation = new Animation();
                Animation_Vector3 positions      = new Animation_Vector3();

                // Timestamps //
                List <int> timeStamps = new List <int>();
                ms.Position = translationM2track[ab].Timestamps.offset + md20position;
                M2Array m2AnimationOffset = s.ReadM2Array(ms);
                ms.Position = m2AnimationOffset.offset;
                for (int t = 0; t < m2AnimationOffset.size; t++)
                {
                    timeStamps.Add(s.ReadLong(ms));
                }
                positions.timeStamps = timeStamps;

                // Values //
                List <Vector3> values = new List <Vector3>();
                ms.Position = translationM2track[ab].Values.offset + md20position;
                M2Array m2AnimationValues = s.ReadM2Array(ms);
                ms.Position = m2AnimationValues.offset;
                for (int t = 0; t < m2AnimationValues.size; t++)
                {
                    Vector3 rawPosition = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale);
                    values.Add(new Vector3(-rawPosition.x, rawPosition.z, -rawPosition.y));
                }
                positions.values = values;
                bone_position_animations.Add(positions);
            }


            // Rotation //
            int numberOfRotationAnimations = rotationM22track[ab].Timestamps.size;
            if (numberOfAnimations < numberOfRotationAnimations)
            {
                numberOfAnimations = numberOfRotationAnimations;
            }
            for (int ar = 0; ar < numberOfRotationAnimations; ar++)
            {
                Animation_Quaternion rotations = new Animation_Quaternion();

                // Timestamps //
                List <int> timeStamps = new List <int>();
                ms.Position = rotationM22track[ab].Timestamps.offset + md20position;
                M2Array m2AnimationOffset = s.ReadM2Array(ms);
                ms.Position = m2AnimationOffset.offset;
                for (int t = 0; t < m2AnimationOffset.size; t++)
                {
                    timeStamps.Add(s.ReadLong(ms));
                }
                rotations.timeStamps = timeStamps;

                // Values //
                List <Quaternion> values = new List <Quaternion>();
                ms.Position = rotationM22track[ab].Values.offset + md20position;
                M2Array m2AnimationValues = s.ReadM2Array(ms);
                ms.Position = m2AnimationValues.offset;
                for (int t = 0; t < m2AnimationValues.size; t++)
                {
                    Quaternion rawRotation = s.ReadQuaternion16(ms);
                    values.Add(new Quaternion(rawRotation.x, rawRotation.y, rawRotation.z, rawRotation.w));
                }
                rotations.values = values;
                bone_rotation_animations.Add(rotations);
            }

            // Scale //
            int numberOfScaleAnimations = scaleM22track[ab].Timestamps.size;
            if (numberOfAnimations < numberOfScaleAnimations)
            {
                numberOfAnimations = numberOfScaleAnimations;
            }
            for (int aS = 0; aS < numberOfScaleAnimations; aS++)
            {
                Animation_Vector3 scales = new Animation_Vector3();

                // Timestamps //
                List <int> timeStamps = new List <int>();
                ms.Position = scaleM22track[ab].Timestamps.offset + md20position;
                M2Array m2AnimationOffset = s.ReadM2Array(ms);
                ms.Position = m2AnimationOffset.offset;
                for (int t = 0; t < m2AnimationOffset.size; t++)
                {
                    timeStamps.Add(s.ReadLong(ms));
                }
                scales.timeStamps = timeStamps;

                // Values //
                List <Vector3> values = new List <Vector3>();
                ms.Position = scaleM22track[ab].Values.offset + md20position;
                M2Array m2AnimationValues = s.ReadM2Array(ms);
                ms.Position = m2AnimationValues.offset;
                for (int t = 0; t < m2AnimationValues.size; t++)
                {
                    Vector3 rawScale = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale);
                    values.Add(new Vector3(-rawScale.x, rawScale.z, -rawScale.y));
                }
                scales.values = values;
                bone_scale_animations.Add(scales);
            }
            //Debug.Log(numberOfPositionAnimations + " " + numberOfRotationAnimations + " " + numberOfScaleAnimations);
            m2Data.position_animations.Add(bone_position_animations);
            m2Data.rotation_animations.Add(bone_rotation_animations);
            m2Data.scale_animations.Add(bone_scale_animations);
        }
        m2Data.numberOfAnimations = numberOfAnimations;

        // Bone Lookup Table //
        ms.Position = bone_lookup_table.offset + md20position;
        for (int blt = 0; blt < key_bone_lookup.size; blt++)
        {
            m2Data.bone_lookup_table.Add(s.ReadUint16(ms));
        }

        // Key-Bone Lookup //
        ms.Position = key_bone_lookup.offset + md20position;
        for (int kbl = 0; kbl < key_bone_lookup.size; kbl++)
        {
            m2Data.key_bone_lookup.Add(s.ReadShort(ms));
        }

        // Vertices //
        ms.Position     = vertices.offset + md20position;
        m2Data.meshData = new MeshData();
        for (int v = 0; v < vertices.size; v++)
        {
            Vector3 rawPosition = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale);
            m2Data.meshData.pos.Add(new Vector3(-rawPosition.x, rawPosition.z, -rawPosition.y));
            m2Data.meshData.bone_weights.Add(new float[] { ms.ReadByte() / 255.0f, ms.ReadByte() / 255.0f, ms.ReadByte() / 255.0f, ms.ReadByte() / 255.0f });
            m2Data.meshData.bone_indices.Add(new int[] { ms.ReadByte(), ms.ReadByte(), ms.ReadByte(), ms.ReadByte() });
            //Debug.Log(m2Data.meshData.bone_indices[v][0] + " " + m2Data.meshData.bone_indices[v][1] + " " + m2Data.meshData.bone_indices[v][2] + " " + m2Data.meshData.bone_indices[v][3]);
            Vector3 rawnormal = new Vector3(s.ReadFloat(ms) * Settings.worldScale, s.ReadFloat(ms) * Settings.worldScale, s.ReadFloat(ms) * Settings.worldScale);
            m2Data.meshData.normal.Add(new Vector3(-rawnormal.x, rawnormal.z, -rawnormal.y));
            m2Data.meshData.tex_coords.Add(new Vector2(s.ReadFloat(ms), s.ReadFloat(ms)));
            m2Data.meshData.tex_coords2.Add(new Vector2(s.ReadFloat(ms), s.ReadFloat(ms)));
        }

        // Textures //
        ms.Position = textures.offset + md20position;
        for (int t = 0; t < textures.size; t++)
        {
            M2Texture m2Texture = new M2Texture();

            m2Texture.type  = s.ReadLong(ms);
            m2Texture.flags = s.ReadLong(ms);

            M2Array filename = s.ReadM2Array(ms);

            // seek to filename and read //
            long savePosition = ms.Position;
            ms.Position = filename.offset + md20position;
            string fileNameString = "";
            for (int n = 0; n < filename.size; n++)
            {
                fileNameString += Convert.ToChar(ms.ReadByte());
            }
            ms.Position = savePosition;

            string fileNameStringFix = fileNameString.TrimEnd(fileNameString[fileNameString.Length - 1]);
            m2Texture.filename = fileNameStringFix;

            Texture2Ddata texture2Ddata = new Texture2Ddata();

            if (fileNameStringFix.Length > 1)
            {
                if (!LoadedBLPs.Contains(fileNameStringFix))
                {
                    string  extractedPath = Casc.GetFile(fileNameStringFix);
                    Stream  stream        = File.Open(extractedPath, FileMode.Open);
                    BLP     blp           = new BLP();
                    byte[]  data          = blp.GetUncompressed(stream, true);
                    BLPinfo info          = blp.Info();
                    texture2Ddata.hasMipmaps    = info.hasMipmaps;
                    texture2Ddata.width         = info.width;
                    texture2Ddata.height        = info.height;
                    texture2Ddata.textureFormat = info.textureFormat;
                    texture2Ddata.TextureData   = data;
                    m2Texture.texture2Ddata     = texture2Ddata;
                    stream.Close();
                    stream.Dispose();
                    stream = null;
                    LoadedBLPs.Add(fileNameString);
                }
            }
            m2Data.m2Tex.Add(m2Texture);
        }

        // texture_lookup_table //
        ms.Position = texture_lookup_table.offset + md20position;
        for (int tl = 0; tl < texture_lookup_table.size; tl++)
        {
            m2Data.textureLookupTable.Add(s.ReadUint16(ms));
        }
    }
예제 #22
0
    public static void ParseSkin(BinaryReader reader, M2Data m2Data)
    {
        string  magic        = reader.ReadFourCC();             // 'SKIN'
        M2Array vertices     = reader.ReadM2Array();
        M2Array indices      = reader.ReadM2Array();
        M2Array bones        = reader.ReadM2Array();
        M2Array submeshes    = reader.ReadM2Array();
        M2Array batches      = reader.ReadM2Array();            // nTexture_units
        int     boneCountMax = reader.ReadInt32();              // WoW takes this and divides it by the number of bones in each submesh, then stores the biggest one.
                                                                // Maximum number of bones per drawcall for each view. Related to (old) GPU numbers of registers.
                                                                // Values seen : 256, 64, 53, 21
        M2Array shadow_batches = reader.ReadM2Array();

        /// Read Batches ///
        reader.BaseStream.Seek(batches.Offset, SeekOrigin.Begin);
        for (var batch = 0; batch < batches.Size; batch++)
        {
            M2BatchIndices m2BatchIndices = new M2BatchIndices();

            m2BatchIndices.M2Batch_flags                      = reader.ReadByte();          // Usually 16 for static textures, and 0 for animated textures. &0x1: materials invert something; &0x2: transform &0x4: projected texture; &0x10: something batch compatible; &0x20: projected texture?; &0x40: use textureWeights
            m2BatchIndices.M2Batch_priorityPlane              = reader.ReadByte();
            m2BatchIndices.M2Batch_shader_id                  = reader.ReadUInt16();        // See below.
            m2BatchIndices.M2Batch_skinSectionIndex           = reader.ReadUInt16();        // A duplicate entry of a submesh from the list above.
            m2BatchIndices.M2Batch_geosetIndex                = reader.ReadUInt16();        // See below.
            m2BatchIndices.M2Batch_color_index                = reader.ReadUInt16();        // A Color out of the Colors-Block or -1 if none.
            m2BatchIndices.M2Batch_materialIndex              = reader.ReadUInt16();        // The renderflags used on this texture-unit.
            m2BatchIndices.M2Batch_materialLayer              = reader.ReadUInt16();        // Capped at 7 (see CM2Scene::BeginDraw)
            m2BatchIndices.M2Batch_textureCount               = reader.ReadUInt16();        // 1 to 4. See below. Also seems to be the number of textures to load, starting at the texture lookup in the next field (0x10).
            m2BatchIndices.M2Batch_textureComboIndex          = reader.ReadUInt16();        // Index into Texture lookup table
            m2BatchIndices.M2Batch_textureCoordComboIndex     = reader.ReadUInt16();        // Index into the texture unit lookup table.
            m2BatchIndices.M2Batch_textureWeightComboIndex    = reader.ReadUInt16();        // Index into transparency lookup table.
            m2BatchIndices.M2Batch_textureTransformComboIndex = reader.ReadUInt16();        // Index into uvanimation lookup table.

            m2Data.m2BatchIndices.Add(m2BatchIndices);
        }

        // Read SubMesh Data //
        int[] Indices   = new int[vertices.Size];                                 // Three indices which make up a triangle.
        int[] Triangles = new int[indices.Size];                                  // Bone indices (Index into BoneLookupTable)

        int[] skinSectionId         = new int[submeshes.Size];                    // Mesh part ID, see below.
        int[] submesh_StartVertex   = new int[submeshes.Size];                    // Starting vertex number.
        int[] submesh_NbrVerts      = new int[submeshes.Size];                    // Number of vertices.
        int[] submesh_StartTriangle = new int[submeshes.Size];                    // Starting triangle index (that's 3* the number of triangles drawn so far).
        int[] submesh_NbrTris       = new int[submeshes.Size];                    // Number of triangle indices.

        int[] submesh_boneCount      = new int[submeshes.Size];                   // Number of elements in the bone lookup table. Max seems to be 256 in Wrath. Shall be ≠ 0.
        int[] submesh_boneComboIndex = new int[submeshes.Size];                   // Starting index in the bone lookup table.
        int[] submesh_boneInfluences = new int[submeshes.Size];                   // <= 4
                                                                                  // from <=BC documentation: Highest number of bones needed at one time in this Submesh --Tinyn (wowdev.org)
                                                                                  // In 2.x this is the amount of of bones up the parent-chain affecting the submesh --NaK
                                                                                  // Highest number of bones referenced by a vertex of this submesh. 3.3.5a and suspectedly all other client revisions. -- Skarn
        int[]     submesh_centerBoneIndex    = new int[submeshes.Size];
        Vector3[] submesh_centerPosition     = new Vector3[submeshes.Size];       // Average position of all the vertices in the sub mesh.
        Vector3[] submesh_sortCenterPosition = new Vector3[submeshes.Size];       // The center of the box when an axis aligned box is built around the vertices in the submesh.
        float[]   submesh_sortRadius         = new float[submeshes.Size];         // Distance of the vertex farthest from CenterBoundingBox.

        /// Indices ///
        reader.BaseStream.Seek(vertices.Offset, SeekOrigin.Begin);
        for (var ind = 0; ind < vertices.Size; ind++)
        {
            Indices[ind] = reader.ReadUInt16();
        }

        /// triangles ///
        reader.BaseStream.Seek(indices.Offset, SeekOrigin.Begin);
        for (var tri = 0; tri < indices.Size; tri++)
        {
            Triangles[tri] = reader.ReadUInt16();
        }

        /// submeshes ///
        reader.BaseStream.Seek(submeshes.Offset, SeekOrigin.Begin);
        for (var sub = 0; sub < submeshes.Size; sub++)
        {
            skinSectionId[sub] = reader.ReadUInt16();
            int Level = reader.ReadUInt16();                                    // (level << 16) is added (|ed) to startTriangle and alike to avoid having to increase those fields to uint32s.
            submesh_StartVertex[sub]   = reader.ReadUInt16() + (Level << 16);
            submesh_NbrVerts[sub]      = reader.ReadUInt16();
            submesh_StartTriangle[sub] = reader.ReadUInt16() + (Level << 16);
            submesh_NbrTris[sub]       = reader.ReadUInt16();

            submesh_boneCount[sub]       = reader.ReadUInt16();
            submesh_boneComboIndex[sub]  = reader.ReadUInt16();
            submesh_boneInfluences[sub]  = reader.ReadUInt16();
            submesh_centerBoneIndex[sub] = reader.ReadUInt16();

            Vector3 canterPosition = new Vector3(reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE);
            submesh_centerPosition[sub] = new Vector3(-canterPosition.x, canterPosition.z, -canterPosition.y);
            Vector3 sortCenterPosition = new Vector3(reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE, reader.ReadSingle() / Settings.WORLD_SCALE);
            submesh_sortCenterPosition[sub] = new Vector3(-sortCenterPosition.x, sortCenterPosition.z, -sortCenterPosition.y);

            submesh_sortRadius[sub] = reader.ReadSingle();
        }

        /// Assemble Submeshes ///
        m2Data.submeshData = new List <SubmeshData>();
        for (int sm = 0; sm < submeshes.Size; sm++)
        {
            Vector3[] vertList  = new Vector3[submesh_NbrVerts[sm]];
            Vector3[] normsList = new Vector3[submesh_NbrVerts[sm]];
            Vector2[] uvsList   = new Vector2[submesh_NbrVerts[sm]];
            Vector2[] uvs2List  = new Vector2[submesh_NbrVerts[sm]];

            BoneWeights[] boneWeights = new BoneWeights[submesh_NbrVerts[sm]];

            for (int vn = 0; vn < submesh_NbrVerts[sm]; vn++)
            {
                vertList[vn]  = m2Data.meshData.pos[vn + submesh_StartVertex[sm]];
                normsList[vn] = m2Data.meshData.normal[vn + submesh_StartVertex[sm]];
                uvsList[vn]   = m2Data.meshData.tex_coords[vn + submesh_StartVertex[sm]];
                uvs2List[vn]  = m2Data.meshData.tex_coords2[vn + submesh_StartVertex[sm]];

                BoneWeights boneWeightVert = new BoneWeights();
                int[]       boneIndex      = new int[4];
                float[]     boneWeight     = new float[4];

                for (int bn = 0; bn < 4; bn++)
                {
                    boneIndex[bn]  = m2Data.meshData.bone_indices[vn + submesh_boneComboIndex[sm]][bn];
                    boneWeight[bn] = m2Data.meshData.bone_weights[vn + submesh_boneComboIndex[sm]][bn];
                }
                boneWeightVert.boneIndex  = boneIndex;
                boneWeightVert.boneWeight = boneWeight;
                boneWeights[vn]           = boneWeightVert;
            }

            int[] triList = new int[submesh_NbrTris[sm]];
            for (var t = 0; t < submesh_NbrTris[sm]; t++)
            {
                //triList[t] = Triangles[t + submesh_StartTriangle[sm]] - submesh_StartVertex[sm];  // using Separate Meshes, reset first triangle to index 0;
                triList[t] = Triangles[t + submesh_StartTriangle[sm]];                              // using Unity Submeshes, don't reset first triangle to index 0;
            }


            SubmeshData submeshData = new SubmeshData();

            submeshData.ID        = skinSectionId[sm];
            submeshData.vertList  = vertList;
            submeshData.normsList = normsList;
            submeshData.uvsList   = uvsList;
            submeshData.uvs2List  = uvs2List;
            Array.Reverse(triList);
            submeshData.triList                = triList;
            submeshData.submesh_StartVertex    = submesh_StartVertex[sm];
            submeshData.boneWeights            = boneWeights;
            submeshData.submesh_boneCount      = submesh_boneCount[sm];
            submeshData.submesh_boneInfluences = submesh_boneInfluences[sm];
            m2Data.submeshData.Add(submeshData);
        }

        /// Read Bone Data ///
        // byte[] Properties = new byte[bones.Size];
        // reader.BaseStream.Seek(bones.Offset, SeekOrigin.Current);
        // for (var bone = 0; bone < bones.Size; bone++)
        // {
        //     Properties[bone] = reader.ReadByte();
        // }
    }
예제 #23
0
    public static void ReadMD21(BinaryReader br, M2Data m2Data, M2Texture m2Tex)
    {
        long md20position = br.BaseStream.Position;

        int     MD20                            = br.ReadInt32();                    // "MD20". Legion uses a chunked file format starting with MD21.
        int     version                         = br.ReadInt32();
        M2Array name                            = br.ReadM2Array();                  // should be globally unique, used to reload by name in internal clients
        var     flags                           = br.ReadInt32();
        M2Array global_loops                    = br.ReadM2Array();                  // Timestamps used in global looping animations.
        M2Array sequences                       = br.ReadM2Array();                  // Information about the animations in the model.
        M2Array sequences_lookups               = br.ReadM2Array();                  // Mapping of sequence IDs to the entries in the Animation sequences block.
        M2Array bones                           = br.ReadM2Array();                  // MAX_BONES = 0x100 => Creature\SlimeGiant\GiantSlime.M2 has 312 bones(Wrath)
        M2Array key_bone_lookup                 = br.ReadM2Array();                  // Lookup table for key skeletal bones.
        M2Array vertices                        = br.ReadM2Array();
        int     num_skin_profiles               = br.ReadInt32();
        M2Array colors                          = br.ReadM2Array();                    // Color and alpha animations definitions.
        M2Array textures                        = br.ReadM2Array();
        M2Array texture_weights                 = br.ReadM2Array();                    // Transparency of textures.
        M2Array texture_transforms              = br.ReadM2Array();
        M2Array replaceable_texture_lookup      = br.ReadM2Array();
        M2Array materials                       = br.ReadM2Array();                          // Blending modes / render flags.
        M2Array bone_lookup_table               = br.ReadM2Array();
        M2Array texture_lookup_table            = br.ReadM2Array();
        M2Array tex_unit_lookup_table           = br.ReadM2Array();              // ≥ Cata: unused
        M2Array transparency_lookup_table       = br.ReadM2Array();
        M2Array texture_transforms_lookup_table = br.ReadM2Array();

        m2Data.bounding_box = br.ReadBoundingBoxes();                              // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height
        float       bounding_sphere_radius  = br.ReadSingle();                     // detail doodad draw dist = clamp (bounding_sphere_radius * detailDoodadDensityFade * detailDoodadDist, …)
        BoundingBox collision_box           = br.ReadBoundingBoxes();
        float       collision_sphere_radius = br.ReadSingle();

        M2Array collision_triangles     = br.ReadM2Array();
        M2Array collision_vertices      = br.ReadM2Array();
        M2Array collision_normals       = br.ReadM2Array();
        M2Array attachments             = br.ReadM2Array();                            // position of equipped weapons or effects
        M2Array attachment_lookup_table = br.ReadM2Array();
        M2Array events              = br.ReadM2Array();                                // Used for playing sounds when dying and a lot else.
        M2Array lights              = br.ReadM2Array();                                // Lights are mainly used in loginscreens but in wands and some doodads too.
        M2Array cameras             = br.ReadM2Array();                                // The cameras are present in most models for having a model in the character tab.
        M2Array camera_lookup_table = br.ReadM2Array();
        M2Array ribbon_emitters     = br.ReadM2Array();                                // Things swirling around. See the CoT-entrance for light-trails.
        M2Array particle_emitters   = br.ReadM2Array();

        // Name //
        br.BaseStream.Position = name.Offset + md20position;
        for (int n = 0; n < name.Size; n++)
        {
            m2Data.name += Convert.ToChar(br.ReadByte());
        }

        // Bones //
        br.BaseStream.Position = bones.Offset + md20position;
        M2TrackBase[] translationM2track = new M2TrackBase[bones.Size];
        M2TrackBase[] rotationM22track   = new M2TrackBase[bones.Size];
        M2TrackBase[] scaleM22track      = new M2TrackBase[bones.Size];
        for (int cb = 0; cb < bones.Size; cb++)
        {
            M2CompBone m2CompBone = new M2CompBone();

            m2CompBone.key_bone_id      = br.ReadInt32();                        // Back-reference to the key bone lookup table. -1 if this is no key bone.
            m2CompBone.flags            = br.ReadInt32();
            m2CompBone.parent_bone      = br.ReadInt16();
            m2CompBone.submesh_id       = br.ReadUInt16();
            m2CompBone.uDistToFurthDesc = br.ReadUInt16();
            m2CompBone.uZRatioOfChain   = br.ReadUInt16();

            translationM2track[cb] = br.ReadM2Track();
            rotationM22track[cb]   = br.ReadM2Track();
            scaleM22track[cb]      = br.ReadM2Track();

            Vector3 pivotRaw = new Vector3(br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale);
            m2CompBone.pivot = new Vector3(-pivotRaw.x, pivotRaw.z, -pivotRaw.y);

            m2Data.m2CompBone.Add(m2CompBone);
        }

        // Animations //
        int numberOfAnimations = 0;

        for (int ab = 0; ab < bones.Size; ab++)
        {
            List <Animation_Vector3>    bone_position_animations = new List <Animation_Vector3>();
            List <Animation_Quaternion> bone_rotation_animations = new List <Animation_Quaternion>();
            List <Animation_Vector3>    bone_scale_animations    = new List <Animation_Vector3>();

            // Position //
            int numberOfPositionAnimations = translationM2track[ab].Timestamps.Size;
            if (numberOfAnimations < numberOfPositionAnimations)
            {
                numberOfAnimations = numberOfPositionAnimations;
            }
            for (int at = 0; at < numberOfPositionAnimations; at++)
            {
                Animation         bone_animation = new Animation();
                Animation_Vector3 positions      = new Animation_Vector3();

                // Timestamps //
                List <int> timeStamps = new List <int>();
                br.BaseStream.Position = translationM2track[ab].Timestamps.Offset + md20position;
                M2Array m2AnimationOffset = br.ReadM2Array();
                br.BaseStream.Position = m2AnimationOffset.Offset;
                for (int t = 0; t < m2AnimationOffset.Size; t++)
                {
                    timeStamps.Add(br.ReadInt32());
                }
                positions.timeStamps = timeStamps;

                // Values //
                List <Vector3> values = new List <Vector3>();
                br.BaseStream.Position = translationM2track[ab].Values.Offset + md20position;
                M2Array m2AnimationValues = br.ReadM2Array();
                br.BaseStream.Position = m2AnimationValues.Offset;
                for (int t = 0; t < m2AnimationValues.Size; t++)
                {
                    Vector3 rawPosition = new Vector3(br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale);
                    values.Add(new Vector3(-rawPosition.x, rawPosition.z, -rawPosition.y));
                }
                positions.values = values;
                bone_position_animations.Add(positions);
            }


            // Rotation //
            int numberOfRotationAnimations = rotationM22track[ab].Timestamps.Size;
            if (numberOfAnimations < numberOfRotationAnimations)
            {
                numberOfAnimations = numberOfRotationAnimations;
            }
            for (int ar = 0; ar < numberOfRotationAnimations; ar++)
            {
                Animation_Quaternion rotations = new Animation_Quaternion();

                // Timestamps //
                List <int> timeStamps = new List <int>();
                br.BaseStream.Position = rotationM22track[ab].Timestamps.Offset + md20position;
                M2Array m2AnimationOffset = br.ReadM2Array();
                br.BaseStream.Position = m2AnimationOffset.Offset;
                for (int t = 0; t < m2AnimationOffset.Size; t++)
                {
                    timeStamps.Add(br.ReadInt32());
                }
                rotations.timeStamps = timeStamps;

                // Values //
                List <Quaternion> values = new List <Quaternion>();
                br.BaseStream.Position = rotationM22track[ab].Values.Offset + md20position;
                M2Array m2AnimationValues = br.ReadM2Array();
                br.BaseStream.Position = m2AnimationValues.Offset;
                for (int t = 0; t < m2AnimationValues.Size; t++)
                {
                    Quaternion rawRotation = br.ReadQuaternion();
                    values.Add(new Quaternion(rawRotation.x, rawRotation.y, rawRotation.z, rawRotation.w));
                }
                rotations.values = values;
                bone_rotation_animations.Add(rotations);
            }

            // Scale //
            int numberOfScaleAnimations = scaleM22track[ab].Timestamps.Size;
            if (numberOfAnimations < numberOfScaleAnimations)
            {
                numberOfAnimations = numberOfScaleAnimations;
            }
            for (int aS = 0; aS < numberOfScaleAnimations; aS++)
            {
                Animation_Vector3 scales = new Animation_Vector3();

                // Timestamps //
                List <int> timeStamps = new List <int>();
                br.BaseStream.Position = scaleM22track[ab].Timestamps.Offset + md20position;
                M2Array m2AnimationOffset = br.ReadM2Array();
                br.BaseStream.Position = m2AnimationOffset.Offset;
                for (int t = 0; t < m2AnimationOffset.Size; t++)
                {
                    timeStamps.Add(br.ReadInt32());
                }
                scales.timeStamps = timeStamps;

                // Values //
                List <Vector3> values = new List <Vector3>();
                br.BaseStream.Position = scaleM22track[ab].Values.Offset + md20position;
                M2Array m2AnimationValues = br.ReadM2Array();
                br.BaseStream.Position = m2AnimationValues.Offset;
                for (int t = 0; t < m2AnimationValues.Size; t++)
                {
                    Vector3 rawScale = new Vector3(br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale);
                    values.Add(new Vector3(-rawScale.x, rawScale.z, -rawScale.y));
                }
                scales.values = values;
                bone_scale_animations.Add(scales);
            }
            //Debug.Log(numberOfPositionAnimations + " " + numberOfRotationAnimations + " " + numberOfScaleAnimations);
            m2Data.position_animations.Add(bone_position_animations);
            m2Data.rotation_animations.Add(bone_rotation_animations);
            m2Data.scale_animations.Add(bone_scale_animations);
        }
        m2Data.numberOfAnimations = numberOfAnimations;

        // Bone Lookup Table //
        br.BaseStream.Position = bone_lookup_table.Offset + md20position;
        for (int blt = 0; blt < key_bone_lookup.Size; blt++)
        {
            m2Data.bone_lookup_table.Add(br.ReadUInt16());
        }

        // Key-Bone Lookup //
        br.BaseStream.Position = key_bone_lookup.Offset + md20position;
        for (int kbl = 0; kbl < key_bone_lookup.Size; kbl++)
        {
            m2Data.key_bone_lookup.Add(br.ReadUInt16());
        }

        // Vertices //
        br.BaseStream.Position = vertices.Offset + md20position;
        m2Data.meshData        = new MeshData();
        for (int v = 0; v < vertices.Size; v++)
        {
            Vector3 rawPosition = new Vector3(br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale, br.ReadSingle() / Settings.WorldScale);
            m2Data.meshData.pos.Add(new Vector3(-rawPosition.x, rawPosition.z, -rawPosition.y));
            m2Data.meshData.bone_weights.Add(new float[] { br.ReadByte() / 255.0f, br.ReadByte() / 255.0f, br.ReadByte() / 255.0f, br.ReadByte() / 255.0f });
            m2Data.meshData.bone_indices.Add(new int[] { br.ReadByte(), br.ReadByte(), br.ReadByte(), br.ReadByte() });
            //Debug.Log(m2Data.meshData.bone_indices[v][0] + " " + m2Data.meshData.bone_indices[v][1] + " " + m2Data.meshData.bone_indices[v][2] + " " + m2Data.meshData.bone_indices[v][3]);
            Vector3 rawnormal = new Vector3(br.ReadSingle() * Settings.WorldScale, br.ReadSingle() * Settings.WorldScale, br.ReadSingle() * Settings.WorldScale);
            m2Data.meshData.normal.Add(new Vector3(-rawnormal.x, rawnormal.z, -rawnormal.y));
            m2Data.meshData.tex_coords.Add(new Vector2(br.ReadSingle(), br.ReadSingle()));
            m2Data.meshData.tex_coords2.Add(new Vector2(br.ReadSingle(), br.ReadSingle()));
        }

        // texture_lookup_table //
        br.BaseStream.Position = texture_lookup_table.Offset + md20position;
        for (int tl = 0; tl < texture_lookup_table.Size; tl++)
        {
            m2Data.textureLookupTable.Add(br.ReadUInt16());
        }
    }
예제 #24
0
        public M2Array <M2Camera> GetCameras()
        {
            M2Array <M2Camera> cameras = new M2Array <M2Camera>();

            if (!_model.Has <CAMS>())
            {
                return(cameras);
            }

            foreach (var c in _model.Get <CAMS>())
            {
                M2Camera camera = new M2Camera()
                {
                    FarClip            = c.FarClip,
                    FieldOfView        = new M2Track <C3Vector>(),
                    NearClip           = c.NearClip,
                    PositionBase       = c.Pivot.ToC3Vector,
                    TargetPositionBase = c.TargetPosition.ToC3Vector
                };
                camera.FieldOfView.Timestamps.Add(new M2Array <uint>()
                {
                    0
                });
                camera.FieldOfView.Values.Add(new M2Array <C3Vector>()
                {
                    new C3Vector(c.FieldOfView, 0, 0)
                });

                switch (c.Name.ToUpper())
                {
                case "PORTRAIT":
                    camera.Type = M2Camera.CameraType.Portrait;
                    break;

                case "PAPERDOLL":
                    camera.Type = M2Camera.CameraType.CharacterInfo;
                    break;

                default:
                    continue;
                }

                cameras.Add(camera);
            }

            //Add missing CharacterInfo camera
            if (!cameras.Any(x => x.Type == M2Camera.CameraType.CharacterInfo) && cameras.Any(x => x.Type == M2Camera.CameraType.Portrait))
            {
                var      c      = cameras.First(x => x.Type == M2Camera.CameraType.Portrait);
                M2Camera camera = new M2Camera()
                {
                    FarClip            = c.FarClip,
                    FieldOfView        = c.FieldOfView,
                    NearClip           = c.NearClip,
                    PositionBase       = c.PositionBase,
                    TargetPositionBase = c.TargetPositionBase,
                    Type = M2Camera.CameraType.CharacterInfo
                };

                cameras.Add(camera);
            }

            return(cameras);
        }
예제 #25
0
        public static M2Array <T> ReadM2Array <T>(this BinaryReader reader, uint version)
        {
            var array = new M2Array <T>(reader, version);

            return(array.Count > 0 ? array : null);
        }