Example #1
0
        private static bool ReadData(BinaryReader file, ref ANMFile data, Logger logger)
        {
            bool result = true;

            try
            {
                // File Header Information.
                data.id = new String(file.ReadChars(ANMFile.ID_SIZE));
                data.version = file.ReadUInt32();

                // Version 0, 1, 2, 3 Code
                if (data.version == 0 ||
                    data.version == 1 ||
                    data.version == 2 ||
                    data.version == 3)
                {
                    //
                    // Header information specific to these versions.
                    //

                    data.magic = file.ReadUInt32();
                    data.numberOfBones = file.ReadUInt32();
                    data.numberOfFrames = file.ReadUInt32();
                    data.playbackFPS = file.ReadUInt32();

                    // Read in all the bones
                    for (UInt32 i = 0; i < data.numberOfBones; ++i)
                    {
                        ANMBone bone = new ANMBone();
                        bone.name = new String(file.ReadChars(ANMBone.BONE_NAME_LENGTH));
                        bone.name = RemoveAnimationNamePadding(bone.name);
                        bone.name = bone.name.ToLower();

                        // Unknown
                        file.ReadUInt32();

                        // For each bone, read in its value at each frame in the animation.
                        for (UInt32 j = 0; j < data.numberOfFrames; ++j)
                        {
                            ANMFrame frame = new ANMFrame();

                            // Read in the frame's quaternion.
                            frame.orientation[0] = file.ReadSingle(); // x
                            frame.orientation[1] = file.ReadSingle(); // y
                            frame.orientation[2] = file.ReadSingle(); // z
                            frame.orientation[3] = file.ReadSingle(); // w

                            // Read in the frame's position.
                            frame.position[0] = file.ReadSingle(); // x
                            frame.position[1] = file.ReadSingle(); // y
                            frame.position[2] = file.ReadSingle(); // z

                            bone.frames.Add(frame);
                        }

                        data.bones.Add(bone);
                    }
                }
                // Version 4 Code
                else if (data.version == 4)
                {
                    //
                    // Based on the reverse engineering work of Hossein Ahmadi.
                    //
                    // In this version, position vectors and orientation quaternions are
                    // stored separately in sorted, keyed blocks.  The assumption is Riot
                    // is removing duplicate vectors and quaternions by using an indexing scheme
                    // to look up values.
                    //
                    // So, after the header, there are three data sections: a vector section, a quaternion
                    // section, and a look up section.  The number of vectors and quaternions
                    // may not match the expected value based on the number of frames and bones.  However,
                    // the number of look ups should match this value and can be used to create the animation.

                    //
                    // Header information specific to version 4.
                    //

                    data.magic = file.ReadUInt32();

                    // Not sure what any of these mean.
                    float unknown = file.ReadSingle();
                    unknown = file.ReadSingle();
                    unknown = file.ReadSingle();

                    data.numberOfBones = file.ReadUInt32();
                    data.numberOfFrames = file.ReadUInt32();

                    // Time per frame is stored in this file type.  Need to invert it into FPS.
                    data.playbackFPS = (UInt32) Math.Round(1.0f / file.ReadSingle());

                    // These are offsets to specific data sections in the file.
                    UInt32 unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();

                    UInt32 positionOffset = file.ReadUInt32();
                    UInt32 orientationOffset = file.ReadUInt32();
                    UInt32 indexOffset = file.ReadUInt32();

                    // These last three values are confusing.
                    // They aren't a vector and they throw off the offset values
                    // by 12 bytes. Just ignore them and keep reading.
                    unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();

                    //
                    // Vector section.
                    //

                    List<float> positions = new List<float>();
                    UInt32 numberOfPositions = (orientationOffset - positionOffset) / sizeof(float);
                    for (UInt32 i = 0; i < numberOfPositions; ++i)
                    {
                        positions.Add(file.ReadSingle());
                    }

                    //
                    // Quaternion section.
                    //

                    List<float> orientations = new List<float>();
                    UInt32 numberOfOrientations = (indexOffset - orientationOffset) / sizeof(float);
                    for (UInt32 i = 0; i < numberOfOrientations; ++i)
                    {
                        orientations.Add(file.ReadSingle());
                    }

                    //
                    // Offset section.
                    //
                    // Note: Unlike versions 0-3, data in this version is
                    // Frame 1:
                    //      Bone 1:
                    //      Bone 2:
                    // ...
                    // Frame 2:
                    //      Bone 1:
                    // ...
                    //

                    Dictionary<UInt32, ANMBone> boneMap = new Dictionary<UInt32, ANMBone>();
                    for (Int32 i = 0; i < data.numberOfBones; ++i)
                    {
                        //
                        // The first frame is a special case since we are allocating bones
                        // as we read them in.
                        //

                        // Read in the offset data.
                        UInt32 boneID = file.ReadUInt32();
                        UInt16 positionID = file.ReadUInt16();
                        UInt16 unknownIndex = file.ReadUInt16(); // Unknown.
                        UInt16 orientationID = file.ReadUInt16();
                        unknownIndex = file.ReadUInt16(); // Unknown. Seems to always be zero.

                        // Allocate the bone.
                        ANMBone bone = new ANMBone();
                        bone.id = boneID;

                        // Allocate all the frames for the bone.
                        for (int j = 0; j < data.numberOfFrames; ++j)
                        {
                            bone.frames.Add(new ANMFrame());
                        }

                        // Retrieve the data for the first frame.
                        ANMFrame frame = bone.frames[0];
                        frame.position = LookUpVector(positionID, positions);
                        frame.orientation = LookUpQuaternion(orientationID, orientations);

                        // Store the bone in the dictionary by bone ID.
                        boneMap[boneID] = bone;
                    }

                    Int32 currentFrame = 1;
                    Int32 currentBone = 0;

                    UInt32 numberOfLookUps = (data.numberOfFrames - 1) * data.numberOfBones;
                    for (UInt32 i = 0; i < numberOfLookUps; ++i)
                    {
                        //
                        // Normal case for all frames after the first.
                        //

                        // Read in the offset data.

                        UInt32 boneID = file.ReadUInt32();
                        UInt16 positionID = file.ReadUInt16();
                        UInt16 unknownIndex = file.ReadUInt16(); // Unknown.
                        UInt16 orientationID = file.ReadUInt16();
                        unknownIndex = file.ReadUInt16(); // Unknown. Seems to always be zero.

                        // Retrieve the bone from the dictionary.
                        // Note: The bones appear to be in the same order in every frame.  So, a dictionary
                        // isn't exactly needed and you could probably get away with a list.  However, this way
                        // feels safer just in case something ends up being out of order.
                        ANMBone bone = boneMap[boneID];
                        ANMFrame frame = bone.frames[currentFrame];
                        frame.position = LookUpVector(positionID, positions);
                        frame.orientation = LookUpQuaternion(orientationID, orientations);

                        // This loop is slightly ambiguous.
                        //
                        // The problem is previous .anm versions contain data like:
                        // foreach bone
                        //      foreach frame
                        //
                        // However, this version contains data like:
                        // foreach frame
                        //      foreach bone
                        //
                        // So, reading one version is going to be a little goofy.
                        currentBone++;
                        if (currentBone >= data.numberOfBones)
                        {
                            currentBone = 0;
                            currentFrame++;
                        }
                    }

                    // Finally, we need to move all the data from the dictionary into the ANMFile.
                    foreach(var bone in boneMap)
                    {
                        data.bones.Add(bone.Value);
                    }

                    // Currently returning false for this version.  We can not render this version correctly yet.
                    // So, we need to tell the viewer not to try and load it.
                    result = false;
                }
                // Unknown version
                else
                {
                    logger.Error("Unknown anm version: " + data.version);
                    result = false;
                }
            }
            catch(Exception e)
            {
                logger.Error("Anm reading error.");
                logger.Error(e.Message);
                result = false;
            }

            logger.Event("File ID: " + data.id);
            logger.Event("Magic: " + data.magic);
            logger.Event("Version: " + data.version);
            logger.Event("Number of Bones: " + data.numberOfBones);
            logger.Event("Number of Frames: " + data.numberOfFrames);
            logger.Event("Playback FPS: " + data.playbackFPS);

            return result;
        }
