Example #1
0
 public ImageAreaInAtlas(ImageAreaInAtlas im)
 {
     imgId = im.imgId;
     w     = im.w;
     h     = im.h;
     x     = im.x;
     y     = im.y;
 }
Example #2
0
        /*
         * Packed rects may exceed atlas size and require scaling
         * When scaling want pixel perfect fit in atlas. Corners of rects should exactly align with pixel grid
         * Padding should be subtracted from pixel perfect rect to create pixel perfect square
         * TODO this doesn't handle each rectangle having different padding
         */
        internal bool ScaleAtlasToFitMaxDim(Vector2 rootWH, List <ImageAreaInAtlas> images, int maxDimensionX, int maxDimensionY, AtlasPadding padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY,
                                            ref int outW, ref int outH, out float padX, out float padY, out int newMinSizeX, out int newMinSizeY)
        {
            newMinSizeX = minImageSizeX;
            newMinSizeY = minImageSizeY;
            bool redoPacking = false;

            // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit
            padX = (float)padding.leftRight / (float)outW; //padding needs to be pixel perfect in size
            if (rootWH.x > maxDimensionX)
            {
                padX = (float)padding.leftRight / (float)maxDimensionX;
                float scaleFactor = (float)maxDimensionX / (float)rootWH.x;
                Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor);
                for (int i = 0; i < images.Count; i++)
                {
                    ImageAreaInAtlas im = images[i];
                    if (im.w * scaleFactor < masterImageSizeX)
                    { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size
                        Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeX.");
                        redoPacking = true;
                        newMinSizeX = Mathf.CeilToInt(minImageSizeX / scaleFactor);
                    }
                    int right = (int)((im.x + im.w) * scaleFactor);
                    im.x = (int)(scaleFactor * im.x);
                    im.w = right - im.x;
                }
                outW = maxDimensionX;
            }

            padY = (float)padding.topBottom / (float)outH;
            if (rootWH.y > maxDimensionY)
            {
                //float minSizeY = ((float)minImageSizeY + 1) / maxDimension;
                padY = (float)padding.topBottom / (float)maxDimensionY;
                float scaleFactor = (float)maxDimensionY / (float)rootWH.y;
                Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor);
                for (int i = 0; i < images.Count; i++)
                {
                    ImageAreaInAtlas im = images[i];
                    if (im.h * scaleFactor < masterImageSizeY)
                    { //check if small images will be rounded too small. If so need to redo packing forcing a larger min size
                        Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeY.");
                        redoPacking = true;
                        newMinSizeY = Mathf.CeilToInt(minImageSizeY / scaleFactor);
                    }
                    int bottom = (int)((im.y + im.h) * scaleFactor);
                    im.y = (int)(scaleFactor * im.y);
                    im.h = bottom - im.y;
                }
                outH = maxDimensionY;
            }
            return(redoPacking);
        }
Example #3
0
        ImageAreaInAtlas PopLargestThatFits(List <ImageAreaInAtlas> images, int spaceRemaining, int maxDim, bool emptyAtlas)
        {
            //pop single images larger than maxdim into their own atlas
            int imageDim;

            if (images.Count == 0)
            {
                return(null);
            }

            if (packingOrientation == TexturePackingOrientation.vertical)
            {
                imageDim = images[0].w;
            }
            else
            {
                imageDim = images[0].h;
            }
            if (images.Count > 0 && imageDim >= maxDim)
            {
                if (emptyAtlas)
                {
                    ImageAreaInAtlas im = images[0];
                    images.RemoveAt(0);
                    return(im);
                }
                else
                {
                    return(null);
                }
            }

            // now look for images that will fit
            int i = 0;

            while (i < images.Count && imageDim >= spaceRemaining)
            {
                i++;
            }
            if (i < images.Count)
            {
                ImageAreaInAtlas im = images[i];
                images.RemoveAt(i);
                return(im);
            }
            else
            {
                return(null);
            }
        }
