Exemple #1
0
        /// <summary>
        /// Generate code of new spriteGroup class.
        /// </summary>
        /// <param name="spriteGroup"> Name of new class/spriteGroup. </param>
        /// <returns>
        /// <code>
        /// [<see cref="NutPackerLib.OriginalNameAttribute"/>("original name of folder")]
        /// public class <paramref name="spriteGroup"/> : <see cref="ISpriteGroup"/> { }
        /// </code>
        /// </returns>
        public static CodeTypeDeclaration GenerateSpriteGroupClass(
            string spriteGroup)
        {
            /// New public class with <param name="spriteGroup"></param> name.
            var spriteGroupClass = new CodeTypeDeclaration()
            {
                Name             = Walkthrough.VariableName(spriteGroup)
                , IsClass        = true
                , TypeAttributes = TypeAttributes.Public
            };

            /// Inherited from <see cref="ISpriteGroup"/>.
            spriteGroupClass.BaseTypes.Add(new CodeTypeReference(typeof(ISpriteGroup)));

            /// Create attribute.
            /// [<see cref="NutPackerLib.OriginalNameAttribute"/>("original name of folder")]
            CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
                typeof(NutPackerLib.OriginalNameAttribute).FullName
                , new CodeAttributeArgument(new CodePrimitiveExpression(spriteGroup))
                );

            /// Add attribute.
            spriteGroupClass.CustomAttributes.Add(attribute);

            return(spriteGroupClass);
        }
Exemple #2
0
        /// <summary>
        /// Generate new property <see cref="Rectangle"/>.
        /// </summary>
        /// <param name="picture"> Name of new property. </param>
        /// <param name="rectangle"> Location in texture atlas. </param>
        /// <returns>
        /// <code>
        /// [<see cref="NutPackerLib.OriginalNameAttribute"/>(name of picture)]
        /// public static <see cref="Rectangle"/> <paramref name="picture"/> {
        ///     get {
        ///         // r - <paramref name="rectangle"/>.
        ///         return new <see cref="Rectangle"/>(r.X, r.Y, r.Width, r.Height);
        ///     }
        /// }
        /// </code>
        /// </returns>
        public static CodeMemberProperty GenerateTileProperty(
            string picture
            , Rectangle rectangle)
        {
            /// New public static class, with getter and type <see cref="Rectangle"/>.
            CodeMemberProperty pic = new CodeMemberProperty()
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Static
                , Name     = Walkthrough.VariableName(Path.GetFileNameWithoutExtension(picture))
                , HasGet   = true
                , Type     = new CodeTypeReference(typeof(Xna.Rectangle))
            };

            /// Add expression to getter: return new <see cref="Rectangle"/>(r.X, r.Y, r.Width, r.Height);
            /// r - <param name="rectangle"></param>
            pic.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeObjectCreateExpression(typeof(Xna.Rectangle)
                                                   , new CodePrimitiveExpression(rectangle.X)
                                                   , new CodePrimitiveExpression(rectangle.Y)
                                                   , new CodePrimitiveExpression(rectangle.Width)
                                                   , new CodePrimitiveExpression(rectangle.Height)
                                                   )));

            /// Create attribute.
            /// [<see cref="NutPackerLib.OriginalNameAttribute"/>("name of picture")]
            CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
                typeof(NutPackerLib.OriginalNameAttribute).FullName
                , new CodeAttributeArgument(new CodePrimitiveExpression(picture))
                );

            /// Add attribute.
            pic.CustomAttributes.Add(attribute);

            return(pic);
        }
