Example #1
0
            public bool AttemptResize(int width, int height, Textures.Group group, int extraBorder, bool pregms2_2_2)
            {
                Resize(width, height);

                foreach (var item in Items)
                {
                    if (!Place(group, item.TextureItem, extraBorder, pregms2_2_2, out _, out _))
                    {
                        return(false);
                    }
                }

                return(true);
            }
Example #2
0
        // Assumes all texture items on this group are already set up as they're desired to be
        // (i.e., everything is already cropped and de-duplicated, which is out of the scope of this function)
        public static List <Page> Pack(Textures.Group group, GMData data, int maxTextureWidth = 2048, int maxTextureHeight = 2048)
        {
            List <Page> result = new List <Page>();

            bool pregms2_2_2 = !data.VersionInfo.IsNumberAtLeast(2, 2, 2);
            int  extraBorder = data.VersionInfo.IsNumberAtLeast(2) ? 1 : 2;

            // Sort entries by area, largest to smallest
            List <GMTextureItem> entries = group.Items.OrderByDescending((entry) => entry.SourceWidth * entry.SourceHeight).ToList();

            // Place every texture item on pages in that order
            List <GMTextureItem> duplicates = new List <GMTextureItem>(64);

            foreach (var entry in entries)
            {
                if (entry._DuplicateOf != null)
                {
                    duplicates.Add(entry);
                    continue; // this is a duplicate of another entry; this will be figured out later
                }

                int  x = -1, y = -1;
                Page targetPage = null;

                // Try placing on each page in order until we find one that the entry fits on
                foreach (Page page in result)
                {
                    if (page.Place(group, entry, extraBorder, pregms2_2_2, out x, out y))
                    {
                        targetPage = page;
                        break;
                    }
                }

                if (targetPage == null)
                {
                    // Make a new page and place this entry on that one
                    targetPage = new Page(maxTextureWidth, maxTextureHeight);
                    result.Add(targetPage);
                    targetPage.Place(group, entry, extraBorder, pregms2_2_2, out x, out y);
                }

                if (x == -1)
                {
                    // Failed to pack!
                    return(null);
                }

                entry._PackItem = new Page.Item(x, y, targetPage, entry);
            }

            // Now try to shrink each page
            foreach (var page in result)
            {
                int w = page.Width, h = page.Height;
                int originalWidth = w, originalHeight = h;
                while (w != 1 || h != 1)
                {
                    if (page.AttemptResize(w / 2, h / 2, group, extraBorder, pregms2_2_2))
                    {
                        // Successful, so halve the size
                        w /= 2;
                        h /= 2;
                    }
                    else
                    {
                        // Unsuccessful, try each direction, then stop
                        if (page.AttemptResize(w / 2, h, group, extraBorder, pregms2_2_2))
                        {
                            w /= 2;
                        }
                        else if (page.AttemptResize(w, h / 2, group, extraBorder, pregms2_2_2))
                        {
                            h /= 2;
                        }
                        break;
                    }
                }

                // We now have the final width/height
                page.Resize(w, h);
                if (w != originalWidth || h != originalHeight)
                {
                    // ...and it changed, so now we have to pack again for real
                    foreach (var item in page.Items)
                    {
                        page.Place(group, item.TextureItem, extraBorder, pregms2_2_2, out item.X, out item.Y);
                    }
                }
            }

            // Now process the duplicates
            foreach (var entry in duplicates)
            {
                var target = entry._DuplicateOf;
                while (target._DuplicateOf != null)
                {
                    target = target._DuplicateOf;
                }
                entry._PackItem = new Page.Item(target._PackItem.X, target._PackItem.Y, target._PackItem.TargetPage, entry);
            }

            return(result);
        }
Example #3
0
            public bool Place(Textures.Group group, GMTextureItem entry, int extraBorder, bool pregms2_2_2, out int x, out int y)
            {
                int gap = group.Border;

                if (entry._HasExtraBorder)
                {
                    gap += extraBorder;
                }

                int  width = entry.SourceWidth, height = entry.SourceHeight;
                bool addX = false, addY = false;

                if (pregms2_2_2)
                {
                    // Before 2.2.2
                    if (width + (gap * 2) < Width)
                    {
                        width = (width + (gap * 2) + 3) & -4;
                        addX  = true;
                    }
                    if (height + (gap * 2) < Height)
                    {
                        height = (height + (gap * 2) + 3) & -4;
                        addY   = true;
                    }
                }
                else
                {
                    // After 2.2.2
                    if (width != Width)
                    {
                        width += gap * 2;
                        addX   = true;
                    }
                    if (height != Height)
                    {
                        height += gap * 2;
                        addY    = true;
                    }
                }

                Rect rect = MainRect.FindSpace(width, height);

                if (rect != null)
                {
                    MainRect.Place(rect, width, height, out x, out y);
                    if (addX)
                    {
                        x += gap;
                    }
                    if (addY)
                    {
                        y += gap;
                    }
                    return(true);
                }

                x = -1;
                y = -1;
                return(false);
            }