Example #4
0
            internal AtalsAreaNode Insert(ImageAreaInAtlas im, bool handed)
            {
                int a, b;

                if (handed)
                {
                    a = 0;
                    b = 1;
                }
                else
                {
                    a = 1;
                    b = 0;
                }
                if (!isLeaf())
                {   //不是叶
                    //try insert into first child
                    AtalsAreaNode newNode = child[a].Insert(im, handed);
                    if (newNode != null)
                    {
                        return(newNode);
                    }
                    //no room insert into second
                    return(child[b].Insert(im, handed));
                }
                else
                {
                    //(if there's already a img here, return)
                    if (img != null)
                    {
                        return(null);
                    }

                    //(if space too small, return)
                    if (nodeAreaRect.w < im.w || nodeAreaRect.h < im.h)
                    {
                        return(null);
                    }

                    //(if space just right, accept)
                    if (nodeAreaRect.w == im.w && nodeAreaRect.h == im.h)
                    {
                        img = im;
                        return(this);
                    }

                    //拆分此节点并创建两个分支
                    child[a] = new AtalsAreaNode(NodeType.regular);
                    child[b] = new AtalsAreaNode(NodeType.regular);

                    //(decide which way to split)
                    int dw = nodeAreaRect.w - im.w;
                    int dh = nodeAreaRect.h - im.h;

                    if (dw > dh)
                    {
                        child[a].nodeAreaRect = new AtalsAreaPixRect(nodeAreaRect.x, nodeAreaRect.y, im.w, nodeAreaRect.h);
                        child[b].nodeAreaRect = new AtalsAreaPixRect(nodeAreaRect.x + im.w, nodeAreaRect.y, nodeAreaRect.w - im.w, nodeAreaRect.h);
                    }
                    else
                    {
                        child[a].nodeAreaRect = new AtalsAreaPixRect(nodeAreaRect.x, nodeAreaRect.y, nodeAreaRect.w, im.h);
                        child[b].nodeAreaRect = new AtalsAreaPixRect(nodeAreaRect.x, nodeAreaRect.y + im.h, nodeAreaRect.w, nodeAreaRect.h - im.h);
                    }
                    return(child[a].Insert(im, handed));
                }
            }
