示例#1
0
 /// <summary>
 /// Exports the given animations into a BundleSheetExport and returns the created sheet
 /// </summary>
 /// <param name="settings">The export settings for the sheet</param>
 /// <param name="anims">The list of animations to export</param>
 /// <param name="cancellationToken">A cancelation token that is passed to the exporters and can be used to cancel the export process mid-way</param>
 /// <param name="progressHandler">Optional event handler for reporting the export progress</param>
 /// <returns>A BundleSheetExport representing the animations passed ready to be saved to disk</returns>
 public async Task <BundleSheetExport> ExportBundleSheet(AnimationExportSettings settings, Animation[] anims, CancellationToken cancellationToken = new CancellationToken(), BundleExportProgressEventHandler progressHandler = null)
 {
     using (var atlas = await GenerateAtlasFromAnimations(settings, anims, "", cancellationToken, progressHandler))
     {
         return(BundleSheetExport.FromAtlas(atlas));
     }
 }
示例#2
0
        /// <summary>
        /// Loads an AnimationSheet from the given stream, using the specified version
        /// number when reading properties
        /// </summary>
        /// <param name="stream">The stream to load the animation sheet from</param>
        /// <param name="parentBundle">The bundle that will contain this AnimationSheet</param>
        /// <param name="version">The version that the stream was written on</param>
        /// <returns>The Animation object loaded</returns>
        public static AnimationSheet LoadAnimationSheetFromStream(Stream stream, Bundle parentBundle, int version)
        {
            BinaryReader reader = new BinaryReader(stream);

            // Load the animation sheet data
            int    id   = reader.ReadInt32();
            string name = reader.ReadString();
            AnimationExportSettings settings = LoadExportSettingsFromStream(stream, version);

            // Create the animation sheet
            AnimationSheet sheet = new AnimationSheet(name)
            {
                ID = id, ExportSettings = settings
            };

            // Load the animation indices
            int animCount = reader.ReadInt32();

            for (int i = 0; i < animCount; i++)
            {
                Animation anim = parentBundle.GetAnimationByID(reader.ReadInt32());

                if (anim != null)
                {
                    sheet.AddAnimation(anim);
                }
            }

            return(sheet);
        }
示例#3
0
        /// <summary>
        /// Loads an AnimationSheet from the given stream, using the specified version
        /// number when reading properties
        /// </summary>
        /// <param name="stream">The stream to load the animation sheet from</param>
        /// <returns>The Animation object loaded</returns>
        protected AnimationSheet LoadAnimationSheetFromStream(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);

            // Load the animation sheet data
            int    id   = reader.ReadInt32();
            string name = reader.ReadString();
            AnimationExportSettings settings = LoadExportSettingsFromStream(stream);

            // Create the animation sheet
            AnimationSheet sheet = new AnimationSheet(name)
            {
                ID = id, ExportSettings = settings
            };

            // Load the animation indices
            int animCount = reader.ReadInt32();

            for (int i = 0; i < animCount; i++)
            {
                Animation anim = owningFile.LoadedBundle.GetAnimationByID(reader.ReadInt32());

                if (anim != null)
                {
                    sheet.AddAnimation(anim);
                }
                else
                {
                    throw new Exception(@"The animation referenced by an animation sheet stored is invalid. This may be due to a corrupted file.");
                }
            }

            return(sheet);
        }
