Ejemplo n.º 1
0
    public static void Load(string dataPath, int uniqueID, Vector3 position, Quaternion rotation, Vector3 scale)
    {
        M2Data    m2Data = new M2Data();
        M2Texture m2Tex  = new M2Texture();

        m2Data.dataPath = dataPath;
        m2Data.uniqueID = uniqueID;
        m2Data.position = position;
        m2Data.rotation = rotation;
        m2Data.scale    = scale;

        try
        {
            ThreadWorking = true;

            ParseM2_Root(dataPath, m2Data, m2Tex);
            ParseM2_Skin(dataPath, m2Data);
            AllM2Data.Enqueue(m2Data);

            ThreadWorking = false;
        }
        catch (Exception ex)
        {
            Debug.Log("Error : Trying to parse M2 - " + dataPath);
            Debug.LogException(ex);
        }
    }
Ejemplo n.º 2
0
    private static void ParseM2_Root(string dataPath, M2Data m2Data, M2Texture m2Tex)
    {
        StreamTools s    = new StreamTools();
        string      path = Casc.GetFile(dataPath);

        byte[] M2MainData     = File.ReadAllBytes(path);
        long   streamPosition = 0;

        using (MemoryStream ms = new MemoryStream(M2MainData))
        {
            while (streamPosition < ms.Length)
            {
                ms.Position = streamPosition;
                int chunkID   = s.ReadLong(ms);
                int chunkSize = s.ReadLong(ms);

                streamPosition = ms.Position + chunkSize;

                switch (chunkID)
                {
                case (int)ChunkID.M2ChunkID.MD21:
                    ReadMD21(ms, m2Data, m2Tex);
                    break;

                default:
                    SkipUnknownChunk(ms, chunkID, chunkSize);
                    break;
                }
            }
        };
    }
Ejemplo n.º 3
0
    public static void Load(uint FileDataId, int uniqueID, Vector3 position, Quaternion rotation, Vector3 scale, CASCHandler Handler)
    {
        M2Data    m2Data = new M2Data();
        M2Texture m2Tex  = new M2Texture();

        m2Data.FileDataId = FileDataId;
        m2Data.uniqueID   = uniqueID;
        m2Data.position   = position;
        m2Data.rotation   = rotation;
        m2Data.scale      = scale;

        try
        {
            ThreadWorking = true;

            ParseM2_Root(FileDataId, m2Data, m2Tex, Handler);

            foreach (uint skinFile in SkinFiles)
            {
                ParseM2_Skin(skinFile, m2Data, Handler);
            }

            AllM2Data.Enqueue(m2Data);

            ThreadWorking = false;
        }
        catch (Exception ex)
        {
            Debug.Log("Error : Trying to parse M2 - " + FileDataId);
            Debug.LogException(ex);
        }
    }
Ejemplo n.º 4
0
    //Load specific texture
    private int LoadTexture(M2Texture texture, int i)
    {
        int file  = -1;
        int index = Array.FindIndex(character.Options, o => o.Form == character.Form);

        switch (texture.Type)
        {
        case 0:
            file = Model.TextureIDs[i];
            break;

        case 11:
            file = character.Choices[index][character.Customization[index]].Textures[0].Texture1;
            break;

        case 12:
            file = character.Choices[index][character.Customization[index]].Textures[0].Texture2;
            break;

        case 13:
            file = character.Choices[index][character.Customization[index]].Textures[0].Texture3;
            break;
        }
        return(file);
    }
Ejemplo n.º 5
0
    public static void ReadTXID(BinaryReader br, M2Data m2Data, CASCHandler CascHandler, uint Size)
    {
        LoadedBLPFileDataIds.Clear();
        var numTextures = Size / 4;

        for (int i = 0; i < numTextures; i++)
        {
            uint texture = br.ReadUInt32();

            M2Texture     m2Texture     = new M2Texture();
            Texture2Ddata texture2Ddata = new Texture2Ddata();
            if (!LoadedBLPFileDataIds.Contains(texture))
            {
                var     stream = CascHandler.OpenFile(texture);
                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;
                m2Texture.FileDataId    = texture;

                stream.Close();
                stream.Dispose();

                LoadedBLPFileDataIds.Add(texture);
            }
            m2Data.m2Tex.Add(m2Texture);
        }
    }
