/// <summary> /// Create a new sprite and add it to the SWF. /// </summary> /// <param name="id">A unique ID as supplied by valid SWF data</param> /// <param name="frameCount">The number of frames on the sprite's /// timeline.</param> /// <param name="exportForScript">If a sprite is exported for script, it will /// appear at the start of the SWF file.</param> /// <returns>The newly created sprite.</returns> public Sprite NewSprite(string id, uint frameCount, bool exportForScript) { if (this.dictionary.ContainsKey(id)) { throw new SWFModellerException(SWFModellerError.Internal, @"Duplicate character ID (Sprite)"); } Sprite newSprite = new Sprite(frameCount, this); this.dictionary[id] = newSprite; if (exportForScript) { this.exportOnFirstFrame.Add(newSprite); } return newSprite; }
public void Instantiate(int frameNum, Sprite sprite, Layer.Position layering, Matrix position, string instanceName, string qClassName) { AS3Class instanceClass = sprite.Class; if (this.Class == null) { throw new SWFModellerException( SWFModellerError.Internal, "Can't instantiate " + instanceName + " on timeline with no code"); } DoABC scriptTag = this.Root.FirstScript; if (scriptTag == null) { /* ISSUE 70: Y'know, we can generate scripts. We should probably do that. */ throw new SWFModellerException( SWFModellerError.Internal, "Can't instantiate clips in a SWF with no code."); } if (instanceClass == null) { DoABC.GenerateDefaultScript(qClassName, sprite); instanceClass = sprite.Class; } /* Create instance variable of type referenced by instanceClass */ Namespace propNS = scriptTag.Code.CreateNamespace(Namespace.NamespaceKind.Package, string.Empty); Multiname propName = scriptTag.Code.CreateMultiname(Multiname.MultinameKind.QName, instanceName, propNS, NamespaceSet.EmptySet); if (this.Class is AS3ClassDef) { ((AS3ClassDef)this.Class).AddInstanceTrait(new SlotTrait() { Kind = TraitKind.Slot, TypeName = instanceClass.Name, Name = propName, ValKind = ConstantKind.ConUndefined }); } this.GetFrame(frameNum).AddTag(new PlaceObject(sprite, this.GetFreeLayer(layering), null, position, instanceName, false, null, null, null)); }
/// <summary> /// Creates an instance within another instance's clip, e.g. creating "mc1.mc2.mc3" /// will create mc3 within mc2, where mc1.mc2 is mc2's qname. /// </summary> /// <param name="qname">The qualified name of the instance to create.</param> /// <param name="swf">The SWF to create it in.</param> /// <param name="transform">This is an XML node which extends transformRelativeToType in the XSD, and /// can be queried for transform information.</param> /// <param name="charToInstantiate">The character to create an instance of.</param> private void CreateInstanceIn(string qname, SWF swf, XPathNavigator transform, Sprite charToInstantiate, string qClassName) { string newInsName; Timeline parent = this.QNameToTimeline(qname, swf, out newInsName); string relativeToQname = transform.GetAttribute(XMLHelper.AttrRelativeTo, string.Empty); Matrix m = null; if (relativeToQname == null || relativeToQname == string.Empty) { m = Xml.TransformTagToMatrix(transform); if (m.IsSimpleTranslate) { m.TransX = m.TransX; m.TransY = m.TransY; } } else { m = swfProc.PositionFromQname(relativeToQname, swf); Matrix rel = Xml.TransformTagToMatrix(transform); if (rel.IsSimpleTranslate) { m.Translate(rel.TransX, rel.TransY); } else { m.Apply(rel); } } try { parent.Instantiate(1, charToInstantiate, Layer.Position.Front, m, newInsName, qClassName); } catch (SWFModellerException sme) { throw new SwiffotronException( SwiffotronError.BadInputXML, this.Context.Sentinel("CreateInstanceIn"), "Failed to instantiate an instance in a timeline. instance name:" + qname + ", instance class:" + qClassName, sme); } }
/// <summary> /// Creates an instance from a referenced SWF. /// </summary> /// <param name="insTag">The instance tag.</param> /// <param name="swf">The SWF to place the instance into.</param> /// <param name="className">Name of the class for the new clip.</param> /// <param name="importSwf">The SWF to import as a clip.</param> private void CreateInstanceFromSWF(XPathNavigator insTag, SWF swf, string className, SWF importSwf) { if (!swf.HasClass) { /* Can't create instances if the parent timeline has no code now can we? */ swf.GenerateTimelineScripts(); } bool isAdobeClassname = className.StartsWith("flash.") || className.StartsWith("fl.") || className.StartsWith("adobe.") || className.StartsWith("air.") || className.StartsWith("flashx."); if (isAdobeClassname && importSwf.HasClass) { /* Can't rename a class to an Adobe class name. That's bonkers. */ throw new SwiffotronException( SwiffotronError.BadInputXML, this.Context.Sentinel("InstanceClassNameInappropriate"), "You can't rename a timeline class to a reserved adobe classname (" + className + "), SWF: " + importSwf.Context); } if (className == string.Empty) { if (importSwf.Class == null) { /* No class name is fine if the imported SWF has no class to rename. We need * a class to bind it to though, so let's make it MovieClip, just like * real flash. */ className = "flash.display.MovieClip"; } else { throw new SwiffotronException( SwiffotronError.BadInputXML, this.Context.Sentinel("MainTimelineInstanceNotRenamed"), "An external instance with timeline code must be explicitely renamed with the instance tag's class attribute."); } } if (className == "flash.display.MovieClip") { Sprite spr = new Sprite(importSwf, swf); this.CreateInstanceIn( insTag.GetAttribute(XMLHelper.AttrID, string.Empty), swf, insTag, spr, className); } else { Sprite spr = new Sprite(importSwf, swf, className); this.CreateInstanceIn( insTag.GetAttribute(XMLHelper.AttrID, string.Empty), swf, insTag, spr, className); spr.SpriteProc(delegate(Sprite s) { if (s.Class != null && !(s.Class is AdobeClass)) { /* ISSUE 29: Only do this if the class hasn't already been bound. */ swf.FirstScript.Code.GenerateClipClassBindingScript(s); } }); if (spr.Class != null) { swf.FirstScript.Code.GenerateClipClassBindingScript(spr); } } }
private void WriteSprite(Sprite s, ListSet<Timeline> unboundClasses) { foreach (ICharacterReference cr in s.CharacterRefs) { this.WriteCharacter(cr.Character, unboundClasses); } if (s.HasClass && !(s.Class is AdobeClass) && !unboundClasses.Contains(s)) { unboundClasses.Add(s); } int id = this.characterMarshal.GetIDFor(s); WriteBuffer tagWriter = this.OpenTag(Tag.DefineSprite, s.ToString() + ";id=" + id.ToString()); tagWriter.WriteUI16((uint)id); tagWriter.WriteUI16(s.FrameCount); #if DEBUG this.LogMessage("char id=" + id); #endif foreach (Frame f in s.Frames) { if (f.HasLabel) { #if DEBUG this.LogMessage("frame label=" + f.Label); #endif WriteBuffer labelWriter = this.OpenTag(Tag.FrameLabel); labelWriter.WriteString(f.Label); this.CloseTag(); } foreach (IDisplayListItem dli in f.DisplayList) { switch (dli.Type) { case DisplayListItemType.PlaceObjectX: this.WritePlaceObjectTag((PlaceObject)dli); break; case DisplayListItemType.RemoveObjectX: this.WriteRemoveObjectTag((RemoveObject)dli); break; default: /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "Unsupported tag in SWF sprite writer: " + dli.GetType().ToString()); } } this.WriteBodylessTag(Tag.ShowFrame); } this.WriteBodylessTag(Tag.End, id.ToString()); this.CloseTag(); /* DefineSprite */ }
/// <summary> /// Generates a script that binds a class to a clip. /// </summary> /// <param name="spr">The sprite to create the class for.</param> public void GenerateClipClassBindingScript(Sprite spr) { Namespace nsEmptyPackage = this.CreateNamespace(Namespace.NamespaceKind.Package, string.Empty); Namespace nsFlashEvents = this.CreateNamespace(Namespace.NamespaceKind.Package, "flash.events"); Namespace nsFlashDisplay = this.CreateNamespace(Namespace.NamespaceKind.Package, "flash.display"); Multiname mnObject = this.CreateMultiname(Multiname.MultinameKind.QName, "Object", nsEmptyPackage, null); Multiname mnEventDispatcher = this.CreateMultiname(Multiname.MultinameKind.QName, "EventDispatcher", nsFlashEvents, null); Multiname mnDisplayObject = this.CreateMultiname(Multiname.MultinameKind.QName, "DisplayObject", nsFlashDisplay, null); Multiname mnInteractiveObject = this.CreateMultiname(Multiname.MultinameKind.QName, "InteractiveObject", nsFlashDisplay, null); Multiname mnDisplayObjectContainer = this.CreateMultiname(Multiname.MultinameKind.QName, "DisplayObjectContainer", nsFlashDisplay, null); Multiname mnSprite = this.CreateMultiname(Multiname.MultinameKind.QName, "Sprite", nsFlashDisplay, null); Multiname mnMovieClip = this.CreateMultiname(Multiname.MultinameKind.QName, "MovieClip", nsFlashDisplay, null); Multiname sprQName = null; Multiname sprMultiname = null; if (spr.Class.Name.Kind == Multiname.MultinameKind.Multiname) { sprMultiname = spr.Class.Name; /* ISSUE 5: Convert a multiname to a QName of the form: * mn QName "MyClassName"; ns Package "com.mypackage"; set * */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "Unsupported sprite class name kind in class binding script generation: " + spr.Class.Name.Kind.ToString()); } else if (spr.Class.Name.Kind == Multiname.MultinameKind.QName) { sprQName = spr.Class.Name; /* Convert to form: * mn Multiname "MyClassName"; ns *; set {ns Package "com.mypackage"} */ sprMultiname = this.CreateMultiname( Multiname.MultinameKind.Multiname, sprQName.Name, nsEmptyPackage, this.CreateNamespaceSet(new Namespace[] { sprQName.NS })); } else { /* ISSUE 73 */ throw new SWFModellerException( SWFModellerError.UnimplementedFeature, "Unsupported sprite class name kind in class binding script generation: " + spr.Class.Name.Kind.ToString()); } Method bindingMethod = this.CreateMethod(spr.Class.Name.Name + "BindingScript.abc", 2, 1, 1, 9, /* The above magic numbers come from the numbers generated by IDE versions of this function. * I have no real ideal about how I'd work them out for myself, which would obviously be * more ideal. */ /* Line */ /* 1 */ this.Op(Opcode.Mnemonics.GetLocal0), /* 2 */ this.Op(Opcode.Mnemonics.PushScope), /* 3 */ this.Op(Opcode.Mnemonics.FindPropStrict, sprMultiname), /* 4 */ this.Op(Opcode.Mnemonics.GetLex, mnObject), /* 5 */ this.Op(Opcode.Mnemonics.PushScope), /* 6 */ this.Op(Opcode.Mnemonics.GetLex, mnEventDispatcher), /* 7 */ this.Op(Opcode.Mnemonics.PushScope), /* 8 */ this.Op(Opcode.Mnemonics.GetLex, mnDisplayObject), /* 9 */ this.Op(Opcode.Mnemonics.PushScope), /* 10 */ this.Op(Opcode.Mnemonics.GetLex, mnInteractiveObject), /* 11 */ this.Op(Opcode.Mnemonics.PushScope), /* 12 */ this.Op(Opcode.Mnemonics.GetLex, mnDisplayObjectContainer), /* 13 */ this.Op(Opcode.Mnemonics.PushScope), /* 14 */ this.Op(Opcode.Mnemonics.GetLex, mnSprite), /* 15 */ this.Op(Opcode.Mnemonics.PushScope), /* 16 */ this.Op(Opcode.Mnemonics.GetLex, mnMovieClip), /* 17 */ this.Op(Opcode.Mnemonics.PushScope), /* 18 */ this.Op(Opcode.Mnemonics.GetLex, mnMovieClip), /* 19 */ this.Op(Opcode.Mnemonics.NewClass, spr.Class), /* 20 */ this.Op(Opcode.Mnemonics.PopScope), /* 21 */ this.Op(Opcode.Mnemonics.PopScope), /* 22 */ this.Op(Opcode.Mnemonics.PopScope), /* 23 */ this.Op(Opcode.Mnemonics.PopScope), /* 24 */ this.Op(Opcode.Mnemonics.PopScope), /* 25 */ this.Op(Opcode.Mnemonics.PopScope), /* 26 */ this.Op(Opcode.Mnemonics.PopScope), /* 27 */ this.Op(Opcode.Mnemonics.InitProperty, sprQName), /* 28 */ this.Op(Opcode.Mnemonics.ReturnVoid)); Trait classTrait = new ClassTrait() { As3class = (AS3ClassDef)spr.Class, Kind = TraitKind.Class, Name = sprQName }; bindingMethod.AddTrait(classTrait); Script bindScript = new Script() { Method = bindingMethod, }; bindScript.AddTrait(classTrait); this.scripts.Insert(0, bindScript); /* Insert at the start to make sure any timeline script is last. */ }