protected virtual void AddMainlineInfo(XmlElement parent, int animIndex) { var mainline = Scml.CreateElement("mainline"); parent.AppendChild(mainline); var bank = AnimData.Anims[animIndex]; var rate = (int)(Utilities.MS_PER_S / bank.Rate); var idMap = bank.BuildIdMap(AnimHashes); for (var frameIndex = 0; frameIndex < bank.FrameCount; frameIndex++) { var occurenceMap = new ObjectNameMap(); var keyframe = AddKeyframe(frameIndex, rate); var frame = bank.Frames[frameIndex]; for (var elementIndex = 0; elementIndex < frame.ElementCount; elementIndex++) { var objectRef = Scml.CreateElement("object_ref"); var element = frame.Elements[elementIndex]; occurenceMap.Update(element, AnimHashes); var occName = occurenceMap.FindObjectName(element, AnimHashes); Logger.Debug(occName); objectRef.SetAttribute("id", idMap[occName].ToString()); objectRef.SetAttribute("timeline", idMap[occName].ToString()); // b/c ONI has animation properties for each element specified at every frame the timeline key frame that // matches a mainline key frame is always the same objectRef.SetAttribute("key", frameIndex.ToString()); objectRef.SetAttribute("z_index", (frame.ElementCount - elementIndex).ToString()); keyframe.AppendChild(objectRef); } mainline.AppendChild(keyframe); } }
protected virtual void AddTimelineInfo(XmlElement parent, int animIndex) { var bank = AnimData.Anims[animIndex]; var rate = (int)(Utilities.MS_PER_S / bank.Rate); var timelineMap = new Dictionary <int, XmlElement>(); var idMap = bank.BuildIdMap(AnimHashes); foreach (var entry in idMap) { var timeline = Scml.CreateElement("timeline"); timeline.SetAttribute("id", entry.Value.ToString()); // This may unintentionally append _0 to timeline names? timeline.SetAttribute("name", entry.Key.Value); timelineMap[entry.Value] = timeline; } for (var frameIndex = 0; frameIndex < bank.FrameCount; frameIndex++) { var frame = bank.Frames[frameIndex]; var occMap = new ObjectNameMap(); for (var elementIndex = 0; elementIndex < frame.ElementCount; elementIndex++) { var keyframe = AddKeyframe(frameIndex, rate); var element = frame.Elements[elementIndex]; occMap.Update(element, AnimHashes); var name = occMap.FindObjectName(element, AnimHashes); var trans = element.Decompose(); var object_def = Scml.CreateElement("object"); object_def.SetAttribute("folder", "0"); // Here we need to explicitly get the file name with its associated index because we are using the filename // to reference the actual image which does include the index of the frame of its symbol in the name var filename = element.FindNameWithIndex(AnimHashes).ToFilename(); if (!filenameindex.ContainsKey(filename)) { // Check if a preceding frame in this symbol exists that we can use before // deciding that the sprite/file does not exist var precedingFilename = GetPrecedingFilename(element); if (precedingFilename != null) { filename = precedingFilename; } else if (FillMissingSprites) { // Must generate the missing sprite. var sprite = new Sprite { Bitmap = new Bitmap(1, 1), Name = filename.ToSpriteName() }; Sprites.Add(sprite); // Also add it to the Spriter file filenameindex[filename] = BuildData.FrameCount + 1; var fileNode = Scml.CreateElement("file"); fileNode.SetAttribute("id", filenameindex[filename].ToString()); fileNode.SetAttribute("name", filename.ToString()); fileNode.SetAttribute("width", 1f.ToStringInvariant()); fileNode.SetAttribute("height", 1f.ToStringInvariant()); fileNode.SetAttribute("pivot_x", 0f.ToStringInvariant()); fileNode.SetAttribute("pivot_y", 0f.ToStringInvariant()); var folderNode = SpriterRoot.GetElementsByTagName("folder")[0]; folderNode.AppendChild(fileNode); } else { throw new ProjectParseException($"Animation \"{bank.Name}\" in \"{BuildData.Name}\" referenced a sprite \"{filename}\" that doesn't exist."); } } object_def.SetAttribute("file", filenameindex[filename].ToString()); object_def.SetAttribute("x", (trans.X * 0.5f).ToStringInvariant()); object_def.SetAttribute("y", (-trans.Y * 0.5f).ToStringInvariant()); object_def.SetAttribute("angle", trans.Angle.ToStringInvariant()); object_def.SetAttribute("scale_x", trans.ScaleX.ToStringInvariant()); object_def.SetAttribute("scale_y", trans.ScaleY.ToStringInvariant()); keyframe.AppendChild(object_def); timelineMap[idMap[name]].AppendChild(keyframe); } } foreach (var timeline in timelineMap.Values) { parent.AppendChild(timeline); } }