Ejemplo n.º 6
0
        protected override int LoadTexture(M2Texture texture, int i, out bool skin)
        {
            int file = -1;
            int index;

            skin = false;
            switch (texture.Type)
            {
            case 0:
                file = Model.TextureIDs[i];
                break;

            case 1:
                index = Array.FindIndex(Character.Options, o => o.Name == "Skin Color");
                file  = Character.Choices[index][Character.Customization[index]].Textures[0].Texture1;
                skin  = true;
                break;

            case 2:
                file = Character.Items[2] != null ? Character.Items[2].LeftTexture : -1;
                break;

            case 6:
                index = Array.FindIndex(Character.Options, o => o.Name == "Hair Color");
                file  = Character.Choices[index][Character.Customization[index]].Textures[0].Texture1;
                break;

            case 19:
                index = Array.FindIndex(Character.Options, o => o.Name == "Eye Color");
                file  = Character.Choices[index][Character.Customization[index]].Textures[0].Texture1;
                break;
            }
            return(file);
        }
Ejemplo n.º 7
0
    //Load specific texture
    private int LoadTexture(M2Texture texture, int i)
    {
        int file = 0;

        switch (texture.Type)
        {
        case 0:
            file = Model.TextureIDs[i];
            break;

        case 2:
            file = MainTexture;
            break;
        }
        return(file);
    }
Ejemplo n.º 8
0
        public M2Texture ToWoW()
        {
            var wowTexture = new M2Texture {
                Type = M2Texture.TextureType.Monster1
            };                                                                      //TODO type with name

            if (WrapU)
            {
                wowTexture.Flags |= M2Texture.TextureFlags.WrapX;
            }
            if (WrapV)
            {
                wowTexture.Flags |= M2Texture.TextureFlags.WrapY;
            }
            return(wowTexture);
        }
Ejemplo n.º 9
0
        public static void M2Textures()
        {
            SpecialSeek(openedFile.texturesPos);

            for (int i = 0; i < openedFile.texturesNum; i++)
            {
                M2Texture text = new M2Texture();
                text.type  = reader.ReadUInt32();
                text.flags = reader.ReadUInt32();

                text.textureLength = reader.ReadUInt32();
                text.texturePos    = reader.ReadUInt32();

                oldPos = reader.BaseStream.Position;

                SpecialSeek(text.texturePos);
                text.texturePath = reader.ReadBytes((int)text.textureLength);
                reader.BaseStream.Seek(oldPos, SeekOrigin.Begin);
                openedFile.textures.Add(text);
            }
        }
Ejemplo n.º 10
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);
        }
    //Load specific texture
    private int LoadTexture(M2Texture texture, int i)
    {
        int file = -1;
        int index;

        switch (texture.Type)
        {
        case 0:
            file = Model.TextureIDs[i];
            break;

        case 2:
            file = Texture;
            break;

        case 8:
            index = Array.FindIndex(character.Options, o => o.Name == "Paint");
            file  = character.Choices[index][character.Customization[index]].Textures[0].Texture1;
            break;
        }
        return(file);
    }
Ejemplo n.º 12
0
    private static void ParseM2_Root(uint fileDataID, M2Data m2Data, M2Texture m2Tex, CASCHandler CascHandler)
    {
        long streamPos = 0;

        using (var stream = CascHandler.OpenFile(fileDataID))
            using (BinaryReader reader = new BinaryReader(stream))
            {
                while (streamPos < stream.Length)
                {
                    stream.Position = streamPos;
                    M2ChunkId chunkID   = (M2ChunkId)reader.ReadUInt32();
                    uint      chunkSize = reader.ReadUInt32();

                    streamPos = stream.Position + chunkSize;

                    switch (chunkID)
                    {
                    case M2ChunkId.MD21:
                        ReadMD21(reader, m2Data, m2Tex);
                        break;

                    case M2ChunkId.SFID:
                        ReadSFID(reader, chunkSize);
                        break;

                    case M2ChunkId.TXID:
                        ReadTXID(reader, m2Data, CascHandler, chunkSize);
                        break;

                    default:
                        SkipUnknownChunk(stream, chunkSize);
                        break;
                    }
                }
            };
    }