示例#4
0
        /// <summary>
        /// Internal atlas packer method, tailored to work with individual rectangle frames
        /// </summary>
        /// <param name="exportSettings">The export settings to use when packing the rectangles</param>
        /// <param name="rectangles">The list of frame rectangles to try to pack</param>
        /// <param name="atlasWidth">An output atlas width uint</param>
        /// <param name="atlasHeight">At output atlas height uint</param>
        /// <param name="maxWidth">The maximum width the generated sheet can have</param>
        /// <returns>An array of rectangles, where each index matches the original passed Rectangle array, and marks the final computed bounds of the rectangle frames calculated</returns>
        private Rectangle[] InternalPack(AnimationExportSettings exportSettings, Rectangle[] rectangles, ref uint atlasWidth, ref uint atlasHeight, int maxWidth)
        {
            // Cache some fields as locals
            int x = exportSettings.XPadding;

            var boundsFinal = new Rectangle[rectangles.Length];

            for (int i = 0; i < rectangles.Length; i++)
            {
                var width  = rectangles[i].Width;
                var height = rectangles[i].Height;

                // X coordinate wrapping
                if (x + width > maxWidth)
                {
                    x = exportSettings.XPadding;
                }

                var y = exportSettings.YPadding;

                // Do a little trickery to find the minimum Y for this frame
                if (x - exportSettings.XPadding < atlasWidth)
                {
                    // Intersect the current frame rectangle with all rectangles above it, and find the maximum bottom Y coordinate between all the intersections
                    int contactRectX     = x - exportSettings.XPadding;
                    int contactRectWidth = width + exportSettings.XPadding * 2;

                    for (int j = 0; j < i; j++)
                    {
                        Rectangle rect = boundsFinal[j];

                        if (rect.X < (contactRectX + contactRectWidth) && contactRectX < (rect.X + rect.Width))
                        {
                            y = Math.Max(y, rect.Y + rect.Height + exportSettings.YPadding);
                        }
                    }
                }

                ////
                //// 3. Calculate frame area on sheet
                ////
                boundsFinal[i] = new Rectangle(x, y, width, height);

                atlasWidth  = (uint)Math.Max(atlasWidth, boundsFinal[i].X + boundsFinal[i].Width + exportSettings.XPadding);
                atlasHeight = (uint)Math.Max(atlasHeight, boundsFinal[i].Y + boundsFinal[i].Height + exportSettings.YPadding);


                // X coordinate update
                x += boundsFinal[i].Width + exportSettings.XPadding;

                if (x > maxWidth) // Jump to next line, at left-most corner
                {
                    x = exportSettings.XPadding;
                }
            }

            return(boundsFinal);
        }
示例#5
0
        /// <summary>
        /// Creates a new TextureAtlas, preparing the atlas to export using the given export settings
        /// </summary>
        /// <param name="settings">The export settings to use when packing the frames</param>
        /// <param name="name">An optional name for the TextureAtlas to be used on progress report</param>
        public TextureAtlas(AnimationExportSettings settings, string name = "")
        {
            _animationList = new List <Animation>();
            FrameList      = new List <IFrame>();
            BoundsList     = new List <Rectangle>();
            OriginsList    = new List <Rectangle>();
            ReuseCount     = new List <int>();
            ExportSettings = settings;
            Information    = new TextureAtlasInformation();

            Name = name;
        }
示例#6
0
        /// <summary>
        /// Saves the given AnimationExportSettings into a stream
        /// </summary>
        /// <param name="settings">The export settings to write to the stream</param>
        /// <param name="stream">The stream to write the animation sheet to</param>
        protected void SaveExportSettingsToStream(AnimationExportSettings settings, Stream stream)
        {
            BinaryWriter writer = new BinaryWriter(stream);

            writer.Write(settings.FavorRatioOverArea);
            writer.Write(settings.ForcePowerOfTwoDimensions);
            writer.Write(settings.ForceMinimumDimensions);
            writer.Write(settings.ReuseIdenticalFramesArea);
            writer.Write(settings.HighPrecisionAreaMatching);
            writer.Write(settings.AllowUnorderedFrames);
            writer.Write(settings.UseUniformGrid);
            writer.Write(settings.UsePaddingOnJson);
            writer.Write(settings.ExportJson);
            writer.Write(settings.XPadding);
            writer.Write(settings.YPadding);
        }
