示例#1
0
 internal void Load(string name, float frameRate, int numFrames, AnimationTrackDictionary tracks)
 {
     name_      = name;
     frameRate_ = frameRate;
     numFrames_ = numFrames;
     tracks_    = tracks;
 }
示例#2
0
 public Animation(string name, AnimationTrackDictionary tracks, float frameRate, int durationFrames)
 {
     Load(name, frameRate, durationFrames, tracks);
     if (durationFrames < 0)
     {
         CalcNumFrames();
     }
 }
示例#3
0
        protected override Animation Read(ContentReader input, Animation existingInstance)
        {
            if (existingInstance == null)
            {
                existingInstance = new Animation();
            }
            string name      = input.ReadString();
            float  frameRate = input.ReadSingle();
            int    numFrames = input.ReadInt32();
            AnimationTrackDictionary tracks = input.ReadObject <AnimationTrackDictionary>();

            existingInstance.Load(name, frameRate, numFrames, tracks);
            return(existingInstance);
        }
示例#4
0
        /// <summary>
        /// Given the animation tracks in the dictionary (for an animation with the given
        /// name), figure out what the latest frame is that contains unique data for any
        /// track, and trim the animation from the end to that length.
        /// </summary>
        /// <param name="name">name of the animation to trim</param>
        /// <param name="tracks">the tracks of the animation to trim</param>
        /// <param name="context">for logging etc</param>
        protected virtual void TrimAnimationTracks(string name, AnimationTrackDictionary tracks,
                                                   ContentProcessorContext context)
        {
            int latestUnique = 1;
            int latestFrame  = 0;

            foreach (AnimationTrack at in tracks.Values)
            {
                Keyframe last          = at.Keyframes[0];
                int      latestCurrent = 0;
                int      index         = 0;
                if (at.NumFrames > latestFrame)
                {
                    latestFrame = at.NumFrames;
                }
                foreach (Keyframe kf in at.Keyframes)
                {
                    if (kf != null && last.DifferenceFrom(kf) >= tolerance_)
                    {
                        latestCurrent = index;
                        last          = kf;
                    }
                    ++index;
                }
                if (latestCurrent > latestUnique)
                {
                    latestUnique = latestCurrent;
                }
            }
            if (latestUnique + 1 < latestFrame)
            {
                context.Logger.LogMessage("Trimming animation {0} from {1} to {2} frames.",
                                          name, latestFrame, latestUnique + 1);
                foreach (AnimationTrack at in tracks.Values)
                {
                    at.ChopToLength(latestUnique + 1);
                }
            }
        }
