//Load all the date into the object
    public M2 LoadModel(byte[] dataBytes, byte[] skinBytes, byte[] skelBytes)
    {
        M2 model = new M2();

        model.LoadFile(dataBytes);
        model.Skin.LoadFile(skinBytes);
        model.Skeleton.LoadFile(model.SkelFileID == 0 ? dataBytes : skelBytes, model.SkelFileID);
        return(model);
    }
Beispiel #2
0
    public override void OnImportAsset(UnityEditor.AssetImporters.AssetImportContext ctx)
    {
        //Load file contents
        M2 file = new M2();

        file.LoadFile(ctx.assetPath);
        //Prepare blank asset
        GameObject model = new GameObject();

        model.AddComponent <Animator>();
        model.AddComponent <SkinnedMeshRenderer>();
        SkinnedMeshRenderer renderer = model.GetComponent <SkinnedMeshRenderer>();
        Mesh mesh = new Mesh();

        mesh.name = file.Name + "_mesh";
        //Fill vertex data
        Vector3[]    vertices = new Vector3[file.Vertices.Length];
        Vector3[]    normals  = new Vector3[file.Vertices.Length];
        BoneWeight[] weights  = new BoneWeight[file.Vertices.Length];
        Vector2[]    uv       = new Vector2[file.Vertices.Length];
        Vector2[]    uv2      = new Vector2[file.Vertices.Length];
        for (int i = 0; i < file.Vertices.Length; i++)
        {
            vertices[i] = new Vector3(-file.Vertices[i].Position.X / 2, file.Vertices[i].Position.Z / 2, -file.Vertices[i].Position.Y / 2);
            normals[i]  = new Vector3(-file.Vertices[i].Normal.X, file.Vertices[i].Normal.Z, -file.Vertices[i].Normal.Y);
            BoneWeight weight = new BoneWeight
            {
                boneIndex0 = file.Vertices[i].Bones[0],
                boneIndex1 = file.Vertices[i].Bones[1],
                boneIndex2 = file.Vertices[i].Bones[2],
                boneIndex3 = file.Vertices[i].Bones[3],
                weight0    = file.Vertices[i].Weights[0] / 255f,
                weight1    = file.Vertices[i].Weights[1] / 255f,
                weight2    = file.Vertices[i].Weights[2] / 255f,
                weight3    = file.Vertices[i].Weights[3] / 255f
            };
            weights[i] = weight;
            uv[i]      = new Vector2(file.Vertices[i].UV[0].X, 1 - file.Vertices[i].UV[0].Y);
            uv2[i]     = new Vector2(file.Vertices[i].UV[1].X, 1 - file.Vertices[i].UV[1].Y);
        }
        mesh.vertices    = vertices;
        mesh.normals     = normals;
        mesh.boneWeights = weights;
        mesh.uv          = uv;
        mesh.uv2         = uv2;
        //Fill Submesh data
        mesh.subMeshCount = file.Skin.Submeshes.Length;
        for (int i = 0; i < mesh.subMeshCount; i++)
        {
            int[] triangles = new int[file.Skin.Submeshes[i].Count];
            for (int j = 0; j < triangles.Length; j++)
            {
                triangles[j] = file.Skin.Indices[file.Skin.Submeshes[i].Start + j];
            }
            mesh.SetTriangles(triangles, i);
        }
        //Generate bones
        Transform[] bones = new Transform[file.Skeleton.Bones.Length];
        for (int i = 0; i < bones.Length; i++)
        {
            bones[i]          = new GameObject("Bone" + i).transform;
            bones[i].position = new Vector3(-file.Skeleton.Bones[i].Pivot.X / 2, file.Skeleton.Bones[i].Pivot.Z / 2, -file.Skeleton.Bones[i].Pivot.Y / 2);
        }
        GameObject skeleton = new GameObject("Skeleton");

        for (int i = 0; i < bones.Length; i++)
        {
            if (file.Skeleton.Bones[i].Parent == -1)
            {
                bones[i].parent = skeleton.transform;
            }
            else
            {
                bones[i].parent = bones[file.Skeleton.Bones[i].Parent];
            }
        }
        Matrix4x4[] bind = new Matrix4x4[bones.Length];
        for (int i = 0; i < bones.Length; i++)
        {
            bind[i] = bones[i].worldToLocalMatrix * model.transform.localToWorldMatrix;
        }
        skeleton.transform.parent = model.transform;
        renderer.materials        = new Material[mesh.subMeshCount];
        renderer.sharedMesh       = mesh;
        renderer.bones            = bones;
        renderer.rootBone         = bones[0];
        mesh.bindposes            = bind;
        //Seralize data in json so they can be accessible at runtime
        TextAsset json = new TextAsset(JsonConvert.SerializeObject(file));

        json.name = file.Name + "_data";
        model.AddComponent <M2Model>();
        model.GetComponent <M2Model>().json = json;
        //Fill particle effect data
        if (file.Particles.Length > 0)
        {
            GameObject[] particles = new GameObject[file.Particles.Length];
            for (int i = 0; i < particles.Length; i++)
            {
                particles[i] = ParticleEffect(file.Particles[i]);
                particles[i].transform.parent        = bones[file.Particles[i].Bone];
                particles[i].transform.localPosition = Vector3.zero;
                particles[i].name = "Particle" + i;
                ctx.AddObjectToAsset(particles[i].name, particles[i]);
            }
        }
        //Populate the asset
        ctx.AddObjectToAsset(file.Name, model);
        ctx.AddObjectToAsset(mesh.name, mesh);
        ctx.AddObjectToAsset(skeleton.name, skeleton);
        ctx.AddObjectToAsset(json.name, json);
    }
    public override void OnImportAsset(AssetImportContext ctx)
    {
        //Load file contents
        BoneLib.Bone file = new BoneLib.Bone();
        file.LoadFile(ctx.assetPath);
        //Load skel file for reference
        M2 model = new M2();

        model.LoadFile(ctx.assetPath.Substring(0, ctx.assetPath.Length - 8) + ".m2");
        Skel skeleton = model.Skeleton;
        //Create empty animation clip
        AnimationClip  clip = new AnimationClip();
        AnimationCurve curve;
        Matrix4x4      matrix;

        Vector4[] columns = new Vector4[4];
        float     value;

        //Generate temporary bones
        Transform[] bones = new Transform[skeleton.Bones.Length];
        for (int i = 0; i < bones.Length; i++)
        {
            bones[i]          = new GameObject("Bone" + i).transform;
            bones[i].position = new Vector3(-skeleton.Bones[i].Pivot.X / 2, skeleton.Bones[i].Pivot.Z / 2, -skeleton.Bones[i].Pivot.Y / 2);
        }
        GameObject rig = new GameObject("Skeleton");

        for (int i = 0; i < bones.Length; i++)
        {
            if (skeleton.Bones[i].Parent == -1)
            {
                bones[i].parent = rig.transform;
            }
            else
            {
                bones[i].parent = bones[skeleton.Bones[i].Parent];
            }
        }
        //Fill animation data for each bone
        for (int i = 0; i < file.Bones.Length; i++)
        {
            string path = GetBonePath(skeleton.Bones[file.Bones[i]].Parent, skeleton.Bones) + "Bone" + file.Bones[i];
            for (int j = 0; j < 4; j++)
            {
                columns[j] = new Vector4(file.Transformations[i][j][0], file.Transformations[i][j][1], file.Transformations[i][j][2], file.Transformations[i][j][3]);
            }
            matrix = new Matrix4x4(columns[0], columns[1], columns[2], columns[3]);
            value  = -matrix.m03 / 2 + bones[file.Bones[i]].localPosition.x;
            curve  = AnimationCurve.Linear(0f, value, 0.1f, value);
            clip.SetCurve(path, typeof(Transform), "localPosition.x", curve);
            value = matrix.m23 / 2 + bones[file.Bones[i]].localPosition.y;
            curve = AnimationCurve.Linear(0f, value, 0.1f, value);
            clip.SetCurve(path, typeof(Transform), "localPosition.y", curve);
            value = -matrix.m13 / 2 + bones[file.Bones[i]].localPosition.z;
            curve = AnimationCurve.Linear(0f, value, 0.1f, value);
            clip.SetCurve(path, typeof(Transform), "localPosition.z", curve);
            UnityEngine.Quaternion rotation = matrix.rotation;
            curve = AnimationCurve.Linear(0f, -rotation.x, 1f, rotation.x);
            clip.SetCurve(path, typeof(Transform), "localRotation.x", curve);
            curve = AnimationCurve.Linear(0f, -rotation.z, 0.1f, rotation.z);
            clip.SetCurve(path, typeof(Transform), "localRotation.y", curve);
            curve = AnimationCurve.Linear(0f, rotation.y, 0.1f, rotation.y);
            clip.SetCurve(path, typeof(Transform), "localRotation.z", curve);
            curve = AnimationCurve.Linear(0f, rotation.w, 0.1f, rotation.w);
            clip.SetCurve(path, typeof(Transform), "localRotation.w", curve);
            Vector3 scale = matrix.lossyScale;
            curve = AnimationCurve.Linear(0f, scale.x, 0.1f, scale.x);
            clip.SetCurve(path, typeof(Transform), "localScale.x", curve);
            curve = AnimationCurve.Linear(0f, scale.z, 0.1f, scale.z);
            clip.SetCurve(path, typeof(Transform), "localScale.y", curve);
            curve = AnimationCurve.Linear(0f, scale.y, 0.1f, scale.y);
            clip.SetCurve(path, typeof(Transform), "localScale.z", curve);
        }
        //Clear temporary bones and add animation clip to the asset
        DestroyImmediate(rig);
        ctx.AddObjectToAsset(Path.GetFileNameWithoutExtension(ctx.assetPath.Replace("/", "\\")), clip);
    }
    public override void OnImportAsset(AssetImportContext ctx)
    {
        //Load file contents
        M2 file = new M2();

        file.LoadFile(ctx.assetPath);
        //Prepare blank asset
        GameObject model = new GameObject();

        model.AddComponent <Animator>();
        model.AddComponent <SkinnedMeshRenderer>();
        SkinnedMeshRenderer renderer = model.GetComponent <SkinnedMeshRenderer>();
        Mesh mesh = new Mesh();

        mesh.name = file.Name + "_mesh";
        //Fill vertex data
        Vector3[]    vertices = new Vector3[file.Vertices.Length];
        Vector3[]    normals  = new Vector3[file.Vertices.Length];
        BoneWeight[] weights  = new BoneWeight[file.Vertices.Length];
        Vector2[]    uv       = new Vector2[file.Vertices.Length];
        Vector2[]    uv2      = new Vector2[file.Vertices.Length];
        for (int i = 0; i < file.Vertices.Length; i++)
        {
            vertices[i] = new Vector3(-file.Vertices[i].Position.X / 2, file.Vertices[i].Position.Z / 2, -file.Vertices[i].Position.Y / 2);
            normals[i]  = new Vector3(-file.Vertices[i].Normal.X, file.Vertices[i].Normal.Z, -file.Vertices[i].Normal.Y);
            BoneWeight weight = new BoneWeight
            {
                boneIndex0 = file.Vertices[i].Bones[0],
                boneIndex1 = file.Vertices[i].Bones[1],
                boneIndex2 = file.Vertices[i].Bones[2],
                boneIndex3 = file.Vertices[i].Bones[3],
                weight0    = file.Vertices[i].Weights[0] / 255f,
                weight1    = file.Vertices[i].Weights[1] / 255f,
                weight2    = file.Vertices[i].Weights[2] / 255f,
                weight3    = file.Vertices[i].Weights[3] / 255f
            };
            weights[i] = weight;
            uv[i]      = new Vector2(file.Vertices[i].UV[0].X, 1 - file.Vertices[i].UV[0].Y);
            uv2[i]     = new Vector2(file.Vertices[i].UV[1].X, 1 - file.Vertices[i].UV[1].Y);
        }
        mesh.vertices    = vertices;
        mesh.normals     = normals;
        mesh.boneWeights = weights;
        mesh.uv          = uv;
        mesh.uv2         = uv2;
        //Fill Submesh data
        mesh.subMeshCount = file.Skin.Submeshes.Length;
        for (int i = 0; i < mesh.subMeshCount; i++)
        {
            int[] triangles = new int[file.Skin.Submeshes[i].Count];
            for (int j = 0; j < triangles.Length; j++)
            {
                triangles[j] = file.Skin.Indices[file.Skin.Submeshes[i].Start + j];
            }
            mesh.SetTriangles(triangles, i);
        }
        //Generate bones
        Transform[] bones = new Transform[file.Skeleton.Bones.Length];
        for (int i = 0; i < bones.Length; i++)
        {
            bones[i]          = new GameObject("Bone" + i).transform;
            bones[i].position = new Vector3(-file.Skeleton.Bones[i].Pivot.X / 2, file.Skeleton.Bones[i].Pivot.Z / 2, -file.Skeleton.Bones[i].Pivot.Y / 2);
        }
        GameObject skeleton = new GameObject("Skeleton");

        for (int i = 0; i < bones.Length; i++)
        {
            if (file.Skeleton.Bones[i].Parent == -1)
            {
                bones[i].parent = skeleton.transform;
            }
            else
            {
                bones[i].parent = bones[file.Skeleton.Bones[i].Parent];
            }
        }
        //Add Attachment points
        if (character)
        {
            AddAttachmentPoint(shield, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[0]].Bone]);
            AddAttachmentPoint(handRight, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[1]].Bone]);
            AddAttachmentPoint(handLeft, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[2]].Bone]);
            AddAttachmentPoint(shoulderRight, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[5]].Bone]);
            AddAttachmentPoint(shoulderLeft, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[6]].Bone]);
            AddAttachmentPoint(helm, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[11]].Bone]);
            AddAttachmentPoint(quiver, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[26]].Bone]);
            AddAttachmentPoint(buckle, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[53]].Bone]);;
            AddAttachmentPoint(book, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[53]].Bone]);
            AddAttachmentPoint(backpack, bones[file.Skeleton.Attachments[file.Skeleton.AttachmentLookup[57]].Bone]);
        }
        Matrix4x4[] bind = new Matrix4x4[bones.Length];
        for (int i = 0; i < bones.Length; i++)
        {
            bind[i] = bones[i].worldToLocalMatrix * model.transform.localToWorldMatrix;
        }
        skeleton.transform.parent = model.transform;
        renderer.materials        = new Material[mesh.subMeshCount];
        renderer.sharedMesh       = mesh;
        renderer.bones            = bones;
        renderer.rootBone         = bones[0];
        mesh.bindposes            = bind;
        //Load *.bytes files so data can be easly accessible at runtime
        string    path = Path.GetDirectoryName(ctx.assetPath);
        TextAsset data = AssetDatabase.LoadAssetAtPath <TextAsset>(path + "\\data.bytes");
        TextAsset skin = AssetDatabase.LoadAssetAtPath <TextAsset>(path + "\\skin.bytes");
        TextAsset skel = new TextAsset("");

        skel.name = "skel";
        if (file.SkelFileID != 0)
        {
            skel = AssetDatabase.LoadAssetAtPath <TextAsset>(path + "\\skel.bytes");
        }
        M2Model m2 = model.AddComponent <M2Model>();

        m2.data = data;
        m2.skin = skin;
        m2.skel = skel;
        //Populate the asset
        ctx.AddObjectToAsset(file.Name, model);
        ctx.AddObjectToAsset(mesh.name, mesh);
        ctx.AddObjectToAsset(skeleton.name, skeleton);
        ctx.AddObjectToAsset(data.name, data);
        ctx.AddObjectToAsset(skin.name, skin);
        ctx.AddObjectToAsset(skel.name, skel);
    }
    //Load the model from CASC
    public IEnumerator LoadModel(int file, int texture, CASCHandler casc)
    {
        File = file;
        if (file != 0)
        {
            Texture   = texture;
            this.casc = casc;
            converter = new System.Drawing.ImageConverter();
            byte[] bytes;
            yield return(null);

            using (BinaryReader reader = new BinaryReader(casc.OpenFile(file)))
            {
                bytes = reader.ReadBytes((int)reader.BaseStream.Length);
            }
            yield return(null);

            Model = new M2();
            Model.LoadFile(bytes);
            yield return(null);

            if (Model.SkelFileID != 0)
            {
                using (BinaryReader reader = new BinaryReader(casc.OpenFile(Model.SkelFileID)))
                {
                    bytes = reader.ReadBytes((int)reader.BaseStream.Length);
                }
            }
            yield return(null);

            Model.Skeleton.LoadFile(bytes, Model.SkelFileID);
            yield return(null);

            using (BinaryReader reader = new BinaryReader(casc.OpenFile(Model.SkinFileID)))
            {
                bytes = reader.ReadBytes((int)reader.BaseStream.Length);
            }
            yield return(null);

            Model.Skin.LoadFile(bytes);
            yield return(null);

            //Array.Sort(Model.Skin.Textures, (a, b) => Model.Materials[a.Material].Blend.CompareTo(Model.Materials[b.Material].Blend));
            LoadColors();
            yield return(null);

            textures = new Texture2D[Model.Textures.Length];
            mesh     = WoWHelper.Generate3DMesh(Model);
            mesh.transform.parent           = GetComponent <Transform>();
            mesh.transform.localPosition    = Vector3.zero;
            mesh.transform.localEulerAngles = Vector3.zero;
            mesh.transform.localScale       = Vector3.one;
            renderer = GetComponentInChildren <SkinnedMeshRenderer>();
            yield return(null);

            Transform[] bones = GetComponentInChildren <SkinnedMeshRenderer>().bones;
            if (Model.Particles.Length > 0)
            {
                GameObject[] particles = new GameObject[Model.Particles.Length];
                for (int i = 0; i < particles.Length; i++)
                {
                    particles[i] = WoWHelper.ParticleEffect(Model.Particles[i]);
                    particles[i].transform.parent        = bones[Model.Particles[i].Bone];
                    particles[i].transform.localPosition = Vector3.zero;
                    particles[i].name = $"Particle{i}";
                    yield return(null);
                }
            }
            if (character.Form == 7)
            {
                MatchBones(gilnean);
            }
            else
            {
                MatchBones(character);
            }
            time  = new float[Model.TextureAnimations.Length];
            frame = new int[Model.TextureAnimations.Length];
            for (int i = 0; i < time.Length; i++)
            {
                time[i]  = 0f;
                frame[i] = 0;
                yield return(null);
            }
            Loaded = true;
            Change = true;
        }
    }