示例#7
0
        /// <summary>
        /// Tests a sheet export procedure with a given export settings struct
        /// </summary>
        /// <param name="settings">The export settings to use in this test</param>
        /// <param name="failMessage">The message to print if the test fails</param>
        private void TestSheetExportWithSettings(AnimationExportSettings settings, string failMessage = "Exported animation sheets should be equivalent to their original sheets")
        {
            // In theory, if you export a sheet and import it back just the way it was described on the generated json file, it will equal the original sheet completely
            OriginalSheet = new AnimationSheet("Sheet1")
            {
                ExportSettings = settings
            };

            for (int i = 0; i < 10; i++)
            {
                int animationWidth  = 12 + i / 2;
                int animationHeight = 12 + i / 2;

                OriginalSheet.AddAnimation(AnimationGenerator.GenerateAnimation("Anim" + OriginalSheet.AnimationCount,
                                                                                animationWidth, animationHeight, 10, OriginalSheet.AnimationCount * 2));
            }

            // Generate export path
            _tempExportPath = Path.GetTempPath() + Path.DirectorySeparatorChar + Path.GetRandomFileName();
            Directory.CreateDirectory(_tempExportPath);

            string exportPath = _tempExportPath + Path.DirectorySeparatorChar + OriginalSheet.Name;
            string jsonPath   = exportPath + ".json";

            // Export and save to disk
            IBundleExporter exporter = new DefaultPngExporter();

            exporter.ExportBundleSheet(OriginalSheet.ExportSettings, OriginalSheet.Animations).Result
            .SaveToDisk(_tempExportPath + Path.DirectorySeparatorChar + OriginalSheet.Name);

            // Export sheet temporarely
            for (int i = 0; i < OriginalSheet.Animations.Length; i++)
            {
                var animation = OriginalSheet.Animations[i];
                var image     = exporter.GenerateSpriteStrip(animation);

                var path = _tempExportPath + Path.DirectorySeparatorChar + OriginalSheet.Name + "_" + i + ".png";

                image.Save(path, ImageFormat.Png);
            }

            // Import it back up
            SheetFromDisk = (AnimationSheet)ImportSheetFile(jsonPath);
            SheetFromDisk.ExportSettings = OriginalSheet.ExportSettings;

            Assert.AreEqual(OriginalSheet, SheetFromDisk, failMessage);
        }
示例#8
0
        /// <summary>
        /// Initializes a new instance of the AnimationSheetEditor class
        /// </summary>
        /// <param name="controller">The controller that owns this form</param>
        /// <param name="sheetToEdit">The sheet to edit on this form. Leave null to show an interface to create a new sheet</param>
        public AnimationSheetView(Controller controller, AnimationSheet sheetToEdit = null)
        {
            InitializeComponent();

            zpb_sheetPreview.HookToControl(this);

            _controller  = controller;
            _sheetToEdit = sheetToEdit;

            if (sheetToEdit != null)
            {
                _exportSettings = sheetToEdit.ExportSettings;
            }

            InitializeFiends();
            ValidateFields();
        }
示例#9
0
        /// <summary>
        /// Loads an AnimationExportSettings from the given stream, using the specified
        /// version number when reading properties
        /// </summary>
        /// <param name="stream">The stream to load the export settings from</param>
        /// <returns>The AnimationExportSettings object loaded</returns>
        protected AnimationExportSettings LoadExportSettingsFromStream(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);

            AnimationExportSettings settings = new AnimationExportSettings
            {
                FavorRatioOverArea        = reader.ReadBoolean(),
                ForcePowerOfTwoDimensions = reader.ReadBoolean(),
                ForceMinimumDimensions    = reader.ReadBoolean(),
                ReuseIdenticalFramesArea  = reader.ReadBoolean(),
                HighPrecisionAreaMatching = reader.ReadBoolean(),
                AllowUnorderedFrames      = reader.ReadBoolean(),
                UseUniformGrid            = reader.ReadBoolean(),
                UsePaddingOnJson          = reader.ReadBoolean(),
                ExportJson = reader.ReadBoolean(),
                XPadding   = reader.ReadInt32(),
                YPadding   = reader.ReadInt32()
            };

            return(settings);
        }
