예제 #1
0
        public Animation(Stream animStream, bool leaveOpen = true, bool alwaysAddBones = false)
        {
            Animations = new List <Keyframe>();
            // Convert OW Animation to our Animation Type
            using (BinaryReader animReader = new BinaryReader(animStream, Encoding.Default, leaveOpen)) {
                Header = animReader.Read <AnimHeader>();

                Duration        = Header.duration;
                FramesPerSecond = Header.fps;
                InfoTableSize   = (int)(Header.fps * Header.duration) + 1;
                ushort bonecount = Header.bonecount;

                animStream.Seek((long)Header.boneListOffset, SeekOrigin.Begin);
                for (uint i = 0; i < Header.bonecount; i++)
                {
                    int boneID = animReader.ReadInt32();
                    BoneList.Add(boneID);
                }

                Vec3d[,] ScaleValues    = new Vec3d[bonecount, InfoTableSize];
                Vec3d[,] PositionValues = new Vec3d[bonecount, InfoTableSize];
                Vec4d[,] RotationValues = new Vec4d[bonecount, InfoTableSize];
                bool[,] hasScale        = new bool[bonecount, InfoTableSize];
                bool[,] hasPosition     = new bool[bonecount, InfoTableSize];
                bool[,] hasRotation     = new bool[bonecount, InfoTableSize];

                animStream.Seek((long)Header.infoTableOffset, SeekOrigin.Begin);
                for (int boneid = 0; boneid < Header.bonecount; boneid++)
                {
                    long          animStreamPos = animStream.Position;
                    AnimInfoTable it            = animReader.Read <AnimInfoTable>();
                    long          SIO           = (long)it.ScaleIndicesOffset * 4 + animStreamPos;
                    long          PIO           = (long)it.PositionIndicesOffset * 4 + animStreamPos;
                    long          RIO           = (long)it.RotationIndicesOffset * 4 + animStreamPos;
                    long          SDO           = (long)it.ScaleDataOffset * 4 + animStreamPos;
                    long          PDO           = (long)it.PositionDataOffset * 4 + animStreamPos;
                    long          RDO           = (long)it.RotationDataOffset * 4 + animStreamPos;
                    InfoTables.Add(it);

                    // Read Indices
                    List <int> ScaleIndexList = new List <int>();
                    animStream.Seek(SIO, SeekOrigin.Begin);
                    for (int j = 0; j < it.ScaleCount; j++)
                    {
                        if (InfoTableSize <= 255)
                        {
                            ScaleIndexList.Add((int)animReader.ReadByte());
                        }
                        else
                        {
                            ScaleIndexList.Add((int)animReader.ReadInt16());
                        }
                    }
                    List <int> PositonIndexList = new List <int>();
                    animStream.Seek(PIO, SeekOrigin.Begin);
                    for (int j = 0; j < it.PositionCount; j++)
                    {
                        if (InfoTableSize <= 255)
                        {
                            PositonIndexList.Add((int)animReader.ReadByte());
                        }
                        else
                        {
                            PositonIndexList.Add((int)animReader.ReadInt16());
                        }
                    }
                    List <int> RotationIndexList = new List <int>();
                    animStream.Seek(RIO, SeekOrigin.Begin);
                    for (int j = 0; j < it.RotationCount; j++)
                    {
                        if (InfoTableSize <= 255)
                        {
                            RotationIndexList.Add((int)animReader.ReadByte());
                        }
                        else
                        {
                            RotationIndexList.Add((int)animReader.ReadInt16());
                        }
                    }
                    // Read Data
                    animStream.Seek(SDO, SeekOrigin.Begin);
                    for (int j = 0; j < it.ScaleCount; j++)
                    {
                        int Index = Math.Abs(ScaleIndexList[j]) % InfoTableSize;
                        hasScale[boneid, Index] = true;
                        ushort x = animReader.ReadUInt16();
                        ushort y = animReader.ReadUInt16();
                        ushort z = animReader.ReadUInt16();

                        Vec3d values = UnpackScale(x, y, z);
                        ScaleValues[boneid, Index] = values;
                    }
                    animStream.Seek(PDO, SeekOrigin.Begin);
                    for (int j = 0; j < it.PositionCount; j++)
                    {
                        int Index = Math.Abs(PositonIndexList[j]) % InfoTableSize;
                        hasPosition[boneid, Index] = true;
                        float x = animReader.ReadSingle();
                        float y = animReader.ReadSingle();
                        float z = animReader.ReadSingle();

                        Vec3d values = new Vec3d(x, y, z);
                        PositionValues[boneid, Index] = values;
                    }
                    animStream.Seek(RDO, SeekOrigin.Begin);
                    for (int j = 0; j < it.RotationCount; j++)
                    {
                        int    Index = Math.Abs(RotationIndexList[j]) % InfoTableSize;
                        ushort x     = animReader.ReadUInt16();
                        ushort y     = animReader.ReadUInt16();
                        ushort z     = animReader.ReadUInt16();

                        Vec4d values = UnpackRotation(x, y, z);
                        hasRotation[boneid, Index]    = true;
                        RotationValues[boneid, Index] = values;
                    }
                    animStream.Seek(animStreamPos + 32L, SeekOrigin.Begin);
                }


                for (int frame = 0; frame < InfoTableSize; frame++)
                {
                    Keyframe kf = new Keyframe();
                    kf.FramePosition  = ((float)frame / FramesPerSecond);
                    kf.FramePositionI = frame;
                    kf.BoneFrames     = new List <BoneAnimation>();
                    for (int bone = 0; bone < Header.bonecount; bone++)
                    {
                        // Build Value Data
                        BoneAnimation ba = new BoneAnimation();
                        ba.BoneID = BoneList[bone];
                        ba.Values = new List <FrameValue>();

                        if (hasScale[bone, frame])
                        {
                            Vec3d      v  = ScaleValues[bone, frame];
                            FrameValue fv = new FrameValue(AnimChannelID.SCALE, v);
                            ba.Values.Add(fv);
                        }
                        if (hasPosition[bone, frame])
                        {
                            Vec3d      v = PositionValues[bone, frame];
                            FrameValue f = new FrameValue(AnimChannelID.POSITION, v);
                            ba.Values.Add(f);
                        }
                        if (hasRotation[bone, frame])
                        {
                            Vec4d      v = RotationValues[bone, frame];
                            FrameValue f = new FrameValue(AnimChannelID.ROTATION, v);
                            ba.Values.Add(f);
                        }
                        if (ba.Values.Count > 0 || alwaysAddBones)
                        {
                            kf.BoneFrames.Add(ba);
                        }
                    }
                    if (kf.BoneFrames.Count > 0)
                    {
                        Animations.Add(kf);
                    }
                }
            }
        }