Example #5
0
        //----------------- Algorithm for fitting everything into multiple Atlases
        //
        // for images being added calc area, maxW, maxH. A perfectly packed atlas will match area exactly. atlas must be at least maxH and maxW in size.
        // Sort images from big to small using either height, width or area comparer
        //
        // If an image is bigger than maxDim, then shrink it to max size on the largest dimension
        // distribute images using the new algorithm, should never have to expand the atlas instead create new atlases as needed
        // should not need to scale atlases
        //
        AtlasPackingResult[] _GetRectsMultiAtlas(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionPassedX, int maxDimensionPassedY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY)
        {
            Debug.Log(String.Format("_GetRects numImages={0}, maxDimensionX={1}, maxDimensionY={2} minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}",
                                    imgWidthHeights.Count, maxDimensionPassedX, maxDimensionPassedY, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY));
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            ImageAreaInAtlas[] imgsToAdd = new ImageAreaInAtlas[imgWidthHeights.Count];
            int maxDimensionX            = maxDimensionPassedX;
            int maxDimensionY            = maxDimensionPassedY;

            if (atlasMustBePowerOfTwo)
            {
                maxDimensionX = RoundToNearestPositivePowerOfTwo(maxDimensionX);
                maxDimensionY = RoundToNearestPositivePowerOfTwo(maxDimensionY);
            }
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int iw = (int)imgWidthHeights[i].x;
                int ih = (int)imgWidthHeights[i].y;

                //shrink the image so that it fits in maxDimenion if it is larger than maxDimension if atlas exceeds maxDim x maxDim then new alas will be created
                iw = Mathf.Min(iw, maxDimensionX - paddings[i].leftRight * 2);
                ih = Mathf.Min(ih, maxDimensionY - paddings[i].topBottom * 2);

                ImageAreaInAtlas im = imgsToAdd[i] = new ImageAreaInAtlas(i, iw, ih, paddings[i], minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            //explore the space to find a resonably efficient packing
            //int sqrtArea = (int)Mathf.Sqrt(area);
            int idealAtlasW;
            int idealAtlasH;

            if (atlasMustBePowerOfTwo)
            {
                idealAtlasH = RoundToNearestPositivePowerOfTwo(maxDimensionY);
                idealAtlasW = RoundToNearestPositivePowerOfTwo(maxDimensionX);
            }
            else
            {
                idealAtlasH = maxDimensionY;
                idealAtlasW = maxDimensionX;
            }

            if (idealAtlasW == 0)
            {
                idealAtlasW = 4;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 4;
            }

            ProbeResult pr = new ProbeResult();

            Array.Sort(imgsToAdd, new ImageHeightComparer());
            if (ProbeMultiAtlas(imgsToAdd, idealAtlasW, idealAtlasH, area, maxDimensionX, maxDimensionY, pr))
            {
                bestRoot = pr;
            }
            Array.Sort(imgsToAdd, new ImageWidthComparer());
            if (ProbeMultiAtlas(imgsToAdd, idealAtlasW, idealAtlasH, area, maxDimensionX, maxDimensionY, pr))
            {
                if (pr.totalAtlasArea < bestRoot.totalAtlasArea)
                {
                    bestRoot = pr;
                }
            }
            Array.Sort(imgsToAdd, new ImageAreaComparer());
            if (ProbeMultiAtlas(imgsToAdd, idealAtlasW, idealAtlasH, area, maxDimensionX, maxDimensionY, pr))
            {
                if (pr.totalAtlasArea < bestRoot.totalAtlasArea)
                {
                    bestRoot = pr;
                }
            }

            if (bestRoot == null)
            {
                return(null);
            }
            Debug.Log("Best fit found: w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.largerOrEqualToMaxDim);

            //the atlas can be larger than the max dimension scale it if this is the case
            //int newMinSizeX = minImageSizeX;
            //int newMinSizeY = minImageSizeY;
            List <AtlasPackingResult> rs = new List <AtlasPackingResult>();

            // find all Nodes that are an individual atlas
            List <AtalsAreaNode>  atlasNodes = new List <AtalsAreaNode>();
            Stack <AtalsAreaNode> stack      = new Stack <AtalsAreaNode>();
            AtalsAreaNode         node       = bestRoot.root;

            while (node != null)
            {
                stack.Push(node);
                node = node.child[0];
            }

            // traverse the tree collecting atlasNodes
            while (stack.Count > 0)
            {
                node = stack.Pop();
                if (node.isFullAtlas == NodeType.maxDim)
                {
                    atlasNodes.Add(node);
                }
                if (node.child[1] != null)
                {
                    node = node.child[1];
                    while (node != null)
                    {
                        stack.Push(node);
                        node = node.child[0];
                    }
                }
            }

            //pack atlases so they all fit
            for (int i = 0; i < atlasNodes.Count; i++)
            {
                List <ImageAreaInAtlas> images = new List <ImageAreaInAtlas>();
                flattenTree(atlasNodes[i], images);
                Rect[] rss       = new Rect[images.Count];
                int[]  srcImgIdx = new int[images.Count];
                for (int j = 0; j < images.Count; j++)
                {
                    rss[j]       = (new Rect(images[j].x - atlasNodes[i].nodeAreaRect.x, images[j].y, images[j].w, images[j].h));
                    srcImgIdx[j] = images[j].imgId;
                }
                AtlasPackingResult res = new AtlasPackingResult(paddings.ToArray());
                GetExtent(atlasNodes[i], ref res.usedW, ref res.usedH);
                res.usedW -= atlasNodes[i].nodeAreaRect.x;
                int outW = atlasNodes[i].nodeAreaRect.w;
                int outH = atlasNodes[i].nodeAreaRect.h;
                if (atlasMustBePowerOfTwo)
                {
                    outW = Mathf.Min(CeilToNearestPowerOfTwo(res.usedW), atlasNodes[i].nodeAreaRect.w);
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(res.usedH), atlasNodes[i].nodeAreaRect.h);
                    if (outH < outW / 2)
                    {
                        outH = outW / 2;                  //smaller dim can't be less than half larger
                    }
                    if (outW < outH / 2)
                    {
                        outW = outH / 2;
                    }
                }
                else
                {
                    outW = res.usedW;
                    outH = res.usedH;
                }

                res.atlasY = outH;
                res.atlasX = outW;

                res.rects      = rss;
                res.srcImgIdxs = srcImgIdx;
                res.CalcUsedWidthAndHeight();
                rs.Add(res);
                normalizeRects(res, paddings[i]);
                Debug.Log(String.Format("Done GetRects "));
            }

            return(rs.ToArray());
        }
Example #6
0
        //------------------ Algorithm for fitting everything into one atlas and scaling down
        //
        // for images being added calc area, maxW, maxH. A perfectly packed atlas will match area exactly. atlas must be at least maxH and maxW in size.
        // Sort images from big to small using either height, width or area comparer
        // Explore space to find a resonably efficient packing. Grow the atlas gradually until a fit is found
        // Scale atlas to fit
        //
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights,
                                                List <AtlasPadding> paddings,
                                                int maxDimensionX,
                                                int maxDimensionY,
                                                int minImageSizeX,
                                                int minImageSizeY,
                                                int masterImageSizeX,
                                                int masterImageSizeY,
                                                int recursionDepth)
        {
            Debug.Log(string.Format("_GetRects 图片数量 ={0}, 最大尺寸X ={1}, 最小尺寸 X={2}, 最小尺寸 Y ={3}, masterImageSizeX={4}, masterImageSizeY={5}, 递归深度 = {6}",
                                    imgWidthHeights.Count, maxDimensionX, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            if (recursionDepth > 10)
            {
                //最大递归深度设定为 10
                Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
                return(null);
            }
            float allImageTotalArea = 0;
            int   maxW = 0;
            int   maxH = 0;

            ImageAreaInAtlas[] imgsToAdd = new ImageAreaInAtlas[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int iw = (int)imgWidthHeights[i].x;
                int ih = (int)imgWidthHeights[i].y;

                ImageAreaInAtlas im = imgsToAdd[i] = new ImageAreaInAtlas(i, iw, ih, paddings[i], minImageSizeX, minImageSizeY);
                allImageTotalArea += im.w * im.h;
                maxW = Mathf.Max(maxW, im.w);
                maxH = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

            //explore the space to find a resonably efficient packing
            //探索图片空间以找到合理有效的包装
            int sqrtArea = (int)Mathf.Sqrt(allImageTotalArea);
            int idealAtlasW;
            int idealAtlasH;

            if (atlasMustBePowerOfTwo)
            {
                idealAtlasW = idealAtlasH = RoundToNearestPositivePowerOfTwo(sqrtArea);
                if (maxW > idealAtlasW)
                {
                    idealAtlasW = CeilToNearestPowerOfTwo(idealAtlasW);
                }
                if (maxH > idealAtlasH)
                {
                    idealAtlasH = CeilToNearestPowerOfTwo(idealAtlasH);
                }
            }
            else
            {
                idealAtlasW = sqrtArea;
                idealAtlasH = sqrtArea;
                if (maxW > sqrtArea)
                {
                    idealAtlasW = maxW;
                    idealAtlasH = Mathf.Max(Mathf.CeilToInt(allImageTotalArea / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(allImageTotalArea / maxH), maxW);
                    idealAtlasH = maxH;
                }
            }

            if (idealAtlasW == 0)
            {
                idealAtlasW = 4;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 4;
            }
            int stepW = (int)(idealAtlasW * .15f);
            int stepH = (int)(idealAtlasH * .15f);

            if (stepW == 0)
            {
                stepW = 1;
            }
            if (stepH == 0)
            {
                stepH = 1;
            }
            int numWIterations = 2;
            int steppedWidth   = idealAtlasW;
            int steppedHeight  = idealAtlasH;

            while (numWIterations >= 1 && steppedHeight < sqrtArea * 1000)
            {
                bool successW = false;
                numWIterations = 0;
                steppedWidth   = idealAtlasW;
                while (!successW && steppedWidth < sqrtArea * 1000)
                {
                    ProbeResult pr = new ProbeResult();
                    Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);

                    if (ProbeSingleAtlas(imgsToAdd, steppedWidth, steppedHeight, allImageTotalArea, maxDimensionX, maxDimensionY, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(atlasMustBePowerOfTwo) > bestRoot.GetScore(atlasMustBePowerOfTwo))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = SetStepWidthHeight(steppedWidth, stepW, maxDimensionX);
                        Debug.Log("增加 Width h=" + steppedHeight + " w=" + steppedWidth);
                    }
                }
                steppedHeight = SetStepWidthHeight(steppedHeight, stepH, maxDimensionY);
                Debug.Log("增加 Height h=" + steppedHeight + " w=" + steppedWidth);
            }
            if (bestRoot == null)
            {
                return(null);
            }

            int outW = 0;
            int outH = 0;

            if (atlasMustBePowerOfTwo)
            {
                outW = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.w), maxDimensionX);
                outH = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.h), maxDimensionY);
                if (outH < outW / 2)
                {
                    outH = outW / 2;                  //smaller dim can't be less than half larger
                }
                if (outW < outH / 2)
                {
                    outW = outH / 2;
                }
            }
            else
            {
                outW = Mathf.Min(bestRoot.w, maxDimensionX);
                outH = Mathf.Min(bestRoot.h, maxDimensionY);
            }

            bestRoot.outW = outW;
            bestRoot.outH = outH;
            Debug.Log("Best fit found: atlasW=" + outW +
                      " atlasH" + outH +
                      " w=" + bestRoot.w +
                      " h=" + bestRoot.h +
                      " efficiency=" + bestRoot.efficiency +
                      " squareness=" + bestRoot.squareness +
                      " fits in max dimension=" + bestRoot.largerOrEqualToMaxDim);

            //Debug.Assert(images.Count != imgsToAdd.Length, "Result images not the same lentgh as source"));

            //the atlas can be larger than the max dimension scale it if this is the case
            //int newMinSizeX = minImageSizeX;
            //int	newMinSizeY = minImageSizeY;


            List <ImageAreaInAtlas> images = new List <ImageAreaInAtlas>();

            flattenTree(bestRoot.root, images);
            images.Sort(new ImgIDComparer());
            // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit
            Vector2 rootWH = new Vector2(bestRoot.w, bestRoot.h);
            float   padX, padY;
            int     newMinSizeX, newMinSizeY;

            if (!ScaleAtlasToFitMaxDim(rootWH, images, maxDimensionX, maxDimensionY, paddings[0], minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                       ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY))
            {
                AtlasPackingResult res = new AtlasPackingResult(paddings.ToArray());
                res.rects      = new Rect[images.Count];
                res.srcImgIdxs = new int[images.Count];
                res.atlasX     = outW;
                res.atlasY     = outH;
                res.usedW      = -1;
                res.usedH      = -1;
                for (int i = 0; i < images.Count; i++)
                {
                    ImageAreaInAtlas im = images[i];
                    Rect             r  = res.rects[i] = new Rect((float)im.x / (float)outW + padX,
                                                                  (float)im.y / (float)outH + padY,
                                                                  (float)im.w / (float)outW - padX * 2f,
                                                                  (float)im.h / (float)outH - padY * 2f);
                    res.srcImgIdxs[i] = im.imgId;
                    Debug.Log("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                              " y=" + r.y * outH + " w=" + r.width * outW +
                              " h=" + r.height * outH + " padding=" + paddings[i]);
                }
                res.CalcUsedWidthAndHeight();
                return(res);
            }
            else
            {
                Debug.Log("==================== REDOING PACKING ================");
                //root = null;
                return(_GetRectsSingleAtlas(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, recursionDepth + 1));
            }


            //Debug.Log(String.Format("Done GetRects atlasW={0} atlasH={1}", bestRoot.w, bestRoot.h));

            //return res;
        }