示例#10
0
        /// <summary>
        /// Exports the given animations into an image sheet and returns the created sheet
        /// </summary>
        /// <param name="exportSettings">The export settings for the sheet</param>
        /// <param name="anims">The list of animations to export</param>
        /// <param name="name">The name for the generated texture atlas. Used for progress reports</param>
        /// <param name="cancellationToken">A cancelation token that is passed to the exporters and can be used to cancel the export process mid-way</param>
        /// <param name="progressHandler">Optional event handler for reporting the export progress</param>
        /// <returns>An image sheet representing the animations passed</returns>
        public async Task <TextureAtlas> GenerateAtlasFromAnimations(AnimationExportSettings exportSettings, Animation[] anims, string name = "", CancellationToken cancellationToken = new CancellationToken(), BundleExportProgressEventHandler progressHandler = null)
        {
            var atlas = new TextureAtlas(exportSettings, name);

            //
            // 1. Add the frames to the texture atlas
            //
            foreach (var anim in anims)
            {
                for (int i = 0; i < anim.FrameCount; i++)
                {
                    atlas.InsertFrame(anim.GetFrameAtIndex(i));
                }
            }

            //
            // 2. Pack the frames into the atlas
            //
            ITexturePacker packer = new DefaultTexturePacker();
            await packer.Pack(atlas, cancellationToken, progressHandler);

            return(atlas);
        }
示例#11
0
        /// <summary>
        /// Loads an AnimationExportSettings from the given stream, using the specified
        /// version number when reading properties
        /// </summary>
        /// <param name="stream">The stream to load the export settings from</param>
        /// <param name="version">The version that the stream was writter on</param>
        /// <returns>The AnimationExportSettings object loaded</returns>
        public static AnimationExportSettings LoadExportSettingsFromStream(Stream stream, int version)
        {
            BinaryReader reader = new BinaryReader(stream);

            AnimationExportSettings settings = new AnimationExportSettings
            {
                FavorRatioOverArea        = reader.ReadBoolean(),
                ForcePowerOfTwoDimensions = reader.ReadBoolean(),
                ForceMinimumDimensions    = reader.ReadBoolean(),
                ReuseIdenticalFramesArea  = reader.ReadBoolean(),
                // >= Version 4
                HighPrecisionAreaMatching = version >= 4 && reader.ReadBoolean(),
                AllowUnorderedFrames      = reader.ReadBoolean(),
                // >= Version 7
                UseUniformGrid   = version >= 7 && reader.ReadBoolean(),
                UsePaddingOnJson = reader.ReadBoolean(),
                // >= Version 5
                ExportJson = version < 5 || reader.ReadBoolean(),
                XPadding   = reader.ReadInt32(),
                YPadding   = reader.ReadInt32()
            };

            return(settings);
        }
示例#12
0
 /// <summary>
 /// Generates a BundleSheetExport object that contains information about the export of a sheet, using a custom event handler
 /// for export progress callback
 /// </summary>
 /// <param name="exportSettings">The export settings for the sheet</param>
 /// <param name="cancellationToken">A cancelation token that can be used to cancel the process mid-way</param>
 /// <param name="callback">The callback delegate to be used during the generation process</param>
 /// <param name="anims">The list of animations to export</param>
 /// <returns>A BundleSheetExport object that contains information about the export of the sheet</returns>
 public Task <BundleSheetExport> GenerateBundleSheet(AnimationExportSettings exportSettings, CancellationToken cancellationToken, BundleExportProgressEventHandler callback, params Animation[] anims)
 {
     return(GetExporter().ExportBundleSheet(exportSettings, anims, cancellationToken, callback));
 }
示例#13
0
 /// <summary>
 /// Generates a BundleSheetExport object that contains information about the export of a sheet
 /// </summary>
 /// <param name="exportSettings">The export settings for the sheet</param>
 /// <param name="anims">The list of animations to export</param>
 /// <returns>A BundleSheetExport object that contains information about the export of the sheet</returns>
 public Task <BundleSheetExport> GenerateBundleSheet(AnimationExportSettings exportSettings, params Animation[] anims)
 {
     return(GetExporter().ExportBundleSheet(exportSettings, anims));
 }