예제 #2
0
        /**
         * Add the result of a throw to this frame; if added, null is returned (no new frame is needed):
         * if we were already at the bottom of the frame, a new frame is created and returned with the throw added.
         */
        public Frame addThrow(FrameValue f)
        {
            Frame toReturn = null;

            // First, ensure the throw is valid; a spare cannot be at the top of the frame, or follow a
            // strike/spare in the 10th frame.

            // Similarly, a Strike can only occur as top, or following a Strike / Spare in the tenth frame
            if (f == FrameValue.Spare)
            {
                if (top == null || (frameNumber == 10 && (top == FrameValue.Strike && bottom == null || bottom == FrameValue.Strike)))
                {
                    throw new InvalidThrowException("Cannot add a spare at the top of a frame.");
                }
            }
            else if (f == FrameValue.Strike)
            {
                if (
                    (frameNumber == 10 &&
                     (top != FrameValue.Strike && top != null &&
                      (bottom == null ||
                       bottom != FrameValue.Spare)
                     )
                    ) || frameNumber != 10 && top != null && top != FrameValue.Strike && bottom == null
                    )
                {
                    throw new InvalidThrowException("Cannot add a strike at the bottom half of a frame (unless 10th and following a strike / spare).");
                }
            }
            else if (top != null && top != FrameValue.Strike && bottom == null && (getThrowPins(top) + getThrowPins(f) > 10))
            {
                throw new InvalidThrowException("Cannnot add a second value which causes the frame total to exceed 10.");
            }

            if (top == null)
            {
                top = f;
            }
            else if (bottom == null && (top != FrameValue.Strike || frameNumber == 10))
            {
                if (getThrowPins(top) + getThrowPins(f) == 10)
                {
                    f = FrameValue.Spare;
                }
                bottom = f;
            }
            else if (frameNumber == 10)
            {
                if (tenthBottom == null)
                {
                    tenthBottom = f;
                }
                else
                {
                    throw new ThrowsExceededException("Cannot add more throws to the 10th frame.");
                }
            }
            else
            {
                toReturn = new Frame(this.frameNumber + 1);
                toReturn.addThrow(f);
                setNextFrame(toReturn);
            }
            return(toReturn);
        }