static public FrameImageContent Tween(this FrameImageContent prev, FrameImageContent next, float pct)
        {
            FrameImageContent result = new FrameImageContent();

            result.TextureFolder = prev.TextureFolder;
            result.TextureFile   = prev.TextureFile;
            result.Clockwise     = prev.Clockwise;
            result.Pivot         = prev.Pivot;
            result.Parent        = prev.Parent;
            result.TimelineId    = prev.TimelineId;

            result.Scale.X = MathHelper.Lerp(prev.Scale.X, next.Scale.X, pct);
            result.Scale.Y = MathHelper.Lerp(prev.Scale.Y, next.Scale.Y, pct);

            result.Position.X = MathHelper.Lerp(prev.Position.X, next.Position.X, pct);
            result.Position.Y = MathHelper.Lerp(prev.Position.Y, next.Position.Y, pct);

            double angleB = prev.Clockwise
                ? ((next.Angle - prev.Angle < 0) ? (next.Angle + MathHelper.TwoPi) : next.Angle)
                : ((next.Angle - prev.Angle > 0) ? (next.Angle - MathHelper.TwoPi) : next.Angle);

            result.Angle = MathHelper.Lerp(prev.Angle, (float)angleB, pct);

            return(result);
        }
Beispiel #2
0
        public static FrameImageContent FromObjectXml(XElement xml, ImageContent[][] textures, bool tweened)
        {
            int folderId = int.Parse(xml.Attribute("folder").Value);
            int fileId   = int.Parse(xml.Attribute("file").Value);

            Vector2 pivot = Vector2.Zero;

            if (xml.Attribute("pivot_x") != null || xml.Attribute("pivot_y") != null)
            {
                pivot = new Vector2(
                    GetFloatAttribute(xml, "pivot_x", 0) * textures[folderId][fileId].Dimensions.X,
                    (1 - GetFloatAttribute(xml, "pivot_y", 1)) * textures[folderId][fileId].Dimensions.Y
                    );
            }
            else
            {
                try
                {
                    pivot =
                        textures[int.Parse(xml.Attribute("folder").Value)][int.Parse(xml.Attribute("file").Value)].Pivot;
                }
                catch
                {
                }
            }

            Vector2 position = new Vector2(
                GetFloatAttribute(xml, "x", 0),
                -GetFloatAttribute(xml, "y", 0)
                );

            Vector2 scale = new Vector2(
                GetFloatAttribute(xml, "scale_x", 1),
                GetFloatAttribute(xml, "scale_y", 1)
                );

            FrameImageContent frameImage = new FrameImageContent()
            {
                Angle         = -MathHelper.ToRadians(GetFloatAttribute(xml, "angle", 0)),
                Pivot         = pivot,
                Position      = position,
                TextureFolder = folderId,
                TextureFile   = fileId,
                TextureName   = textures[folderId][fileId].TextureName,
                Clockwise     = xml.Parent.Attribute("spin") != null && xml.Parent.Attribute("spin").Value == "-1",
                Tweened       = tweened,
                ZIndex        = GetInt32Attribute(xml, "z_index", 0),
                Scale         = scale
            };

            return(frameImage);
        }
 static public FrameImageContent CloneFrameImage(this FrameImageContent fimg, int?zindex, int?timelineId, int?parent)
 {
     return(new FrameImageContent()
     {
         Angle = fimg.Angle,
         Clockwise = fimg.Clockwise,
         Pivot = fimg.Pivot,
         Position = fimg.Position,
         TextureFile = fimg.TextureFile,
         TextureFolder = fimg.TextureFolder,
         TextureName = fimg.TextureName,
         Tweened = fimg.Tweened,
         ZIndex = zindex.HasValue ? zindex.Value : fimg.ZIndex,
         TimelineId = timelineId.HasValue ? timelineId.Value : fimg.TimelineId,
         Parent = parent.HasValue ? parent.Value : fimg.Parent,
         Scale = fimg.Scale
     });
 }
        public override CharacterContent Process(XDocument input, ContentProcessorContext context)
        {
            // Prevent parsing issues based on culture (i.e., decimals vs. commas in numbers)
            CultureInfo culture = Thread.CurrentThread.CurrentCulture;

            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            CharacterContent character = new CharacterContent();

            // Internal
            character.FramesPerSecond = AnimationFPS;

            // Textures
            // <folder> and <file> should be numbered in sequential order, so we shouldn't need
            // to get the id values here; <file> name attributes should also contain folder names
            //TODO: Future versions will support atlas images and sounds
            List <List <string> > textures = (from fld in input.Root.Elements("folder")
                                              select
                                              (
                                                  from file in fld.Elements("file")
                                                  select file.Attribute("name").Value
                                              ).ToList()
                                              ).ToList();

            character.Textures = (from fld in input.Root.Elements("folder")
                                  select
                                  (
                                      from file in fld.Elements("file")
                                      select XmlHelpers.FromImageXml(file, Path.GetDirectoryName(context.OutputFilename.Remove(0, context.OutputDirectory.Length)))
                                  ).ToArray()).ToArray();

            // Entities
            // Currently one entity per file, with no ID or name
            //TODO: Future versions may include more than one entity, with names

            // Animations
            List <AnimationContent> animations = new List <AnimationContent>();

            foreach (XElement xanim in input.Root.Element("entity").Elements("animation"))
            {
                // Make a dictionary of external timelines which get pulled into the mainline
                Dictionary <int, Dictionary <int, List <FrameImageContent> > > objCache = new Dictionary <int, Dictionary <int, List <FrameImageContent> > >();
                Dictionary <int, Dictionary <int, List <Bone> > > boneCache             = new Dictionary <int, Dictionary <int, List <Bone> > >();
                foreach (XElement tl in xanim.Elements("timeline"))
                {
                    int tlId = int.Parse(tl.Attribute("id").Value);
                    if (!objCache.ContainsKey(tlId))
                    {
                        objCache[tlId] = new Dictionary <int, List <FrameImageContent> >();
                    }
                    if (!boneCache.ContainsKey(tlId))
                    {
                        boneCache[tlId] = new Dictionary <int, List <Bone> >();
                    }

                    foreach (XElement key in tl.Elements("key"))
                    {
                        int objId = int.Parse(key.Attribute("id").Value);
                        objCache[tlId][objId] =
                            (from obj in key.Elements("object") select XmlHelpers.FromObjectXml(obj, character.Textures, true)).ToList();
                        boneCache[tlId][objId] =
                            (from bone in key.Elements("bone") select XmlHelpers.FromBoneXml(bone)).ToList();
                    }
                }

                // Build the animation itself
                AnimationContent anim = new AnimationContent()
                {
                    Name    = xanim.Attribute("name").Value,
                    Length  = long.Parse(xanim.Attribute("length").Value),
                    Looping = XmlHelpers.GetBoolAttribute(xanim, "looping", true),
                };

                // Retrieve a list of keyframes from the mainline
                List <Keyframe> keyframes = new List <Keyframe>();
                foreach (XElement xkey in xanim.Element("mainline").Elements("key"))
                {
                    Keyframe key = new Keyframe();
                    key.Time = XmlHelpers.GetInt64Attribute(xkey, "time", 0);

                    List <FrameImageContent> objs = new List <FrameImageContent>();
                    List <Bone> bones             = new List <Bone>();
                    foreach (XElement xobj in xkey.DescendantNodes())
                    {
                        if (xobj.Name == "object")
                        {
                            objs.Add(XmlHelpers.FromObjectXml(xobj, character.Textures, false));
                        }
                        else if (xobj.Name == "bone")
                        {
                            bones.Add(XmlHelpers.FromBoneXml(xobj));
                        }
                        else if (xobj.Name == "object_ref")
                        {
                            int tlId     = int.Parse(xobj.Attribute("timeline").Value);
                            int keyId    = int.Parse(xobj.Attribute("key").Value);
                            int zindex   = int.Parse(xobj.Attribute("z_index").Value);
                            int parentId = XmlHelpers.GetInt32Attribute(xobj, "parent", -1);

                            foreach (FrameImageContent fimg in objCache[tlId][keyId])
                            {
                                objs.Add(fimg.CloneFrameImage(zindex, tlId, parentId));
                            }
                        }
                        else if (xobj.Name == "bone_ref")
                        {
                            int tlId     = int.Parse(xobj.Attribute("timeline").Value);
                            int keyId    = int.Parse(xobj.Attribute("key").Value);
                            int parentId = XmlHelpers.GetInt32Attribute(xobj, "parent", -1);

                            foreach (Bone bone in boneCache[tlId][keyId])
                            {
                                bones.Add(bone.CloneBone(tlId, parentId));
                            }
                        }
                    }

                    // Save to object
                    key.Objects = objs.ToArray();
                    key.Bones   = bones.OrderBy(x => x.Id).ToArray();

                    keyframes.Add(key);
                }
                if (keyframes[keyframes.Count - 1].Time < anim.Length)
                {
                    keyframes.Add(keyframes[0].Clone(anim.Length));
                }

                // Process into frames
                Int32 frameTimeStep        = 1000 / AnimationFPS;
                List <FrameContent> frames = new List <FrameContent>();
                for (int frameTime = 0; frameTime <= anim.Length; frameTime += frameTimeStep)
                {
                    Keyframe currentFrame =
                        (from kf in keyframes where kf.Time <= frameTime orderby kf.Time descending select kf).
                        FirstOrDefault();
                    Keyframe nextFrame =
                        (from kf in keyframes where kf.Time > frameTime orderby kf.Time ascending select kf).
                        FirstOrDefault();

                    float timePct = (nextFrame != null) ?
                                    ((frameTime - currentFrame.Time) / (float)(nextFrame.Time - currentFrame.Time)) :
                                    0;

                    List <FrameImageContent> frameImages = new List <FrameImageContent>();
                    foreach (FrameImageContent currentFrameImage in currentFrame.Objects)
                    {
                        FrameImageContent nextFrameImage = (currentFrameImage.Tweened && nextFrame != null && nextFrame.Objects.Where(x => x.TimelineId == currentFrameImage.TimelineId).Any())
                                                        ? nextFrame.Objects.Where(x => x.TimelineId == currentFrameImage.TimelineId).Select(x => x).First()
                                                        : null;

                        // Tweening
                        //TODO: Future versions will use tweening methods other than linear
                        if (nextFrameImage != null)
                        {
                            frameImages.Add(currentFrameImage.Tween(nextFrameImage, timePct));
                        }
                        // Select last frame
                        else
                        {
                            frameImages.Add(currentFrameImage.CloneFrameImage());
                        }
                    }

                    List <Bone> bones = new List <Bone>();
                    foreach (Bone currentBone in currentFrame.Bones)
                    {
                        Bone nextBone = (nextFrame != null &&
                                         nextFrame.Bones.Where(x => x.TimelineId == currentBone.TimelineId).Any())
                                            ? nextFrame.Bones.Where(x => x.TimelineId == currentBone.TimelineId)
                                        .Select(x => x)
                                        .First()
                                            : null;

                        // Tweening
                        if (nextBone != null)
                        {
                            bones.Add(currentBone.Tween(nextBone, timePct));
                        }
                        else
                        {
                            bones.Add(currentBone.CloneBone());
                        }
                    }

                    FrameContent frame = new FrameContent()
                    {
                        Objects = frameImages.OrderBy(x => x.ZIndex).ToArray(), Bones = bones.OrderBy(x => x.Id).ToArray()
                    };
                    frames.Add(frame);
                }
                anim.Frames = frames.ToArray();

                // Build timeline/texture lookup
                anim.TextureTimelines = new Dictionary <string, int>();
                foreach (List <string> folder in textures)
                {
                    foreach (string file in folder)
                    {
                        var textimeline = frames.SelectMany(x => x.Objects)
                                          .Where(x => x.TextureName != null && x.TextureName.Equals(file))
                                          .Select(x => x.TimelineId);
                        if (textimeline.Any())
                        {
                            anim.TextureTimelines[file] = textimeline.First();
                        }
                    }
                }

                // Build timeline/bone lookup
                anim.BoneTimelines = new Dictionary <string, int>();
                foreach (Bone bone in frames.SelectMany(x => x.Bones))
                {
                    if (!String.IsNullOrEmpty(bone.Name) && !anim.BoneTimelines.ContainsKey(bone.Name))
                    {
                        anim.BoneTimelines.Add(bone.Name, bone.TimelineId);
                    }
                }

                animations.Add(anim);
            }

            character.Animations = new List <AnimationContent>();
            character.Animations.AddRange(animations);

            // Build external textures
            foreach (List <string> folder in textures)
            {
                foreach (string txfile in folder)
                {
                    String assetName = Path.Combine(
                        Path.GetDirectoryName(context.OutputFilename.Remove(0, context.OutputDirectory.Length)),
                        Path.GetFileNameWithoutExtension(context.OutputFilename),
                        textures.IndexOf(folder).ToString("00"),
                        folder.IndexOf(txfile).ToString("00"));

                    String sourceName = Path.Combine(
                        Path.GetDirectoryName(context.OutputFilename.Remove(0, context.OutputDirectory.Length)),
                        txfile
                        );

                    OpaqueDataDictionary data = new OpaqueDataDictionary();
                    data.Add("GenerateMipmaps", false);
                    data.Add("ResizeToPowerOfTwo", false);
                    data.Add("PremultiplyAlpha", PremultiplyAlpha);
                    data.Add("TextureFormat", TextureFormat);
                    context.BuildAsset <TextureContent, TextureContent>(
                        new ExternalReference <TextureContent>(sourceName),
                        "TextureProcessor", data, "TextureImporter", assetName);
                }
            }

            Thread.CurrentThread.CurrentCulture = culture;
            return(character);
        }
 static public FrameImageContent CloneFrameImage(this FrameImageContent fimg)
 {
     return(fimg.CloneFrameImage(null, null, null));
 }