Ejemplo n.º 13
0
    public static void Load(uint FileDataId, int uniqueID, Vector3 position, Quaternion rotation, Vector3 scale, CASCHandler Handler)
    {
        M2Data    m2Data = new M2Data();
        M2Texture m2Tex  = new M2Texture();

        m2Data.FileDataId = FileDataId;
        m2Data.uniqueID   = uniqueID;
        m2Data.position   = position;
        m2Data.rotation   = rotation;
        m2Data.scale      = scale;

        ThreadWorking = true;

        ParseM2_Root(FileDataId, m2Data, m2Tex, Handler);

        foreach (uint skinFile in SkinFiles)
        {
            ParseM2_Skin(skinFile, m2Data, Handler);
        }

        AllM2Data.Enqueue(m2Data);

        ThreadWorking = false;
    }
Ejemplo n.º 14
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));
        }
    }
Ejemplo n.º 15
0
 //Load texture from casc
 protected abstract int LoadTexture(M2Texture texture, int i, out bool skin);
Ejemplo n.º 16
0
        /// <inheritdoc/>
        public void LoadBinaryData(byte[] inData)
        {
            using (var ms = new MemoryStream(inData))
                using (var br = new BinaryReader(ms))
                {
                    br.ReadUInt32(); // Signature
                    Version = br.ReadUInt32();
                    Name    = br.ReadMD20String(br.ReadUInt32(), br.ReadUInt32());
                    Flags   = br.ReadUInt32(); // TODO: Implement Flags


                    // Global Sequences
                    UInt32 count     = br.ReadUInt32();
                    UInt32 offset    = br.ReadUInt32();
                    long   headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        UInt32 value = br.ReadUInt32();
                        GlobalSequences.Add(value);
                    }
                    br.BaseStream.Position = headerpos;

                    // Sequences
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Sequence seq = new M2Sequence();

                        seq.AnimationID         = br.ReadUInt16();
                        seq.SubAnimationID      = br.ReadUInt16();
                        seq.Length              = br.ReadUInt32();
                        seq.MovingSpeed         = br.ReadSingle();
                        seq.Flags               = br.ReadUInt32();
                        seq.Probability         = br.ReadInt16();
                        seq.Padding             = br.ReadUInt16();
                        seq.MinimumRepetitions  = br.ReadUInt32();
                        seq.MaximumRepetitions  = br.ReadUInt32();
                        seq.BlendTime           = br.ReadUInt32();
                        seq.BoundsMinimumExtend = new C3Vector(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        seq.BoundsMaximumExtend = new C3Vector(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        seq.BoundRadius         = br.ReadSingle();
                        seq.NextAnimation       = br.ReadInt16();
                        seq.aliasNext           = br.ReadUInt16();

                        Sequences.Add(seq);
                    }
                    br.BaseStream.Position = headerpos;

                    //SequencesLookups
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        SequencesLookups.Add(br.ReadInt16());
                    }
                    br.BaseStream.Position = headerpos;

                    // Bones
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Bone bone = new M2Bone();

                        bone.KeyBoneID  = br.ReadInt32();
                        bone.Flags      = br.ReadUInt32();
                        bone.ParentBone = br.ReadInt16();
                        bone.SubmeshID  = br.ReadUInt16();

                        bone.CompressData[0] = br.ReadUInt16();
                        bone.CompressData[1] = br.ReadUInt16();

                        //translation

                        M2Track translation = new M2Track();
                        translation.readM2Track(br);
                        bone.translation = translation;

                        // rotation
                        M2Track rotation = new M2Track();
                        rotation.readM2Track(br);
                        bone.rotation = rotation;

                        // Scale
                        M2Track scale = new M2Track();
                        scale.readM2Track(br);
                        bone.scale = scale;

                        bone.pivot = new C3Vector(br.ReadUInt32(), br.ReadUInt32(), br.ReadUInt32());

                        Bones.Add(bone);
                    }
                    br.BaseStream.Position = headerpos;

                    // key_bone_lookup
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        KeyBoneLookup.Add(br.ReadInt16());
                    }
                    br.BaseStream.Position = headerpos;

                    // Vetices
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Vertex temp = new M2Vertex();

                        temp.Pos = new C3Vector(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        for (int a = 0; a < 4; a++)
                        {
                            temp.BoneWeights.Add(br.ReadByte());
                        }
                        for (int a = 0; a < 4; a++)
                        {
                            temp.BoneIndices.Add(br.ReadByte());
                        }
                        temp.Normal = new C3Vector(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                        temp.TexCords.Add(new C2Vector(br.ReadSingle(), br.ReadSingle()));
                        temp.TexCords.Add(new C2Vector(br.ReadSingle(), br.ReadSingle()));
                    }
                    br.BaseStream.Position = headerpos;

                    // Number of Skin profiles
                    NumberSkinProfiles = br.ReadUInt32();

                    // Colors
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Color temp = new M2Color();

                        // Color
                        M2Track color = new M2Track();
                        color.readM2Track(br);
                        temp.Color = color;

                        // Alpha
                        M2Track alpha = new M2Track();
                        alpha.readM2Track(br);
                        temp.Alpha = alpha;

                        Color.Add(temp);
                    }
                    br.BaseStream.Position = headerpos;

                    // Textures
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Texture temp = new M2Texture();

                        temp.Type  = br.ReadUInt32();
                        temp.Flags = br.ReadUInt32();

                        UInt32 tCount     = br.ReadUInt32();
                        UInt32 tOffset    = br.ReadUInt32();
                        long   tHeaderpos = br.BaseStream.Position;
                        br.BaseStream.Position = tOffset;

                        temp.Filename = "";
                        for (int a = 0; a < tCount; a++)
                        {
                            temp.Filename += br.ReadChar();
                        }
                        br.BaseStream.Position = tHeaderpos;

                        Texture.Add(temp);
                    }
                    br.BaseStream.Position = headerpos;

                    // Texture Weights
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Track temp = new M2Track();
                        temp.readM2Track(br);
                        TextureWeights.Add(temp);
                    }
                    br.BaseStream.Position = headerpos;

                    // UV Animations
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2TextureTransform temp = new M2TextureTransform();

                        M2Track translation = new M2Track();
                        translation.readM2Track(br);
                        temp.Translation = translation;

                        M2Track rotation = new M2Track();
                        rotation.readM2Track(br);
                        temp.Rotation = rotation;

                        M2Track scaling = new M2Track();
                        scaling.readM2Track(br);
                        temp.Scaling = scaling;

                        UvAnimations.Add(temp);
                    }
                    br.BaseStream.Position = headerpos;

                    // Texture Replacements
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        TextureReplacements.Add(br.ReadInt16());
                    }
                    br.BaseStream.Position = headerpos;

                    // Materials
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        M2Material temp = new M2Material();

                        temp.Flags     = br.ReadUInt16();
                        temp.BlendMode = br.ReadUInt16();

                        Materials.Add(temp);
                    }
                    br.BaseStream.Position = headerpos;

                    // Bone Lookups
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        BoneLookups.Add(br.ReadUInt16());
                    }
                    br.BaseStream.Position = headerpos;

                    // Texture Units
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        TextureUnits.Add(br.ReadUInt16());
                    }
                    br.BaseStream.Position = headerpos;

                    // Texture Weights Lookups
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        TextureWeightsLookups.Add(br.ReadUInt16());
                    }
                    br.BaseStream.Position = headerpos;

                    // Animation Lookups
                    count     = br.ReadUInt32();
                    offset    = br.ReadUInt32();
                    headerpos = br.BaseStream.Position;
                    br.BaseStream.Position = offset;
                    for (int i = 0; i < count; i++)
                    {
                        UvAnimationLookups.Add(br.ReadInt16());
                    }
                    br.BaseStream.Position = headerpos;
                }
        }
Ejemplo n.º 17
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());
        }
    }