Example #7
0
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionX, int maxDimensionY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            AtlasPackingResult res = new AtlasPackingResult(paddings.ToArray());

            List <Rect>             rects  = new List <Rect>();
            int                     extent = 0;
            int                     maxh   = 0;
            int                     maxw   = 0;
            List <ImageAreaInAtlas> images = new List <ImageAreaInAtlas>();

            Debug.Log("Packing rects for: " + imgWidthHeights.Count);
            for (int i = 0; i < imgWidthHeights.Count; i++)
            {
                ImageAreaInAtlas im = new ImageAreaInAtlas(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, paddings[i], minImageSizeX, minImageSizeY);

                // if images are stacked horizontally then there is no padding at the top or bottom
                if (packingOrientation == TexturePackingOrientation.vertical)
                {
                    im.h -= paddings[i].topBottom * 2;
                    im.x  = extent;
                    im.y  = 0;
                    rects.Add(new Rect(im.w, im.h, extent, 0));
                    extent += im.w;
                    maxh    = Mathf.Max(maxh, im.h);
                }
                else
                {
                    im.w -= paddings[i].leftRight * 2;
                    im.y  = extent;
                    im.x  = 0;
                    rects.Add(new Rect(im.w, im.h, 0, extent));
                    extent += im.h;
                    maxw    = Mathf.Max(maxw, im.w);
                }
                images.Add(im);
            }
            //scale atlas to fit maxDimension
            Vector2 rootWH;

            if (packingOrientation == TexturePackingOrientation.vertical)
            {
                rootWH = new Vector2(extent, maxh);
            }
            else
            {
                rootWH = new Vector2(maxw, extent);
            }
            int outW = (int)rootWH.x;
            int outH = (int)rootWH.y;

            if (packingOrientation == TexturePackingOrientation.vertical)
            {
                if (atlasMustBePowerOfTwo)
                {
                    outW = Mathf.Min(CeilToNearestPowerOfTwo(outW), maxDimensionX);
                }
                else
                {
                    outW = Mathf.Min(outW, maxDimensionX);
                }
            }
            else
            {
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimensionY);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimensionY);
                }
            }

            float padX, padY;
            int   newMinSizeX, newMinSizeY;

            if (!ScaleAtlasToFitMaxDim(rootWH, images, maxDimensionX, maxDimensionY, paddings[0], minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                       ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY))
            {
                res            = new AtlasPackingResult(paddings.ToArray());
                res.rects      = new Rect[images.Count];
                res.srcImgIdxs = new int[images.Count];
                res.atlasX     = outW;
                res.atlasY     = outH;
                for (int i = 0; i < images.Count; i++)
                {
                    ImageAreaInAtlas im = images[i];
                    Rect             r;
                    if (packingOrientation == TexturePackingOrientation.vertical)
                    {
                        r = res.rects[i] = new Rect((float)im.x / (float)outW + padX,
                                                    (float)im.y / (float)outH,
                                                    (float)im.w / (float)outW - padX * 2f,
                                                    stretchImagesToEdges ? 1f : (float)im.h / (float)outH);          // all images are stretched to fill the height
                    }
                    else
                    {
                        r = res.rects[i] = new Rect((float)im.x / (float)outW,
                                                    (float)im.y / (float)outH + padY,
                                                    (stretchImagesToEdges ? 1f : ((float)im.w / (float)outW)),
                                                    (float)im.h / (float)outH - padY * 2f);          // all images are stretched to fill the height
                    }
                    res.srcImgIdxs[i] = im.imgId;
                    Debug.Log("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                              " y=" + r.y * outH + " w=" + r.width * outW +
                              " h=" + r.height * outH + " padding=" + paddings[i] + " outW=" + outW + " outH=" + outH);
                }
                res.CalcUsedWidthAndHeight();
                return(res);
            }
            Debug.Log("Packing failed returning null atlas result");
            return(null);
        }