Exemple #3
0
        /// <summary>
        /// Generate code of new SpriteSheet class.
        /// </summary>
        /// <remarks>
        /// Ya, all this code will be generated for every class,
        /// but it's only way to use indexer with static field.
        /// And ya, we need static field, cause we don't wanna create instance of array
        /// each time when we use it.
        /// So, it's some kinda singleton.
        /// </remarks>
        /// <param name="spriteSheetName"> Name of new class/spriteSheet. </param>
        /// <param name="rectangles"> Array of rectangles. </param>
        /// <returns>
        /// <code>
        /// public class <paramref name="spriteSheetName"/> : <see cref="ISpriteSheet"/>
        /// {
        ///     private static <see cref="Xna.Rectangle"/>[] Frames =
        ///         new <see cref="Xna.Rectangle"/>[] { }
        ///
        ///     public int Length {
        ///         get {
        ///             return Frames.Length; // Here will be just number.
        ///         }
        ///     }
        ///
        ///     public int this[int index] { get { return Frames[index] } }
        /// }
        /// </code>
        /// </returns>
        public static CodeTypeDeclaration GenerateSpriteSheetClass(
            string spriteSheetName
            , params Rectangle[] rectangles)
        {
            /// New public class with <param name="spriteSheetName"></param> name.
            CodeTypeDeclaration spriteSheetClass = new CodeTypeDeclaration()
            {
                Name             = Walkthrough.VariableName(spriteSheetName)
                , IsClass        = true
                , TypeAttributes = TypeAttributes.Public
            };

            /// Inherited from <see cref="ISpriteSheet"/>.
            spriteSheetClass.BaseTypes.Add(new CodeTypeReference(typeof(ISpriteSheet)));

            /// Create attribute.
            /// [<see cref="NutPackerLib.OriginalNameAttribute"/>("original name of folder")]
            CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
                typeof(NutPackerLib.OriginalNameAttribute).FullName
                , new CodeAttributeArgument(new CodePrimitiveExpression(spriteSheetName))
                );

            /// Add attribute.
            spriteSheetClass.CustomAttributes.Add(attribute);

            /// Array of expressions which create rectangles.
            CodeExpression[] createRectangles = new CodeExpression[rectangles.Length];

            for (int i = 0; i < rectangles.Length; i++)
            {
                /// One rectangle
                /// new Rectangle(X, Y, Width, Height);
                CodeExpression rectangle = new CodeObjectCreateExpression(typeof(Xna.Rectangle)
                                                                          , new CodePrimitiveExpression(rectangles[i].X)
                                                                          , new CodePrimitiveExpression(rectangles[i].Y)
                                                                          , new CodePrimitiveExpression(rectangles[i].Width)
                                                                          , new CodePrimitiveExpression(rectangles[i].Height)
                                                                          );

                createRectangles[i] = rectangle;
            }

            /// Array of rectangles.
            /// new Rectangles[rectangles.Length] { <param name="rectangles"></param> };
            CodeArrayCreateExpression createArray = new CodeArrayCreateExpression(
                new CodeTypeReference(typeof(Xna.Rectangle))
                , createRectangles);


            /// private static field with array of <see cref="Xna.Rectangle"/> which called Frames.
            CodeMemberField frames = new CodeMemberField()
            {
                Attributes       = MemberAttributes.Private | MemberAttributes.Static | MemberAttributes.Final
                , Type           = new CodeTypeReference(typeof(Xna.Rectangle[]))
                , Name           = "Frames"
                , InitExpression = createArray
            };

            /// Length property,
            /// only one getter which return number of rectangles in Frames field.
            CodeMemberProperty length = new CodeMemberProperty()
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Final
                , Type     = new CodeTypeReference(typeof(int))
                , Name     = "Length"
                , HasGet   = true
            };

            /// Expression which return number of rectangles.
            CodeMethodReturnStatement retn =
                new CodeMethodReturnStatement(new CodePrimitiveExpression(rectangles.Length));

            /// Add return expression to length getter.
            length.GetStatements.Add(retn);

            /// Indexer.
            /// I don't know why, but it's only way to create indexer.
            /// Ya, we MUST create PROPERTY which called "Item", not "item" or "indexer" or somthing else,
            /// just f*****g "Item".
            /// And after thar, we MUST add declaration of variable to PROPERTY parameters.
            /// Microsoft what the f**k?
            /// Documentation says we should use <see cref="CodeIndexerExpression"/>,
            /// but it's not work.
            /// Anyway, I found ONE post from 2003 with correct example
            /// source: https://forums.asp.net/post/354445.aspx
            /// thanks man, this is gonna suck when your post will be deleted.
            CodeMemberProperty indexer = new CodeMemberProperty()
            {
                Attributes = MemberAttributes.Public | MemberAttributes.Final
                , Type     = new CodeTypeReference(typeof(Xna.Rectangle))
                , Name     = "Item"
                , HasGet   = true
            };

            /// Declaration of variable.
            /// int index
            CodeParameterDeclarationExpression index =
                new CodeParameterDeclarationExpression(
                    new CodeTypeReference(typeof(int))
                    , "index"
                    );

            /// Magic continues.
            indexer.Parameters.Add(index);

            /// Create getter.
            /// get { return Frames[index]; }
            indexer.GetStatements.Add(new CodeMethodReturnStatement(
                                          new CodeArrayIndexerExpression(
                                              new CodeVariableReferenceExpression("Frames")
                                              , new CodeVariableReferenceExpression("index"))
                                          ));

            /// Add Frames field, Length property, and indexer to the class.
            spriteSheetClass.Members.Add(frames);
            spriteSheetClass.Members.Add(length);
            spriteSheetClass.Members.Add(indexer);

            return(spriteSheetClass);
        }
        /// <summary>
        /// Create atlas,
        /// and generate .dll or(and) source code
        /// with classes which contains rectangles.
        /// </summary>
        public static void Pack(IPackOptions opt)
        {
            if (opt.Sprites.Length == 0 && opt.Tiles.Length == 0)
            {
                throw new ApplicationException("Nothing to pack here.");
            }

            /// Delete previous atlas.
            File.Delete(Path.Combine(opt.Output, String.Concat(opt.Name, ".png")));

            /// Paths to all dirs.
            var allDirs = opt.Sprites.Concat(opt.Tiles);
            /// Paths to all images.
            var images = new List <string>();

            foreach (var dir in allDirs)
            {
                var dirInfo = new DirectoryInfo(dir);
                images.AddRange(Walkthrough.GetPictures(dirInfo).Select(file => file.FullName));
            }

            /// Find same paths.
            var groups = images.GroupBy(name => name).Where(group => group.Count() != 1);

            if (groups.Count() != 0)
            {
                throw new ApplicationException(
                          "Found nested paths. Check input parameters."
                          );
            }

            /// Packer from sspack.
            var imagePacker = new sspack.ImagePacker();

            /// Create sprite and dictionary.
            /// map - Dictionary: full filename -> rectangle in output image.
            /// imageBitmap - Texture atlas.
            imagePacker.PackImage(
                images
                , opt.PowerOfTwo
                , opt.Square
                , opt.MaxWidth
                , opt.MaxHeight
                , opt.Padding
                , true  /// Generate dictionary,
                , out var imageBitmap
                , out var map
                );


            var codeUnit = new CodeCompileUnit();

            var codeNameSpace = new CodeNamespace("NutPacker.Content");

            codeUnit.Namespaces.Add(codeNameSpace);

            /// Generate code.
            if (opt.Sprites.Length != 0)
            {
                foreach (var sprites in opt.Sprites)
                {
                    var spritesDirectory = new DirectoryInfo(sprites);

                    codeNameSpace.Types.Add(Walkthrough.GenerateSpriteCodeDom(spritesDirectory, map));
                }
            }
            if (opt.Tiles.Length != 0)
            {
                foreach (var pics in opt.Tiles)
                {
                    var picturesDirectory = new DirectoryInfo(pics);

                    codeNameSpace.Types.Add(Walkthrough.GenerateTileCodeDom(picturesDirectory, map));
                }
            }

            var codeDomProvider  = CodeDomProvider.CreateProvider("CSharp");
            var generatorOptions = new CodeGeneratorOptions {
                BracingStyle = "C"
                , BlankLinesBetweenMembers = false
                , VerbatimOrder            = true
            };

            /// Create file with source code.
            if (opt.GenerateSource)
            {
                using (var sourceWriter =
                           new StreamWriter(Path.Combine(opt.Output, String.Concat(Walkthrough.VariableName(opt.Name), ".cs")))) {
                    codeDomProvider.GenerateCodeFromCompileUnit(
                        codeUnit
                        , sourceWriter
                        , generatorOptions);
                }
            }


            var assemblyNames = new string[] {
                "NutPackerLib.dll"
                , "MonoGame.Framework.dll"
                , "System.Runtime.dll"
            };

            CompilerParameters cp;

            if (opt.GenerateLib)
            {
                cp = new CompilerParameters(
                    assemblyNames
                    , Path.Combine(opt.Output, String.Concat(Walkthrough.VariableName(opt.Name), ".dll"))
                    , false
                    )
                {
                    GenerateInMemory = false
                };
            }
            else
            {
                cp = new CompilerParameters(assemblyNames)
                {
                    GenerateInMemory = true
                };
            }

            /// Compile the CodeDom.
            var compile = codeDomProvider.CompileAssemblyFromDom(cp, codeUnit);

            /// Print errors.
            foreach (var e in compile.Errors)
            {
                Console.Error.WriteLine(e.ToString());
            }

            /// If no error - save the sprite.
            if (compile.Errors.Count == 0)
            {
                using (var streamWriter =
                           new StreamWriter(Path.Combine(opt.Output, String.Concat(Walkthrough.VariableName(opt.Name), ".png")))) {
                    imageBitmap.Save(
                        streamWriter.BaseStream
                        , System.Drawing.Imaging.ImageFormat.Png
                        );
                }
            }
        }