A sprite object with its own timeline
Inheritance: SWFProcessing.SWFModeller.Modelling.Timeline, ICharacter
Beispiel #1
0
        /// <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;
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        /// <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);
            }
        }
Beispiel #4
0
        /// <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);
                }
            }
        }
Beispiel #5
0
        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 */
        }
Beispiel #6
0
        /// <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. */
        }