Example #8
0
        AtlasPackingResult[] _GetRectsMultiAtlasHorizontal(List <Vector2> imgWidthHeights, List <AtlasPadding> paddings, int maxDimensionPassedX, int maxDimensionPassedY, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY)
        {
            List <AtlasPackingResult> rs = new List <AtlasPackingResult>();
            int extent = 0;
            int maxh   = 0;
            int maxw   = 0;

            Debug.Log("Packing rects for: " + imgWidthHeights.Count);

            List <ImageAreaInAtlas> allImages = new List <ImageAreaInAtlas>();

            for (int i = 0; i < imgWidthHeights.Count; i++)
            {
                ImageAreaInAtlas im = new ImageAreaInAtlas(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, paddings[i], minImageSizeX, minImageSizeY);
                im.w -= paddings[i].leftRight * 2;
                allImages.Add(im);
            }
            allImages.Sort(new ImageHeightComparer());
            List <ImageAreaInAtlas> images = new List <ImageAreaInAtlas>();
            List <Rect>             rects  = new List <Rect>();
            int spaceRemaining             = maxDimensionPassedY;

            while (allImages.Count > 0 || images.Count > 0)
            {
                ImageAreaInAtlas im = PopLargestThatFits(allImages, spaceRemaining, maxDimensionPassedY, images.Count == 0);
                if (im == null)
                {
                    Debug.Log("Atlas filled creating a new atlas ");
                    AtlasPackingResult apr = new AtlasPackingResult(paddings.ToArray());
                    apr.atlasX = maxw;
                    apr.atlasY = maxh;
                    Rect[] rss       = new Rect[images.Count];
                    int[]  srcImgIdx = new int[images.Count];
                    for (int j = 0; j < images.Count; j++)
                    {
                        Rect r = new Rect(images[j].x, images[j].y,
                                          stretchImagesToEdges ? maxw : images[j].w,
                                          images[j].h);
                        rss[j]       = r;
                        srcImgIdx[j] = images[j].imgId;
                    }
                    apr.rects      = rss;
                    apr.srcImgIdxs = srcImgIdx;

                    images.Clear();
                    rects.Clear();
                    extent = 0;
                    maxh   = 0;
                    rs.Add(apr);
                    spaceRemaining = maxDimensionPassedY;
                }
                else
                {
                    im.x = 0;
                    im.y = extent;
                    images.Add(im);
                    rects.Add(new Rect(0, extent, im.w, im.h));
                    extent        += im.h;
                    maxw           = Mathf.Max(maxw, im.w);
                    maxh           = extent;
                    spaceRemaining = maxDimensionPassedY - extent;
                }
            }

            for (int i = 0; i < rs.Count; i++)
            {
                int outH = rs[i].atlasY;
                int outW = Mathf.Min(rs[i].atlasX, maxDimensionPassedX);
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimensionPassedY);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimensionPassedY);
                }
                rs[i].atlasY = outH;
                //-------------------------------
                //scale atlas to fit maxDimension
                float padX, padY;
                int   newMinSizeX, newMinSizeY;
                ScaleAtlasToFitMaxDim(new Vector2(rs[i].atlasX, rs[i].atlasY), images, maxDimensionPassedX, maxDimensionPassedY, paddings[0], minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                      ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY);
            }



            //normalize atlases so that that rects are 0 to 1
            for (int i = 0; i < rs.Count; i++)
            {
                normalizeRects(rs[i], paddings[i]);
                rs[i].CalcUsedWidthAndHeight();
            }
            //-----------------------------
            return(rs.ToArray());
        }