示例#5
0
        /// <summary>
        /// The workhorse of the animation processor. It loops through all
        /// animations, all tracks, and all keyframes, and converts to the format
        /// expected by the runtime animation classes.
        /// </summary>
        /// <param name="input">The NodeContent to process. Comes from the base ModelProcessor.</param>
        /// <param name="output">The ModelContent that was produced. You don't typically change this.</param>
        /// <param name="context">The build context (logger, etc).</param>
        /// <returns>An allocated AnimationSet with the animations to include.</returns>
        public virtual AnimationSet BuildAnimationSet(NodeContent input, ref ModelContent output,
                                                      ContentProcessorContext context)
        {
            AnimationSet ret = new AnimationSet();

            if (!DoAnimations)
            {
                context.Logger.LogImportantMessage("DoAnimation is set to false for {0}; not generating animations.", input.Name);
                return(ret);
            }

            //  go from name to index
            Dictionary <string, ModelBoneContent> nameToIndex = new Dictionary <string, ModelBoneContent>();

            foreach (ModelBoneContent mbc in output.Bones)
            {
                nameToIndex.Add(GetBoneName(mbc), mbc);
            }

            AnimationContentDictionary adict = MergeAnimatedBones(input);

            if (adict == null || adict.Count == 0)
            {
                context.Logger.LogWarning("http://kwxport.sourceforge.net/", input.Identity,
                                          "Model processed with AnimationProcessor has no animations.");
                return(ret);
            }

            foreach (AnimationContent ac in adict.Values)
            {
                if (!IncludeAnimation(ac))
                {
                    context.Logger.LogImportantMessage(String.Format("Not including animation named {0}.", ac.Name));
                    continue;
                }
                context.Logger.LogImportantMessage(
                    "Processing animation {0} duration {1} sample rate {2} reduction tolerance {3}.",
                    ac.Name, ac.Duration, SampleRate, Tolerance);
                AnimationChannelDictionary acdict = ac.Channels;
                AnimationTrackDictionary   tracks = new AnimationTrackDictionary();
                foreach (string name in acdict.Keys)
                {
                    if (!IncludeTrack(ac, name))
                    {
                        context.Logger.LogImportantMessage(String.Format("Not including track named {0}.", name));
                        continue;
                    }

                    int ix = 0;
                    AnimationChannel achan = acdict[name];
                    int bix = nameToIndex[name].Index;
                    context.Logger.LogMessage("Processing bone {0}:{1}.", name, bix);
                    AnimationTrack at;
                    if (tracks.TryGetValue(bix, out at))
                    {
                        throw new System.ArgumentException(
                                  String.Format("Bone index {0} is used by multiple animations in the same clip (name {1}).",
                                                bix, name));
                    }

                    //  Sample at given frame rate from 0 .. Duration
                    List <Keyframe> kfl     = new List <Keyframe>();
                    int             nFrames = (int)Math.Floor(ac.Duration.TotalSeconds * SampleRate + 0.5);
                    for (int i = 0; i < nFrames; ++i)
                    {
                        Keyframe k = SampleChannel(achan, i / SampleRate, ref ix);
                        kfl.Add(k);
                    }

                    //  Run keyframe elimitation
                    Keyframe[] frames   = kfl.ToArray();
                    int        nReduced = 0;
                    if (tolerance_ > 0)
                    {
                        nReduced = ReduceKeyframes(frames, tolerance_);
                    }
                    if (nReduced > 0)
                    {
                        context.Logger.LogMessage("Reduced '{2}' from {0} to {1} frames.",
                                                  frames.Length, frames.Length - nReduced, name);
                    }

                    //  Create an AnimationTrack
                    at = new AnimationTrack(bix, frames);
                    tracks.Add(bix, at);
                }

                Animation a = new Animation(ac.Name, tracks, SampleRate);
                ret.AddAnimation(a);
            }

            //  build the special "identity" and "bind pose" animations
            AnimationTrackDictionary atd_id   = new AnimationTrackDictionary();
            AnimationTrackDictionary atd_bind = new AnimationTrackDictionary();

            foreach (KeyValuePair <string, ModelBoneContent> nip in nameToIndex)
            {
                Keyframe[] frames_id = new Keyframe[2];
                frames_id[0] = new Keyframe();
                frames_id[1] = new Keyframe();
                AnimationTrack at_id = new AnimationTrack(nip.Value.Index, frames_id);
                atd_id.Add(nip.Value.Index, at_id);

                Keyframe[] frames_bind = new Keyframe[2];
                Matrix     mat         = nip.Value.Transform;
                frames_bind[0] = Keyframe.CreateFromMatrix(mat);
                frames_bind[1] = new Keyframe();
                frames_bind[1].CopyFrom(frames_bind[0]);
                AnimationTrack at_bind = new AnimationTrack(nip.Value.Index, frames_bind);
                atd_bind.Add(nip.Value.Index, at_bind);
            }
            ret.AddAnimation(new Animation("$id$", atd_id, 1.0f));
            ret.AddAnimation(new Animation("$bind$", atd_bind, 1.0f));

            return(ret);
        }
 /// <summary>
 /// Given the animation tracks in the dictionary (for an animation with the given 
 /// name), figure out what the latest frame is that contains unique data for any 
 /// track, and trim the animation from the end to that length.
 /// </summary>
 /// <param name="name">name of the animation to trim</param>
 /// <param name="tracks">the tracks of the animation to trim</param>
 /// <param name="context">for logging etc</param>
 protected virtual void TrimAnimationTracks(string name, AnimationTrackDictionary tracks,
 ContentProcessorContext context)
 {
     int latestUnique = 1;
       int latestFrame = 0;
       foreach (AnimationTrack at in tracks.Values)
       {
     Keyframe last = at.Keyframes[0];
     int latestCurrent = 0;
     int index = 0;
     if (at.NumFrames > latestFrame)
     {
       latestFrame = at.NumFrames;
     }
     foreach (Keyframe kf in at.Keyframes)
     {
       if (kf != null && last.DifferenceFrom(kf) >= tolerance_)
       {
     latestCurrent = index;
     last = kf;
       }
       ++index;
     }
     if (latestCurrent > latestUnique)
     {
       latestUnique = latestCurrent;
     }
       }
       if (latestUnique + 1 < latestFrame)
       {
     context.Logger.LogMessage("Trimming animation {0} from {1} to {2} frames.",
     name, latestFrame, latestUnique + 1);
     foreach (AnimationTrack at in tracks.Values)
     {
       at.ChopToLength(latestUnique + 1);
     }
       }
 }
        /// <summary>
        /// The workhorse of the animation processor. It loops through all 
        /// animations, all tracks, and all keyframes, and converts to the format
        /// expected by the runtime animation classes.
        /// </summary>
        /// <param name="input">The NodeContent to process. Comes from the base ModelProcessor.</param>
        /// <param name="output">The ModelContent that was produced. You don't typically change this.</param>
        /// <param name="context">The build context (logger, etc).</param>
        /// <returns>An allocated AnimationSet with the animations to include.</returns>
        public virtual AnimationSet BuildAnimationSet(NodeContent input, ref ModelContent output, 
        ContentProcessorContext context)
        {
            AnimationSet ret = new AnimationSet();
              if (!DoAnimations)
              {
            context.Logger.LogImportantMessage("DoAnimation is set to false for {0}; not generating animations.", input.Name);
            return ret;
              }

              //  go from name to index
              Dictionary<string, ModelBoneContent> nameToIndex = new Dictionary<string, ModelBoneContent>();
              foreach (ModelBoneContent mbc in output.Bones)
            nameToIndex.Add(GetBoneName(mbc), mbc);

              AnimationContentDictionary adict = MergeAnimatedBones(input);
              if (adict == null || adict.Count == 0)
              {
            context.Logger.LogWarning("http://kwxport.sourceforge.net/", input.Identity,
            "Model processed with AnimationProcessor has no animations.");
            return ret;
              }

              foreach (AnimationContent ac in adict.Values)
              {
            if (!IncludeAnimation(ac))
            {
              context.Logger.LogImportantMessage(String.Format("Not including animation named {0}.", ac.Name));
              continue;
            }
            context.Logger.LogImportantMessage(
            "Processing animation {0} duration {1} sample rate {2} reduction tolerance {3}.",
            ac.Name, ac.Duration, SampleRate, Tolerance);
            AnimationChannelDictionary acdict = ac.Channels;
            AnimationTrackDictionary tracks = new AnimationTrackDictionary();
            TimeSpan longestUniqueDuration = new TimeSpan(0);
            foreach (string name in acdict.Keys)
            {
              if (!IncludeTrack(name))
              {
            context.Logger.LogImportantMessage(String.Format("Not including track named {0}.", name));
            continue;
              }

              int ix = 0;
              AnimationChannel achan = acdict[name];
              int bix = nameToIndex[name].Index;
              context.Logger.LogMessage("Processing bone {0}:{1}.", name, bix);
              AnimationTrack at;
              if (tracks.TryGetValue(bix, out at))
              {
            throw new System.ArgumentException(
                String.Format("Bone index {0} is used by multiple animations in the same clip (name {1}).",
                bix, name));
              }

              //  Sample at given frame rate from 0 .. Duration
              List<Keyframe> kfl = new List<Keyframe>();
              int nFrames = (int)Math.Floor(ac.Duration.TotalSeconds * SampleRate + 0.5);
              for (int i = 0; i < nFrames; ++i)
              {
            Keyframe k = SampleChannel(achan, i / SampleRate, ref ix);
            kfl.Add(k);
              }

              //  Run keyframe elimitation
              Keyframe[] frames = kfl.ToArray();
              int nReduced = 0;
              if (tolerance_ > 0)
            nReduced = ReduceKeyframes(frames, tolerance_);
              if (nReduced > 0)
            context.Logger.LogMessage("Reduced '{2}' from {0} to {1} frames.",
                frames.Length, frames.Length - nReduced, name);

              //  Create an AnimationTrack
              at = new AnimationTrack(bix, frames);
              Debug.Assert(name != null);
              at.Name = name;
              tracks.Add(bix, at);
            }
            if (ShouldTrimAnimation(ac))
            {
              TrimAnimationTracks(ac.Name, tracks, context);
            }

            Animation a = new Animation(ac.Name, tracks, SampleRate);
            ret.AddAnimation(a);
              }

              //  build the special "identity" and "bind pose" animations
              AnimationTrackDictionary atd_id = new AnimationTrackDictionary();
              AnimationTrackDictionary atd_bind = new AnimationTrackDictionary();
              foreach (KeyValuePair<string, ModelBoneContent> nip in nameToIndex)
              {
            if (!IncludeTrack(nip.Key))
              continue;
            Keyframe[] frames_id = new Keyframe[2];
            frames_id[0] = new Keyframe();
            frames_id[1] = new Keyframe();
            AnimationTrack at_id = new AnimationTrack(nip.Value.Index, frames_id);
            at_id.Name = nip.Key;
            atd_id.Add(nip.Value.Index, at_id);

            Keyframe[] frames_bind = new Keyframe[2];
            Matrix mat = nip.Value.Transform;
            frames_bind[0] = Keyframe.CreateFromMatrix(mat);
            frames_bind[1] = new Keyframe();
            frames_bind[1].CopyFrom(frames_bind[0]);
            AnimationTrack at_bind = new AnimationTrack(nip.Value.Index, frames_bind);
            at_bind.Name = nip.Key;
            atd_bind.Add(nip.Value.Index, at_bind);
              }
              ret.AddAnimation(new Animation("$id$", atd_id, 1.0f));
              ret.AddAnimation(new Animation("$bind$", atd_bind, 1.0f));

              return ret;
        }
示例#8
0
 public Animation(string name, AnimationTrackDictionary tracks, float frameRate)
     : this(name, tracks, frameRate, -1)
 {
 }