Example #2
0
        private static bool ReadData(BinaryReader file, ref ANMFile data, Logger logger)
        {
            bool result = true;

            try
            {
                // File Header Information.
                data.id      = new String(file.ReadChars(ANMFile.ID_SIZE));
                data.version = file.ReadUInt32();

                // Version 0, 1, 2, 3 Code
                if (data.version == 0 ||
                    data.version == 1 ||
                    data.version == 2 ||
                    data.version == 3)
                {
                    //
                    // Header information specific to these versions.
                    //

                    data.magic          = file.ReadUInt32();
                    data.numberOfBones  = file.ReadUInt32();
                    data.numberOfFrames = file.ReadUInt32();
                    data.playbackFPS    = file.ReadUInt32();

                    // Read in all the bones
                    for (UInt32 i = 0; i < data.numberOfBones; ++i)
                    {
                        ANMBone bone = new ANMBone();
                        bone.name = new String(file.ReadChars(ANMBone.BONE_NAME_LENGTH));
                        bone.name = RemoveAnimationNamePadding(bone.name);
                        bone.name = bone.name.ToLower();

                        // Unknown
                        file.ReadUInt32();

                        // For each bone, read in its value at each frame in the animation.
                        for (UInt32 j = 0; j < data.numberOfFrames; ++j)
                        {
                            ANMFrame frame = new ANMFrame();

                            // Read in the frame's quaternion.
                            frame.orientation[0] = file.ReadSingle(); // x
                            frame.orientation[1] = file.ReadSingle(); // y
                            frame.orientation[2] = file.ReadSingle(); // z
                            frame.orientation[3] = file.ReadSingle(); // w

                            // Read in the frame's position.
                            frame.position[0] = file.ReadSingle(); // x
                            frame.position[1] = file.ReadSingle(); // y
                            frame.position[2] = file.ReadSingle(); // z

                            bone.frames.Add(frame);
                        }

                        data.bones.Add(bone);
                    }
                }
                // Version 4 Code
                else if (data.version == 4)
                {
                    //
                    // Based on the reverse engineering work of Hossein Ahmadi.
                    //
                    // In this version, position vectors and orientation quaternions are
                    // stored separately in sorted, keyed blocks.  The assumption is Riot
                    // is removing duplicate vectors and quaternions by using an indexing scheme
                    // to look up values.
                    //
                    // So, after the header, there are three data sections: a vector section, a quaternion
                    // section, and a look up section.  The number of vectors and quaternions
                    // may not match the expected value based on the number of frames and bones.  However,
                    // the number of look ups should match this value and can be used to create the animation.

                    //
                    // Header information specific to version 4.
                    //

                    data.magic = file.ReadUInt32();

                    // Not sure what any of these mean.
                    float unknown = file.ReadSingle();
                    unknown = file.ReadSingle();
                    unknown = file.ReadSingle();

                    data.numberOfBones  = file.ReadUInt32();
                    data.numberOfFrames = file.ReadUInt32();

                    // Time per frame is stored in this file type.  Need to invert it into FPS.
                    data.playbackFPS = (UInt32)Math.Round(1.0f / file.ReadSingle());

                    // These are offsets to specific data sections in the file.
                    UInt32 unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();

                    UInt32 positionOffset    = file.ReadUInt32();
                    UInt32 orientationOffset = file.ReadUInt32();
                    UInt32 indexOffset       = file.ReadUInt32();

                    // These last three values are confusing.
                    // They aren't a vector and they throw off the offset values
                    // by 12 bytes. Just ignore them and keep reading.
                    unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();
                    unknownOffset = file.ReadUInt32();

                    //
                    // Vector section.
                    //

                    List <float> positions         = new List <float>();
                    UInt32       numberOfPositions = (orientationOffset - positionOffset) / sizeof(float);
                    for (UInt32 i = 0; i < numberOfPositions; ++i)
                    {
                        positions.Add(file.ReadSingle());
                    }

                    //
                    // Quaternion section.
                    //

                    List <float> orientations         = new List <float>();
                    UInt32       numberOfOrientations = (indexOffset - orientationOffset) / sizeof(float);
                    for (UInt32 i = 0; i < numberOfOrientations; ++i)
                    {
                        orientations.Add(file.ReadSingle());
                    }

                    //
                    // Offset section.
                    //
                    // Note: Unlike versions 0-3, data in this version is
                    // Frame 1:
                    //      Bone 1:
                    //      Bone 2:
                    // ...
                    // Frame 2:
                    //      Bone 1:
                    // ...
                    //

                    Dictionary <UInt32, ANMBone> boneMap = new Dictionary <UInt32, ANMBone>();
                    for (Int32 i = 0; i < data.numberOfBones; ++i)
                    {
                        //
                        // The first frame is a special case since we are allocating bones
                        // as we read them in.
                        //

                        // Read in the offset data.
                        UInt32 boneID        = file.ReadUInt32();
                        UInt16 positionID    = file.ReadUInt16();
                        UInt16 unknownIndex  = file.ReadUInt16(); // Unknown.
                        UInt16 orientationID = file.ReadUInt16();
                        unknownIndex = file.ReadUInt16();         // Unknown. Seems to always be zero.

                        // Allocate the bone.
                        ANMBone bone = new ANMBone();
                        bone.id = boneID;

                        // Allocate all the frames for the bone.
                        for (int j = 0; j < data.numberOfFrames; ++j)
                        {
                            bone.frames.Add(new ANMFrame());
                        }

                        // Retrieve the data for the first frame.
                        ANMFrame frame = bone.frames[0];
                        frame.position    = LookUpVector(positionID, positions);
                        frame.orientation = LookUpQuaternion(orientationID, orientations);

                        // Store the bone in the dictionary by bone ID.
                        boneMap[boneID] = bone;
                    }

                    Int32 currentFrame = 1;
                    Int32 currentBone  = 0;

                    UInt32 numberOfLookUps = (data.numberOfFrames - 1) * data.numberOfBones;
                    for (UInt32 i = 0; i < numberOfLookUps; ++i)
                    {
                        //
                        // Normal case for all frames after the first.
                        //

                        // Read in the offset data.

                        UInt32 boneID        = file.ReadUInt32();
                        UInt16 positionID    = file.ReadUInt16();
                        UInt16 unknownIndex  = file.ReadUInt16(); // Unknown.
                        UInt16 orientationID = file.ReadUInt16();
                        unknownIndex = file.ReadUInt16();         // Unknown. Seems to always be zero.

                        // Retrieve the bone from the dictionary.
                        // Note: The bones appear to be in the same order in every frame.  So, a dictionary
                        // isn't exactly needed and you could probably get away with a list.  However, this way
                        // feels safer just in case something ends up being out of order.
                        ANMBone  bone  = boneMap[boneID];
                        ANMFrame frame = bone.frames[currentFrame];
                        frame.position    = LookUpVector(positionID, positions);
                        frame.orientation = LookUpQuaternion(orientationID, orientations);

                        // This loop is slightly ambiguous.
                        //
                        // The problem is previous .anm versions contain data like:
                        // foreach bone
                        //      foreach frame
                        //
                        // However, this version contains data like:
                        // foreach frame
                        //      foreach bone
                        //
                        // So, reading one version is going to be a little goofy.
                        currentBone++;
                        if (currentBone >= data.numberOfBones)
                        {
                            currentBone = 0;
                            currentFrame++;
                        }
                    }

                    // Finally, we need to move all the data from the dictionary into the ANMFile.
                    foreach (var bone in boneMap)
                    {
                        data.bones.Add(bone.Value);
                    }

                    // Currently returning false for this version.  We can not render this version correctly yet.
                    // So, we need to tell the viewer not to try and load it.
                    result = false;
                }
                // Unknown version
                else
                {
                    logger.Error("Unknown anm version: " + data.version);

                    result = false;
                }
            }
            catch (Exception e)
            {
                logger.Error("Anm reading error.");
                logger.Error(e.Message);
                result = false;
            }

            logger.Event("File ID: " + data.id);
            logger.Event("Magic: " + data.magic);
            logger.Event("Version: " + data.version);
            logger.Event("Number of Bones: " + data.numberOfBones);
            logger.Event("Number of Frames: " + data.numberOfFrames);
            logger.Event("Playback FPS: " + data.playbackFPS);

            return(result);
        }