Vector2[] _getMeshUV2s(Mesh m)
 {
     Vector2[] uv = m.uv2;
     if (uv.Length == 0)
     {
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no uv2s. Generating");
         }
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have uv2s. Generating uv2s.");
         }
         if (this.mc._lightmapOption == MB2_LightmapOptions.copy_UV2_unchanged_to_separate_rects)
         {
             Debug.LogError("Mesh " + m + " did not have a UV2 channel. Nothing to copy when trying to copy UV2 to separate rects. The combined mesh will not lightmap properly. Try using generate new uv2 layout.");
         }
         uv = new Vector2[m.vertexCount];
         for (int i = 0; i < uv.Length; i++)
         {
             uv[i] = _HALF_UV;
         }
     }
     return(uv);
 }
Example #2
0
        public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource = true)
        {
            //Profile.Start//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects1");
            //PART 1 ==== Validate
            if (_usingTemporaryTextureBakeResult && gos != null && gos.Length > 0)
            {
                MB_Utility.Destroy(_textureBakeResults);
                _textureBakeResults = null;
                _usingTemporaryTextureBakeResult = false;
            }

            //if all objects use the same material we can create a temporary _textureBakeResults
            if (_textureBakeResults == null && gos != null && gos.Length > 0 && gos[0] != null)
            {
                if (!_CreateTemporaryTextrueBakeResult(gos, GetMaterialsOnTargetRenderer()))
                {
                    return(false);
                }
            }

            if (!_validate(gos, deleteGOinstanceIDs))
            {
                return(false);
            }
            _distributeAmongBakers(gos, deleteGOinstanceIDs);
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("MB2_MultiMeshCombiner.AddDeleteGameObjects numCombinedMeshes: " + meshCombiners.Count + " added:" + gos + " deleted:" + deleteGOinstanceIDs + " disableRendererInSource:" + disableRendererInSource + " maxVertsPerCombined:" + _maxVertsInMesh);
            }
            return(_bakeStep1(gos, deleteGOinstanceIDs, disableRendererInSource));
        }
Example #3
0
 public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource = true)
 {
     if (this._usingTemporaryTextureBakeResult && gos != null && gos.Length > 0)
     {
         MB_Utility.Destroy(this._textureBakeResults);
         this._textureBakeResults = null;
         this._usingTemporaryTextureBakeResult = false;
     }
     if (this._textureBakeResults == null && gos != null && gos.Length > 0 && gos[0] != null && !this._CheckIfAllObjsToAddUseSameMaterialsAndCreateTemporaryTextrueBakeResult(gos))
     {
         return(false);
     }
     if (!this._validate(gos, deleteGOinstanceIDs))
     {
         return(false);
     }
     this._distributeAmongBakers(gos, deleteGOinstanceIDs);
     if (this.LOG_LEVEL >= MB2_LogLevel.debug)
     {
         MB2_Log.LogDebug(string.Concat(new object[]
         {
             "MB2_MultiMeshCombiner.AddDeleteGameObjects numCombinedMeshes: ",
             this.meshCombiners.Count,
             " added:",
             gos,
             " deleted:",
             deleteGOinstanceIDs,
             " disableRendererInSource:",
             disableRendererInSource,
             " maxVertsPerCombined:",
             this._maxVertsInMesh
         }), new object[0]);
     }
     return(this._bakeStep1(gos, deleteGOinstanceIDs, disableRendererInSource));
 }
Example #4
0
 public Vector2[] GetMeshUV1s(Mesh m, MB2_LogLevel LOG_LEVEL)
 {
     Vector2[] uv;
                 #if (UNITY_4_6 || UNITY_4_7 || UNITY_4_5 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
     uv = m.uv1;
                 #else
     if (LOG_LEVEL >= MB2_LogLevel.warn)
     {
         MB2_Log.LogDebug("UV1 does not exist in Unity 5+");
     }
     uv = m.uv;
                 #endif
     if (uv.Length == 0)
     {
         if (LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no uv1s. Generating");
         }
         if (LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have uv1s. Generating uv1s.");
         }
         uv = new Vector2[m.vertexCount];
         for (int i = 0; i < uv.Length; i++)
         {
             uv[i] = _HALF_UV;
         }
     }
     return(uv);
 }
Example #5
0
        public Vector2[] GetMeshUV3orUV4(Mesh m, bool get3, MB2_LogLevel LOG_LEVEL)
        {
            Vector2[] uvs;
#if (UNITY_4_6 || UNITY_4_7 || UNITY_4_5 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5)
            if (LOG_LEVEL >= MB2_LogLevel.warn)
            {
                MB2_Log.LogDebug("UV3 and UV4 do not exist in Unity 4");
            }
            uvs = m.uv;
#else
            if (get3)
            {
                uvs = m.uv3;
            }
            else
            {
                uvs = m.uv4;
            }
#endif
            if (uvs.Length == 0)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Mesh " + m + " has no uv" + (get3 ? "3" : "4") + ". Generating");
                }
                uvs = new Vector2[m.vertexCount];
                for (int i = 0; i < uvs.Length; i++)
                {
                    uvs[i] = _HALF_UV;
                }
            }
            return(uvs);
        }
 Vector4[] _getMeshTangents(Mesh m)
 {
     Vector4[] ts = m.tangents;
     if (ts.Length == 0)
     {
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no tangents. Generating");
         }
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have tangents. Generating tangents.");
         }
         Vector3[] verts = m.vertices;
         Vector2[] uvs   = GetUv0Raw(m);
         Vector3[] norms = _getMeshNormals(m);
         ts = new Vector4[m.vertexCount];
         for (int i = 0; i < m.subMeshCount; i++)
         {
             int[] tris = m.GetTriangles(i);
             _generateTangents(tris, verts, uvs, norms, ts);
         }
     }
     return(ts);
 }
Example #7
0
 public Vector2[] GetMeshUV3orUV4(Mesh m, bool get3, MB2_LogLevel LOG_LEVEL)
 {
     Vector2[] array;
     if (get3)
     {
         array = m.uv3;
     }
     else
     {
         array = m.uv4;
     }
     if (array.Length == 0)
     {
         if (LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug(string.Concat(new object[]
             {
                 "Mesh ",
                 m,
                 " has no uv",
                 (!get3) ? "4" : "3",
                 ". Generating"
             }), new object[0]);
         }
         array = new Vector2[m.vertexCount];
         for (int i = 0; i < array.Length; i++)
         {
             array[i] = this._HALF_UV;
         }
     }
     return(array);
 }
Example #8
0
 public Vector2[] GetMeshUV1s(Mesh m, MB2_LogLevel LOG_LEVEL)
 {
     if (LOG_LEVEL >= MB2_LogLevel.warn)
     {
         MB2_Log.LogDebug("UV1 does not exist in Unity 5+", new object[0]);
     }
     Vector2[] array = m.uv;
     if (array.Length == 0)
     {
         if (LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no uv1s. Generating", new object[0]);
         }
         if (LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have uv1s. Generating uv1s.");
         }
         array = new Vector2[m.vertexCount];
         for (int i = 0; i < array.Length; i++)
         {
             array[i] = this._HALF_UV;
         }
     }
     return(array);
 }
        public Vector2[] GetMeshUVChannel(int channel, Mesh m, MB2_LogLevel LOG_LEVEL)
        {
            Vector2[] uvs = new Vector2[0];

            switch (channel)
            {
            case 0:
                uvs = m.uv;
                break;

            case 2:
                uvs = m.uv2;
                break;

            case 3:
                uvs = m.uv3;
                break;

            case 4:
                uvs = m.uv4;
                break;

#if UNITY_2018_2_OR_NEWER
            case 5:
                uvs = m.uv5;
                break;

            case 6:
                uvs = m.uv6;
                break;

            case 7:
                uvs = m.uv7;
                break;

            case 8:
                uvs = m.uv8;
                break;
#endif
            default:
                Debug.LogError("Mesh does not have UV channel " + channel);
                break;
            }

            if (uvs.Length == 0)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Mesh " + m + " has no uv" + channel + ". Generating");
                }
                uvs = new Vector2[m.vertexCount];
                for (int i = 0; i < uvs.Length; i++)
                {
                    uvs[i] = _HALF_UV;
                }
            }

            return(uvs);
        }
 public override bool AddDeleteGameObjectsByID(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource = true)
 {
     //Profile.Start//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects1");
     //PART 1 ==== Validate
     if (!_validate(gos, deleteGOinstanceIDs))
     {
         return(false);
     }
     _distributeAmongBakers(gos, deleteGOinstanceIDs);
     if (LOG_LEVEL >= MB2_LogLevel.debug)
     {
         MB2_Log.LogDebug("MB2_MultiMeshCombiner.AddDeleteGameObjects numCombinedMeshes: " + meshCombiners.Count + " added:" + gos + " deleted:" + deleteGOinstanceIDs + " disableRendererInSource:" + disableRendererInSource + " maxVertsPerCombined:" + _maxVertsInMesh);
     }
     return(_bakeStep1(gos, deleteGOinstanceIDs, disableRendererInSource));
 }
        bool ProbeMultiAtlas(Image[] imgsToAdd, int idealAtlasW, int idealAtlasH, float imgArea, int maxAtlasDimX, int maxAtlasDimY, ProbeResult pr)
        {
            int  numAtlases = 0;
            Node root       = new Node(NodeType.maxDim);

            root.r = new PixRect(0, 0, idealAtlasW, idealAtlasH);
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                Node n = root.Insert(imgsToAdd[i], false);
                if (n == null)
                {
                    if (imgsToAdd[i].x > idealAtlasW && imgsToAdd[i].y > idealAtlasH)
                    {
                        return(false);
                    }
                    else
                    {
                        // create a new root node wider than previous atlas
                        Node newRoot = new Node(NodeType.Container);
                        newRoot.r = new PixRect(0, 0, root.r.w + idealAtlasW, idealAtlasH);
                        // create a new right child
                        Node newRight = new Node(NodeType.maxDim);
                        newRight.r       = new PixRect(root.r.w, 0, idealAtlasW, idealAtlasH);
                        newRoot.child[1] = newRight;
                        // insert root as a new left child
                        newRoot.child[0] = root;
                        root             = newRoot;
                        n = root.Insert(imgsToAdd[i], false);
                        numAtlases++;
                    }
                }
            }
            pr.numAtlases = numAtlases;
            pr.root       = root;
            //todo atlas may not be maxDim * maxDim. Do some checking to see what actual needed sizes are and update pr.totalArea
            pr.totalAtlasArea = numAtlases * maxAtlasDimX * maxAtlasDimY;
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("Probe success efficiency numAtlases=" + numAtlases + " totalArea=" + pr.totalAtlasArea);
            }
            return(true);
        }
 Vector3[] _getMeshNormals(Mesh m)
 {
     Vector3[] ns = m.normals;
     if (ns.Length == 0)
     {
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no normals. Generating");
         }
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have normals. Generating normals.");
         }
         Mesh tempMesh = (Mesh)GameObject.Instantiate(m);
         tempMesh.RecalculateNormals();
         ns = tempMesh.normals;
         MB_Utility.Destroy(tempMesh);
     }
     return(ns);
 }
 Vector2[] _getMeshUVs(Mesh m)
 {
     Vector2[] uv = m.uv;
     if (uv.Length == 0)
     {
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no uvs. Generating");
         }
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have uvs. Generating uvs.");
         }
         uv = new Vector2[m.vertexCount];
         for (int i = 0; i < uv.Length; i++)
         {
             uv[i] = _HALF_UV;
         }
     }
     return(uv);
 }
 Color[] _getMeshColors(Mesh m)
 {
     Color[] cs = m.colors;
     if (cs.Length == 0)
     {
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.debug)
         {
             MB2_Log.LogDebug("Mesh " + m + " has no colors. Generating");
         }
         if (this.mc.LOG_LEVEL >= MB2_LogLevel.warn)
         {
             Debug.LogWarning("Mesh " + m + " didn't have colors. Generating an array of white colors");
         }
         cs = new Color[m.vertexCount];
         for (int i = 0; i < cs.Length; i++)
         {
             cs[i] = Color.white;
         }
     }
     return(cs);
 }
Example #15
0
        bool Probe(Image[] imgsToAdd, int idealAtlasW, int idealAtlasH, float imgArea, int maxAtlasDim, ProbeResult pr)
        {
            Node root = new Node();

            root.r = new PixRect(0, 0, idealAtlasW, idealAtlasH);
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                Node n = root.Insert(imgsToAdd[i], false);
                if (n == null)
                {
                    return(false);
                }
                else if (i == imgsToAdd.Length - 1)
                {
                    int usedW = 0;
                    int usedH = 0;
                    GetExtent(root, ref usedW, ref usedH);
                    float squareness;
                    float efficiency = 1f - (usedW * usedH - imgArea) / (usedW * usedH);
                    if (usedW < usedH)
                    {
                        squareness = (float)usedW / (float)usedH;
                    }
                    else
                    {
                        squareness = (float)usedH / (float)usedW;
                    }
                    bool fitsInMaxDim = usedW <= maxAtlasDim && usedH <= maxAtlasDim;
                    pr.Set(usedW, usedH, root, fitsInMaxDim, efficiency, squareness);
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Probe success efficiency w=" + usedW + " h=" + usedH + " e=" + efficiency + " sq=" + squareness + " fits=" + fitsInMaxDim);
                    }
                    return(true);
                }
            }
            Debug.LogError("Should never get here.");
            return(false);
        }
Example #16
0
        public Rect[] GetRects(List <Vector2> imgWidthHeights, int maxDimension, int padding, out int outW, out int outH)
        {
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd = new Image[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                Image im = imgsToAdd[i] = new Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer");
                }
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }
//			List<Node> ns = new List<Node>();

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

            if (maxW > sqrtArea)
            {
                idealAtlasW = maxW;
                idealAtlasH = Mathf.Max(Mathf.CeilToInt(area / maxW), maxH);
            }
            if (maxH > sqrtArea)
            {
                idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / maxH), maxW);
                idealAtlasH = maxH;
            }
            if (idealAtlasW == 0)
            {
                idealAtlasW = 1;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 1;
            }
            int stepW = (int)(idealAtlasW * .15f);
            int stepH = (int)(idealAtlasH * .15f);

            if (stepW == 0)
            {
                stepW = 1;
            }
            if (stepH == 0)
            {
                stepH = 1;
            }
//			bool doStepHeight = true;
//			bool successH = false;
            int numWIterations = 2;
            int steppedHeight  = idealAtlasH;

            while (numWIterations > 1 && steppedHeight < sqrtArea * 1000)
            {
                bool successW = false;
                numWIterations = 0;
                int steppedWidth = idealAtlasW;
                while (!successW && steppedWidth < sqrtArea * 1000)
                {
                    ProbeResult pr = new ProbeResult();
                    if (Probe(imgsToAdd, steppedWidth, steppedHeight, area, maxDimension, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore() > bestRoot.GetScore())
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth += stepW;
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            MB2_Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight += stepH;
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("increasing Height h=" + steppedHeight + " w=" + steppedWidth);
                }
            }

            outW = 0;
            outH = 0;
            if (bestRoot == null)
            {
                return(null);
            }
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("Best fit found: w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.fitsInMaxSize);
            }
            outW = bestRoot.w;
            outH = bestRoot.h;
            List <Image> images = new List <Image>();

            flattenTree(bestRoot.root, images);
            images.Sort(new ImgIDComparer());
            if (images.Count != imgsToAdd.Length)
            {
                Debug.LogError("Result images not the same lentgh as source");
            }

            //scale images if too large
            float padX = (float)padding / (float)bestRoot.w;

            if (bestRoot.w > maxDimension)
            {
                padX = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)bestRoot.w;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image im    = images[i];
                    int   right = (int)((im.x + im.w) * scaleFactor);
                    im.x = (int)(scaleFactor * im.x);
                    im.w = right - im.x;
                    if (im.w == 0)
                    {
                        Debug.LogError("rounding scaled image w to zero");
                    }
                }
                outW = maxDimension;
            }

            float padY = (float)padding / (float)bestRoot.h;

            if (bestRoot.h > maxDimension)
            {
                padY = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)bestRoot.h;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image im     = images[i];
                    int   bottom = (int)((im.y + im.h) * scaleFactor);
                    im.y = (int)(scaleFactor * im.y);
                    im.h = bottom - im.y;
                    if (im.h == 0)
                    {
                        Debug.LogError("rounding scaled image h to zero");
                    }
                }
                outH = maxDimension;
            }

            Rect[] rs = new Rect[images.Count];
            for (int i = 0; i < images.Count; i++)
            {
                Image im = images[i];
                Rect  r  = rs[i] = new Rect((float)im.x / (float)outW + padX,
                                            (float)im.y / (float)outH + padY,
                                            (float)im.w / (float)outW - padX * 2,
                                            (float)im.h / (float)outH - padY * 2);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                     " y=" + r.y * outH + " w=" + r.width * outW +
                                     " h=" + r.height * outH + " padding=" + padding);
                }
            }

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("Done GetRects");
            }
            return(rs);
        }
Example #17
0
        private Rect[] _GetRects(List <Vector2> imgWidthHeights, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, out int outW, out int outH, int recursionDepth)
        {
            if (this.LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(string.Format("_GetRects numImages={0}, maxDimension={1}, padding={2}, minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}, recursionDepth={7}", new object[]
                {
                    imgWidthHeights.Count,
                    maxDimension,
                    padding,
                    minImageSizeX,
                    minImageSizeY,
                    masterImageSizeX,
                    masterImageSizeY,
                    recursionDepth
                }));
            }
            if (recursionDepth > 10)
            {
                Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
                outW = 0;
                outH = 0;
                return(new Rect[0]);
            }
            float num  = 0f;
            int   num2 = 0;
            int   num3 = 0;

            MB2_TexturePacker.Image[] array = new MB2_TexturePacker.Image[imgWidthHeights.Count];
            for (int i = 0; i < array.Length; i++)
            {
                MB2_TexturePacker.Image image = array[i] = new MB2_TexturePacker.Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding, minImageSizeX, minImageSizeY);
                num += (float)(image.w * image.h);
                num2 = Mathf.Max(num2, image.w);
                num3 = Mathf.Max(num3, image.h);
            }
            if ((float)num3 / (float)num2 > 2f)
            {
                if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer", new object[0]);
                }
                Array.Sort <MB2_TexturePacker.Image>(array, new MB2_TexturePacker.ImageHeightComparer());
            }
            else if ((double)((float)num3 / (float)num2) < 0.5)
            {
                if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer", new object[0]);
                }
                Array.Sort <MB2_TexturePacker.Image>(array, new MB2_TexturePacker.ImageWidthComparer());
            }
            else
            {
                if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer", new object[0]);
                }
                Array.Sort <MB2_TexturePacker.Image>(array, new MB2_TexturePacker.ImageAreaComparer());
            }
            int num4 = (int)Mathf.Sqrt(num);
            int num6;
            int num5;

            if (this.doPowerOfTwoTextures)
            {
                num5 = (num6 = this.RoundToNearestPositivePowerOfTwo(num4));
                if (num2 > num6)
                {
                    num6 = this.CeilToNearestPowerOfTwo(num6);
                }
                if (num3 > num5)
                {
                    num5 = this.CeilToNearestPowerOfTwo(num5);
                }
            }
            else
            {
                num6 = num4;
                num5 = num4;
                if (num2 > num4)
                {
                    num6 = num2;
                    num5 = Mathf.Max(Mathf.CeilToInt(num / (float)num2), num3);
                }
                if (num3 > num4)
                {
                    num6 = Mathf.Max(Mathf.CeilToInt(num / (float)num3), num2);
                    num5 = num3;
                }
            }
            if (num6 == 0)
            {
                num6 = 1;
            }
            if (num5 == 0)
            {
                num5 = 1;
            }
            int num7 = (int)((float)num6 * 0.15f);
            int num8 = (int)((float)num5 * 0.15f);

            if (num7 == 0)
            {
                num7 = 1;
            }
            if (num8 == 0)
            {
                num8 = 1;
            }
            int num9  = 2;
            int num10 = num5;

            while (num9 >= 1 && num10 < num4 * 1000)
            {
                bool flag = false;
                num9 = 0;
                int num11 = num6;
                while (!flag && num11 < num4 * 1000)
                {
                    MB2_TexturePacker.ProbeResult probeResult = new MB2_TexturePacker.ProbeResult();
                    if (this.LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log(string.Concat(new object[]
                        {
                            "Probing h=",
                            num10,
                            " w=",
                            num11
                        }));
                    }
                    if (this.Probe(array, num11, num10, num, maxDimension, probeResult))
                    {
                        flag = true;
                        if (this.bestRoot == null)
                        {
                            this.bestRoot = probeResult;
                        }
                        else if (probeResult.GetScore(this.doPowerOfTwoTextures) > this.bestRoot.GetScore(this.doPowerOfTwoTextures))
                        {
                            this.bestRoot = probeResult;
                        }
                    }
                    else
                    {
                        num9++;
                        num11 = this.StepWidthHeight(num11, num7, maxDimension);
                        if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            MB2_Log.LogDebug(string.Concat(new object[]
                            {
                                "increasing Width h=",
                                num10,
                                " w=",
                                num11
                            }), new object[0]);
                        }
                    }
                }
                num10 = this.StepWidthHeight(num10, num8, maxDimension);
                if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug(string.Concat(new object[]
                    {
                        "increasing Height h=",
                        num10,
                        " w=",
                        num11
                    }), new object[0]);
                }
            }
            outW = 0;
            outH = 0;
            if (this.doPowerOfTwoTextures)
            {
                outW = Mathf.Min(this.CeilToNearestPowerOfTwo(this.bestRoot.w), maxDimension);
                outH = Mathf.Min(this.CeilToNearestPowerOfTwo(this.bestRoot.h), maxDimension);
                if (outH < outW / 2)
                {
                    outH = outW / 2;
                }
                if (outW < outH / 2)
                {
                    outW = outH / 2;
                }
            }
            else
            {
                outW = this.bestRoot.w;
                outH = this.bestRoot.h;
            }
            if (this.bestRoot == null)
            {
                return(null);
            }
            if (this.LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug(string.Concat(new object[]
                {
                    "Best fit found: atlasW=",
                    outW,
                    " atlasH",
                    outH,
                    " w=",
                    this.bestRoot.w,
                    " h=",
                    this.bestRoot.h,
                    " efficiency=",
                    this.bestRoot.efficiency,
                    " squareness=",
                    this.bestRoot.squareness,
                    " fits in max dimension=",
                    this.bestRoot.fitsInMaxSize
                }), new object[0]);
            }
            List <MB2_TexturePacker.Image> list = new List <MB2_TexturePacker.Image>();

            MB2_TexturePacker.flattenTree(this.bestRoot.root, list);
            list.Sort(new MB2_TexturePacker.ImgIDComparer());
            if (list.Count != array.Length)
            {
                Debug.LogError("Result images not the same lentgh as source");
            }
            int   minImageSizeX2 = minImageSizeX;
            int   minImageSizeY2 = minImageSizeY;
            bool  flag2          = false;
            float num12          = (float)padding / (float)outW;

            if (this.bestRoot.w > maxDimension)
            {
                num12 = (float)padding / (float)maxDimension;
                float num13 = (float)maxDimension / (float)this.bestRoot.w;
                if (this.LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas width shrinking to " + num13);
                }
                for (int j = 0; j < list.Count; j++)
                {
                    MB2_TexturePacker.Image image2 = list[j];
                    if ((float)image2.w * num13 < (float)masterImageSizeX)
                    {
                        if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeX.");
                        }
                        flag2          = true;
                        minImageSizeX2 = Mathf.CeilToInt((float)minImageSizeX / num13);
                    }
                    int num14 = (int)((float)(image2.x + image2.w) * num13);
                    image2.x = (int)(num13 * (float)image2.x);
                    image2.w = num14 - image2.x;
                }
                outW = maxDimension;
            }
            float num15 = (float)padding / (float)outH;

            if (this.bestRoot.h > maxDimension)
            {
                num15 = (float)padding / (float)maxDimension;
                float num16 = (float)maxDimension / (float)this.bestRoot.h;
                if (this.LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas height shrinking to " + num16);
                }
                for (int k = 0; k < list.Count; k++)
                {
                    MB2_TexturePacker.Image image3 = list[k];
                    if ((float)image3.h * num16 < (float)masterImageSizeY)
                    {
                        if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Small images are being scaled to zero. Will need to redo packing with larger minTexSizeY.");
                        }
                        flag2          = true;
                        minImageSizeY2 = Mathf.CeilToInt((float)minImageSizeY / num16);
                    }
                    int num17 = (int)((float)(image3.y + image3.h) * num16);
                    image3.y = (int)(num16 * (float)image3.y);
                    image3.h = num17 - image3.y;
                }
                outH = maxDimension;
            }
            Rect[] array2;
            if (!flag2)
            {
                array2 = new Rect[list.Count];
                for (int l = 0; l < list.Count; l++)
                {
                    MB2_TexturePacker.Image image4 = list[l];
                    Rect rect = array2[l] = new Rect((float)image4.x / (float)outW + num12, (float)image4.y / (float)outH + num15, (float)image4.w / (float)outW - num12 * 2f, (float)image4.h / (float)outH - num15 * 2f);
                    if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug(string.Concat(new object[]
                        {
                            "Image: ",
                            l,
                            " imgID=",
                            image4.imgId,
                            " x=",
                            rect.x * (float)outW,
                            " y=",
                            rect.y * (float)outH,
                            " w=",
                            rect.width * (float)outW,
                            " h=",
                            rect.height * (float)outH,
                            " padding=",
                            padding
                        }), new object[0]);
                    }
                }
            }
            else
            {
                if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("==================== REDOING PACKING ================");
                }
                this.bestRoot = null;
                array2        = this._GetRects(imgWidthHeights, maxDimension, padding, minImageSizeX2, minImageSizeY2, masterImageSizeX, masterImageSizeY, out outW, out outH, recursionDepth + 1);
            }
            if (this.LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("Done GetRects", new object[0]);
            }
            return(array2);
        }
Example #18
0
 private bool Probe(MB2_TexturePacker.Image[] imgsToAdd, int idealAtlasW, int idealAtlasH, float imgArea, int maxAtlasDim, MB2_TexturePacker.ProbeResult pr)
 {
     MB2_TexturePacker.Node node = new MB2_TexturePacker.Node();
     node.r = new MB2_TexturePacker.PixRect(0, 0, idealAtlasW, idealAtlasH);
     for (int i = 0; i < imgsToAdd.Length; i++)
     {
         if (node.Insert(imgsToAdd[i], false) == null)
         {
             return(false);
         }
         if (i == imgsToAdd.Length - 1)
         {
             int num  = 0;
             int num2 = 0;
             this.GetExtent(node, ref num, ref num2);
             bool  flag;
             float num8;
             float num9;
             if (this.doPowerOfTwoTextures)
             {
                 int num3 = Mathf.Min(this.CeilToNearestPowerOfTwo(num), maxAtlasDim);
                 int num4 = Mathf.Min(this.CeilToNearestPowerOfTwo(num2), maxAtlasDim);
                 if (num4 < num3 / 2)
                 {
                     num4 = num3 / 2;
                 }
                 if (num3 < num4 / 2)
                 {
                     num3 = num4 / 2;
                 }
                 flag = (num <= maxAtlasDim && num2 <= maxAtlasDim);
                 float num5 = Mathf.Max(1f, (float)num / (float)maxAtlasDim);
                 float num6 = Mathf.Max(1f, (float)num2 / (float)maxAtlasDim);
                 float num7 = (float)num3 * num5 * (float)num4 * num6;
                 num8 = 1f - (num7 - imgArea) / num7;
                 num9 = 1f;
             }
             else
             {
                 num8 = 1f - ((float)(num * num2) - imgArea) / (float)(num * num2);
                 if (num < num2)
                 {
                     num9 = (float)num / (float)num2;
                 }
                 else
                 {
                     num9 = (float)num2 / (float)num;
                 }
                 flag = (num <= maxAtlasDim && num2 <= maxAtlasDim);
             }
             pr.Set(num, num2, node, flag, num8, num9);
             if (this.LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug(string.Concat(new object[]
                 {
                     "Probe success efficiency w=",
                     num,
                     " h=",
                     num2,
                     " e=",
                     num8,
                     " sq=",
                     num9,
                     " fits=",
                     flag
                 }), new object[0]);
             }
             return(true);
         }
     }
     Debug.LogError("Should never get here.");
     return(false);
 }
Example #19
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, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("_GetRects numImages={0}, maxDimension={1}, padding={2}, minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}, recursionDepth={7}",
                                        imgWidthHeights.Count, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            }
            if (recursionDepth > 10)
            {
                if (LOG_LEVEL >= MB2_LogLevel.error)
                {
                    Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
                }
                return(null);
            }
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd = new Image[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int   iw = (int)imgWidthHeights[i].x;
                int   ih = (int)imgWidthHeights[i].y;
                Image im = imgsToAdd[i] = new Image(i, iw, ih, padding, minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer");
                }
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

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

            if (doPowerOfTwoTextures)
            {
                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(area / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / 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();
                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);
                    }
                    if (ProbeSingleAtlas(imgsToAdd, steppedWidth, steppedHeight, area, maxDimension, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(doPowerOfTwoTextures) > bestRoot.GetScore(doPowerOfTwoTextures))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = StepWidthHeight(steppedWidth, stepW, maxDimension);
                        if (LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            MB2_Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimension);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("increasing Height h=" + steppedHeight + " w=" + steppedWidth);
                }
            }
            if (bestRoot == null)
            {
                return(null);
            }

            int outW = 0;
            int outH = 0;

            if (doPowerOfTwoTextures)
            {
                outW = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.w), maxDimension);
                outH = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.h), maxDimension);
                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, maxDimension);
                outH = Mathf.Min(bestRoot.h, maxDimension);
            }

            bestRoot.outW = outW;
            bestRoot.outH = outH;
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                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 <Image> images = new List <Image>();

            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
            AtlasPackingResult res = ScaleAtlasToFitMaxDim(bestRoot, imgWidthHeights, images, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, outW, outH, recursionDepth);

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug(String.Format("Done GetRects atlasW={0} atlasH={1}", bestRoot.w, bestRoot.h));
            }

            return(res);
        }
 bool _bakeStep1(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource)
 {
     //Profile.End//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects2.2");
     //Profile.Start//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects3");
     //PART 3 ==== Add delete meshes from combined
     for (int i = 0; i < meshCombiners.Count; i++)
     {
         CombinedMesh cm = meshCombiners[i];
         if (cm.combinedMesh.targetRenderer == null)
         {
             cm.combinedMesh.resultSceneObject = _resultSceneObject;
             cm.combinedMesh.BuildSceneMeshObject(gos, true);
             if (_LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug("BuildSO combiner {0} goID {1} targetRenID {2} meshID {3}", i, cm.combinedMesh.targetRenderer.gameObject.GetInstanceID(), cm.combinedMesh.targetRenderer.GetInstanceID(), cm.combinedMesh.GetMesh().GetInstanceID());
             }
         }
         else
         {
             if (cm.combinedMesh.targetRenderer.transform.parent != resultSceneObject.transform)
             {
                 Debug.LogError("targetRender objects must be children of resultSceneObject");
                 return(false);
             }
         }
         if (cm.gosToAdd.Count > 0 || cm.gosToDelete.Count > 0)
         {
             cm.combinedMesh.AddDeleteGameObjectsByID(cm.gosToAdd.ToArray(), cm.gosToDelete.ToArray(), disableRendererInSource);
             if (_LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug("Baked combiner {0} obsAdded {1} objsRemoved {2} goID {3} targetRenID {4} meshID {5}", i, cm.gosToAdd.Count, cm.gosToDelete.Count, cm.combinedMesh.targetRenderer.gameObject.GetInstanceID(), cm.combinedMesh.targetRenderer.GetInstanceID(), cm.combinedMesh.GetMesh().GetInstanceID());
             }
         }
         Renderer r = cm.combinedMesh.targetRenderer;
         Mesh     m = cm.combinedMesh.GetMesh();
         if (r is MeshRenderer)
         {
             MeshFilter mf = r.gameObject.GetComponent <MeshFilter>();
             mf.sharedMesh = m;
         }
         else
         {
             SkinnedMeshRenderer smr = (SkinnedMeshRenderer)r;
             smr.sharedMesh = m;
         }
     }
     for (int i = 0; i < meshCombiners.Count; i++)
     {
         CombinedMesh cm = meshCombiners[i];
         for (int j = 0; j < cm.gosToDelete.Count; j++)
         {
             obj2MeshCombinerMap.Remove(cm.gosToDelete[j]);
         }
     }
     for (int i = 0; i < meshCombiners.Count; i++)
     {
         CombinedMesh cm = meshCombiners[i];
         for (int j = 0; j < cm.gosToAdd.Count; j++)
         {
             obj2MeshCombinerMap.Add(cm.gosToAdd[j].GetInstanceID(), cm);
         }
         if (cm.gosToAdd.Count > 0 || cm.gosToDelete.Count > 0)
         {
             cm.gosToDelete.Clear();
             cm.gosToAdd.Clear();
             cm.numVertsInListToDelete = 0;
             cm.numVertsInListToAdd    = 0;
             cm.isDirty = true;
         }
     }
     //Profile.End//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects3");
     if (LOG_LEVEL >= MB2_LogLevel.debug)
     {
         string s = "Meshes in combined:";
         for (int i = 0; i < meshCombiners.Count; i++)
         {
             s += " mesh" + i + "(" + meshCombiners[i].combinedMesh.GetObjectsInCombined().Count + ")\n";
         }
         s += "children in result: " + resultSceneObject.transform.childCount;
         MB2_Log.LogDebug(s, LOG_LEVEL);
     }
     if (meshCombiners.Count > 0)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
        void _distributeAmongBakers(GameObject[] gos, int[] deleteGOinstanceIDs)
        {
            if (gos == null)
            {
                gos = empty;
            }
            if (deleteGOinstanceIDs == null)
            {
                deleteGOinstanceIDs = emptyIDs;
            }

            if (resultSceneObject == null)
            {
                resultSceneObject = new GameObject("CombinedMesh-" + name);
            }

            //PART 2 ==== calculate which bakers to add objects to
            for (int i = 0; i < meshCombiners.Count; i++)
            {
                meshCombiners[i].extraSpace = _maxVertsInMesh - meshCombiners[i].combinedMesh.GetMesh().vertexCount;
            }
            //Profile.End//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects1");

            //Profile.Start//Profile("MB2_MultiMeshCombiner.AddDeleteGameObjects2.1");
            //first delete game objects from the existing combinedMeshes keep track of free space
            for (int i = 0; i < deleteGOinstanceIDs.Length; i++)
            {
                CombinedMesh c = null;
                if (obj2MeshCombinerMap.TryGetValue(deleteGOinstanceIDs[i], out c))
                {
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("MB2_MultiMeshCombiner.Removing " + deleteGOinstanceIDs[i] + " from meshCombiner " + meshCombiners.IndexOf(c));
                    }
                    c.numVertsInListToDelete += c.combinedMesh.GetNumVerticesFor(deleteGOinstanceIDs[i]);              //m.vertexCount;
                    c.gosToDelete.Add(deleteGOinstanceIDs[i]);
                }
                else
                {
                    Debug.LogWarning("Object " + deleteGOinstanceIDs[i] + " in the list of objects to delete is not in the combined mesh.");
                }
            }
            for (int i = 0; i < gos.Length; i++)
            {
                GameObject   go       = gos[i];
                int          numVerts = MB_Utility.GetMesh(go).vertexCount;
                CombinedMesh cm       = null;
                for (int j = 0; j < meshCombiners.Count; j++)
                {
                    if (meshCombiners[j].extraSpace + meshCombiners[j].numVertsInListToDelete - meshCombiners[j].numVertsInListToAdd > numVerts)
                    {
                        cm = meshCombiners[j];
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            MB2_Log.LogDebug("MB2_MultiMeshCombiner.Added " + gos[i] + " to combinedMesh " + j, LOG_LEVEL);
                        }
                        break;
                    }
                }
                if (cm == null)
                {
                    cm = new CombinedMesh(maxVertsInMesh, _resultSceneObject, _LOG_LEVEL);
                    _setMBValues(cm.combinedMesh);
                    meshCombiners.Add(cm);
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("MB2_MultiMeshCombiner.Created new combinedMesh");
                    }
                }
                cm.gosToAdd.Add(go);
                cm.numVertsInListToAdd += numVerts;
//			obj2MeshCombinerMap.Add(go,cm);
            }
        }
Example #22
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
         */
        AtlasPackingResult ScaleAtlasToFitMaxDim(ProbeResult root, List <Vector2> imgWidthHeights, List <Image> images, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int outW, int outH, int recursionDepth)
        {
            int  newMinSizeX = minImageSizeX;
            int  newMinSizeY = minImageSizeY;
            bool redoPacking = false;
            //AtlasPackingResult[] rs = null;

            // the atlas may be packed larger than the maxDimension. If so then the atlas needs to be scaled down to fit
            float padX = (float)padding / (float)outW; //padding needs to be pixel perfect in size

            if (root.w > maxDimension)
            {
                padX = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)root.w;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image 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
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            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 = maxDimension;
            }

            float padY = (float)padding / (float)outH;

            if (root.h > maxDimension)
            {
                //float minSizeY = ((float)minImageSizeY + 1) / maxDimension;
                padY = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)root.h;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image 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
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            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 = maxDimension;
            }

            AtlasPackingResult res;

            if (!redoPacking)
            {
                res            = new AtlasPackingResult();
                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++)
                {
                    Image 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;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + padding);
                    }
                }
                return(res);
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("==================== REDOING PACKING ================");
                }
                root = null;
                return(_GetRectsSingleAtlas(imgWidthHeights, maxDimension, padding, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, recursionDepth + 1));
            }
        }
Example #23
0
        AtlasPackingResult _GetRectsSingleAtlas(List <Vector2> imgWidthHeights, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, int recursionDepth)
        {
            AtlasPackingResult res = new AtlasPackingResult();

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

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Packing rects for: " + imgWidthHeights.Count);
            }
            for (int i = 0; i < imgWidthHeights.Count; i++)
            {
                Image im = new Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding, minImageSizeX, minImageSizeY);

                // if images are stacked horizontally then there is no padding at the top or bottom
                if (packingOrientation == TexturePackingOrientation.vertical)
                {
                    im.h -= padding * 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 -= padding * 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), maxDimension);
                }
                else
                {
                    outW = Mathf.Min(outW, maxDimension);
                }
            }
            else
            {
                if (atlasMustBePowerOfTwo)
                {
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(outH), maxDimension);
                }
                else
                {
                    outH = Mathf.Min(outH, maxDimension);
                }
            }

            float padX, padY;
            int   newMinSizeX, newMinSizeY;

            if (!ScaleAtlasToFitMaxDim(rootWH, images, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY,
                                       ref outW, ref outH, out padX, out padY, out newMinSizeX, out newMinSizeY))
            {
                res            = new AtlasPackingResult();
                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++)
                {
                    Image 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;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + padding + " outW=" + outW + " outH=" + outH);
                    }
                }
                return(res);
            }
            Debug.Log("Packing failed returning null atlas result");
            return(null);
        }
Example #24
0
 private void _distributeAmongBakers(GameObject[] gos, int[] deleteGOinstanceIDs)
 {
     if (gos == null)
     {
         gos = MB3_MultiMeshCombiner.empty;
     }
     if (deleteGOinstanceIDs == null)
     {
         deleteGOinstanceIDs = MB3_MultiMeshCombiner.emptyIDs;
     }
     if (this.resultSceneObject == null)
     {
         this.resultSceneObject = new GameObject("CombinedMesh-" + base.name);
     }
     for (int i = 0; i < this.meshCombiners.Count; i++)
     {
         this.meshCombiners[i].extraSpace = this._maxVertsInMesh - this.meshCombiners[i].combinedMesh.GetMesh().vertexCount;
     }
     for (int j = 0; j < deleteGOinstanceIDs.Length; j++)
     {
         MB3_MultiMeshCombiner.CombinedMesh combinedMesh = null;
         if (this.obj2MeshCombinerMap.TryGetValue(deleteGOinstanceIDs[j], out combinedMesh))
         {
             if (this.LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug(string.Concat(new object[]
                 {
                     "MB2_MultiMeshCombiner.Removing ",
                     deleteGOinstanceIDs[j],
                     " from meshCombiner ",
                     this.meshCombiners.IndexOf(combinedMesh)
                 }), new object[0]);
             }
             combinedMesh.numVertsInListToDelete += combinedMesh.combinedMesh.GetNumVerticesFor(deleteGOinstanceIDs[j]);
             combinedMesh.gosToDelete.Add(deleteGOinstanceIDs[j]);
         }
         else
         {
             Debug.LogWarning("Object " + deleteGOinstanceIDs[j] + " in the list of objects to delete is not in the combined mesh.");
         }
     }
     for (int k = 0; k < gos.Length; k++)
     {
         GameObject gameObject  = gos[k];
         int        vertexCount = MB_Utility.GetMesh(gameObject).vertexCount;
         MB3_MultiMeshCombiner.CombinedMesh combinedMesh2 = null;
         for (int l = 0; l < this.meshCombiners.Count; l++)
         {
             if (this.meshCombiners[l].extraSpace + this.meshCombiners[l].numVertsInListToDelete - this.meshCombiners[l].numVertsInListToAdd > vertexCount)
             {
                 combinedMesh2 = this.meshCombiners[l];
                 if (this.LOG_LEVEL >= MB2_LogLevel.debug)
                 {
                     MB2_Log.LogDebug(string.Concat(new object[]
                     {
                         "MB2_MultiMeshCombiner.Added ",
                         gos[k],
                         " to combinedMesh ",
                         l
                     }), new object[]
                     {
                         this.LOG_LEVEL
                     });
                 }
                 break;
             }
         }
         if (combinedMesh2 == null)
         {
             combinedMesh2 = new MB3_MultiMeshCombiner.CombinedMesh(this.maxVertsInMesh, this._resultSceneObject, this._LOG_LEVEL);
             this._setMBValues(combinedMesh2.combinedMesh);
             this.meshCombiners.Add(combinedMesh2);
             if (this.LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug("MB2_MultiMeshCombiner.Created new combinedMesh", new object[0]);
             }
         }
         combinedMesh2.gosToAdd.Add(gameObject);
         combinedMesh2.numVertsInListToAdd += vertexCount;
     }
 }
        //----------------- 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)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                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;

            Image[] imgsToAdd     = new Image[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);

                Image im = imgsToAdd[i] = new Image(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);
            }
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                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 <Node>  atlasNodes = new List <Node>();
            Stack <Node> stack      = new Stack <Node>();
            Node         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 <Image> images = new List <Image>();
                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].r.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].r.x;
                int outW = atlasNodes[i].r.w;
                int outH = atlasNodes[i].r.h;
                if (atlasMustBePowerOfTwo)
                {
                    outW = Mathf.Min(CeilToNearestPowerOfTwo(res.usedW), atlasNodes[i].r.w);
                    outH = Mathf.Min(CeilToNearestPowerOfTwo(res.usedH), atlasNodes[i].r.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);
                ConvertToRectsWithoutPaddingAndNormalize01(res, paddings[i]);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug(String.Format("Done GetRects "));
                }
            }

            return(rs.ToArray());
        }
Example #26
0
 private bool _bakeStep1(GameObject[] gos, int[] deleteGOinstanceIDs, bool disableRendererInSource)
 {
     for (int i = 0; i < this.meshCombiners.Count; i++)
     {
         MB3_MultiMeshCombiner.CombinedMesh combinedMesh = this.meshCombiners[i];
         if (combinedMesh.combinedMesh.targetRenderer == null)
         {
             combinedMesh.combinedMesh.resultSceneObject = this._resultSceneObject;
             combinedMesh.combinedMesh.BuildSceneMeshObject(gos, true);
             if (this._LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug("BuildSO combiner {0} goID {1} targetRenID {2} meshID {3}", new object[]
                 {
                     i,
                     combinedMesh.combinedMesh.targetRenderer.gameObject.GetInstanceID(),
                     combinedMesh.combinedMesh.targetRenderer.GetInstanceID(),
                     combinedMesh.combinedMesh.GetMesh().GetInstanceID()
                 });
             }
         }
         else if (combinedMesh.combinedMesh.targetRenderer.transform.parent != this.resultSceneObject.transform)
         {
             Debug.LogError("targetRender objects must be children of resultSceneObject");
             return(false);
         }
         if (combinedMesh.gosToAdd.Count > 0 || combinedMesh.gosToDelete.Count > 0)
         {
             combinedMesh.combinedMesh.AddDeleteGameObjectsByID(combinedMesh.gosToAdd.ToArray(), combinedMesh.gosToDelete.ToArray(), disableRendererInSource);
             if (this._LOG_LEVEL >= MB2_LogLevel.debug)
             {
                 MB2_Log.LogDebug("Baked combiner {0} obsAdded {1} objsRemoved {2} goID {3} targetRenID {4} meshID {5}", new object[]
                 {
                     i,
                     combinedMesh.gosToAdd.Count,
                     combinedMesh.gosToDelete.Count,
                     combinedMesh.combinedMesh.targetRenderer.gameObject.GetInstanceID(),
                     combinedMesh.combinedMesh.targetRenderer.GetInstanceID(),
                     combinedMesh.combinedMesh.GetMesh().GetInstanceID()
                 });
             }
         }
         Renderer targetRenderer = combinedMesh.combinedMesh.targetRenderer;
         Mesh     mesh           = combinedMesh.combinedMesh.GetMesh();
         if (targetRenderer is MeshRenderer)
         {
             MeshFilter component = targetRenderer.gameObject.GetComponent <MeshFilter>();
             component.sharedMesh = mesh;
         }
         else
         {
             SkinnedMeshRenderer skinnedMeshRenderer = (SkinnedMeshRenderer)targetRenderer;
             skinnedMeshRenderer.sharedMesh = mesh;
         }
     }
     for (int j = 0; j < this.meshCombiners.Count; j++)
     {
         MB3_MultiMeshCombiner.CombinedMesh combinedMesh2 = this.meshCombiners[j];
         for (int k = 0; k < combinedMesh2.gosToDelete.Count; k++)
         {
             this.obj2MeshCombinerMap.Remove(combinedMesh2.gosToDelete[k]);
         }
     }
     for (int l = 0; l < this.meshCombiners.Count; l++)
     {
         MB3_MultiMeshCombiner.CombinedMesh combinedMesh3 = this.meshCombiners[l];
         for (int m = 0; m < combinedMesh3.gosToAdd.Count; m++)
         {
             this.obj2MeshCombinerMap.Add(combinedMesh3.gosToAdd[m].GetInstanceID(), combinedMesh3);
         }
         if (combinedMesh3.gosToAdd.Count > 0 || combinedMesh3.gosToDelete.Count > 0)
         {
             combinedMesh3.gosToDelete.Clear();
             combinedMesh3.gosToAdd.Clear();
             combinedMesh3.numVertsInListToDelete = 0;
             combinedMesh3.numVertsInListToAdd    = 0;
             combinedMesh3.isDirty = true;
         }
     }
     if (this.LOG_LEVEL >= MB2_LogLevel.debug)
     {
         string text = "Meshes in combined:";
         for (int n = 0; n < this.meshCombiners.Count; n++)
         {
             string text2 = text;
             text = string.Concat(new object[]
             {
                 text2,
                 " mesh",
                 n,
                 "(",
                 this.meshCombiners[n].combinedMesh.GetObjectsInCombined().Count,
                 ")\n"
             });
         }
         text = text + "children in result: " + this.resultSceneObject.transform.childCount;
         MB2_Log.LogDebug(text, new object[]
         {
             this.LOG_LEVEL
         });
     }
     return(this.meshCombiners.Count > 0);
 }
        bool ProbeSingleAtlas(Image[] imgsToAdd, int idealAtlasW, int idealAtlasH, float imgArea, int maxAtlasDimX, int maxAtlasDimY, ProbeResult pr)
        {
            Node root = new Node(NodeType.maxDim);

            root.r = new PixRect(0, 0, idealAtlasW, idealAtlasH);
            //Debug.Assert(maxAtlasDim >= 1);
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                Node n = root.Insert(imgsToAdd[i], false);
                if (n == null)
                {
                    return(false);
                }
                else if (i == imgsToAdd.Length - 1)
                {
                    int usedW = 0;
                    int usedH = 0;
                    GetExtent(root, ref usedW, ref usedH);
                    float efficiency, squareness;
                    bool  fitsInMaxDim;
                    int   atlasW = usedW;
                    int   atlasH = usedH;
                    if (atlasMustBePowerOfTwo)
                    {
                        atlasW = Mathf.Min(CeilToNearestPowerOfTwo(usedW), maxAtlasDimX);
                        atlasH = Mathf.Min(CeilToNearestPowerOfTwo(usedH), maxAtlasDimY);
                        if (atlasH < atlasW / 2)
                        {
                            atlasH = atlasW / 2;
                        }
                        if (atlasW < atlasH / 2)
                        {
                            atlasW = atlasH / 2;
                        }
                        fitsInMaxDim = usedW <= maxAtlasDimX && usedH <= maxAtlasDimY;
                        float scaleW    = Mathf.Max(1f, ((float)usedW) / maxAtlasDimX);
                        float scaleH    = Mathf.Max(1f, ((float)usedH) / maxAtlasDimY);
                        float atlasArea = atlasW * scaleW * atlasH * scaleH; //area if we scaled it up to something large enough to contain images
                        efficiency = 1f - (atlasArea - imgArea) / atlasArea;
                        squareness = 1f;                                     //don't care about squareness in power of two case
                    }
                    else
                    {
                        efficiency = 1f - (usedW * usedH - imgArea) / (usedW * usedH);
                        if (usedW < usedH)
                        {
                            squareness = (float)usedW / (float)usedH;
                        }
                        else
                        {
                            squareness = (float)usedH / (float)usedW;
                        }
                        fitsInMaxDim = usedW <= maxAtlasDimX && usedH <= maxAtlasDimY;
                    }
                    pr.Set(usedW, usedH, atlasW, atlasH, root, fitsInMaxDim, efficiency, squareness);
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Probe success efficiency w=" + usedW + " h=" + usedH + " e=" + efficiency + " sq=" + squareness + " fits=" + fitsInMaxDim);
                    }
                    return(true);
                }
            }
            Debug.LogError("Should never get here.");
            return(false);
        }
Example #28
0
 public void LogDebug(string msg, params object[] args)
 {
     _CacheLogMessage(MB2_Log.LogDebug(msg, args));
 }
        //------------------ 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)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("_GetRects numImages={0}, maxDimension={1}, minImageSizeX={2}, minImageSizeY={3}, masterImageSizeX={4}, masterImageSizeY={5}, recursionDepth={6}",
                                        imgWidthHeights.Count, maxDimensionX, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            }
            if (recursionDepth > MAX_RECURSION_DEPTH)
            {
                if (LOG_LEVEL >= MB2_LogLevel.error)
                {
                    Debug.LogError("Maximum recursion depth reached. The baked atlas is likely not very good. " +
                                   " This happens when the packed atlases exceeds the maximum" +
                                   " atlas size in one or both dimensions so that the atlas needs to be downscaled AND there are some very thin or very small images (only-a-few-pixels)." +
                                   " these very thin images can 'vanish' completely when the atlas is downscaled.\n\n" +
                                   " Try one or more of the following: using multiple atlases, increase the maximum atlas size, don't use 'force-power-of-two', remove the source materials that are are using very small/thin textures.");
                }
                //return null;
            }
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd = new Image[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                int   iw = (int)imgWidthHeights[i].x;
                int   ih = (int)imgWidthHeights[i].y;
                Image im = imgsToAdd[i] = new Image(i, iw, ih, paddings[i], minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer");
                }
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

            //explore the space to find a resonably efficient packing
            int sqrtArea = (int)Mathf.Sqrt(area);
            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(area / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / 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();
                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);
                    }
                    if (ProbeSingleAtlas(imgsToAdd, steppedWidth, steppedHeight, area, maxDimensionX, maxDimensionY, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(atlasMustBePowerOfTwo) > bestRoot.GetScore(atlasMustBePowerOfTwo))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = StepWidthHeight(steppedWidth, stepW, maxDimensionX);
                        if (LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            MB2_Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimensionY);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("increasing 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;
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                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 <Image> images = new List <Image>();

            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) ||
                recursionDepth > MAX_RECURSION_DEPTH)
            {
                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++)
                {
                    Image 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;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + (paddings[i].leftRight * 2) + "x" + (paddings[i].topBottom * 2));
                    }
                }
                res.CalcUsedWidthAndHeight();
                return(res);
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("==================== REDOING PACKING ================");
                }
                //root = null;
                return(_GetRectsSingleAtlas(imgWidthHeights, paddings, maxDimensionX, maxDimensionY, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, recursionDepth + 1));
            }


            //if (LOG_LEVEL >= MB2_LogLevel.debug) MB2_Log.LogDebug(String.Format("Done GetRects atlasW={0} atlasH={1}", bestRoot.w, bestRoot.h));

            //return res;
        }
        Rect[] _GetRects(List <Vector2> imgWidthHeights, int maxDimension, int padding, int minImageSizeX, int minImageSizeY, int masterImageSizeX, int masterImageSizeY, out int outW, out int outH, int recursionDepth)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("_GetRects numImages={0}, maxDimension={1}, padding={2}, minImageSizeX={3}, minImageSizeY={4}, masterImageSizeX={5}, masterImageSizeY={6}, recursionDepth={7}",
                                        imgWidthHeights.Count, maxDimension, padding, minImageSizeX, minImageSizeY, masterImageSizeX, masterImageSizeY, recursionDepth));
            }
            if (recursionDepth > 10)
            {
                Debug.LogError("Maximum recursion depth reached. Couldn't find packing for these textures.");
                outW = 0;
                outH = 0;
                return(new Rect[0]);
            }
            float area = 0;
            int   maxW = 0;
            int   maxH = 0;

            Image[] imgsToAdd = new Image[imgWidthHeights.Count];
            for (int i = 0; i < imgsToAdd.Length; i++)
            {
                Image im = imgsToAdd[i] = new Image(i, (int)imgWidthHeights[i].x, (int)imgWidthHeights[i].y, padding, minImageSizeX, minImageSizeY);
                area += im.w * im.h;
                maxW  = Mathf.Max(maxW, im.w);
                maxH  = Mathf.Max(maxH, im.h);
            }

            if ((float)maxH / (float)maxW > 2)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using height Comparer");
                }
                Array.Sort(imgsToAdd, new ImageHeightComparer());
            }
            else if ((float)maxH / (float)maxW < .5)
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using width Comparer");
                }
                Array.Sort(imgsToAdd, new ImageWidthComparer());
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("Using area Comparer");
                }
                Array.Sort(imgsToAdd, new ImageAreaComparer());
            }

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

            if (doPowerOfTwoTextures)
            {
                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(area / maxW), maxH);
                }
                if (maxH > sqrtArea)
                {
                    idealAtlasW = Mathf.Max(Mathf.CeilToInt(area / maxH), maxW);
                    idealAtlasH = maxH;
                }
            }
            if (idealAtlasW == 0)
            {
                idealAtlasW = 1;
            }
            if (idealAtlasH == 0)
            {
                idealAtlasH = 1;
            }
            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();
                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log("Probing h=" + steppedHeight + " w=" + steppedWidth);
                    }
                    if (Probe(imgsToAdd, steppedWidth, steppedHeight, area, maxDimension, pr))
                    {
                        successW = true;
                        if (bestRoot == null)
                        {
                            bestRoot = pr;
                        }
                        else if (pr.GetScore(doPowerOfTwoTextures) > bestRoot.GetScore(doPowerOfTwoTextures))
                        {
                            bestRoot = pr;
                        }
                    }
                    else
                    {
                        numWIterations++;
                        steppedWidth = StepWidthHeight(steppedWidth, stepW, maxDimension);
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            MB2_Log.LogDebug("increasing Width h=" + steppedHeight + " w=" + steppedWidth);
                        }
                    }
                }
                steppedHeight = StepWidthHeight(steppedHeight, stepH, maxDimension);
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    MB2_Log.LogDebug("increasing Height h=" + steppedHeight + " w=" + steppedWidth);
                }
            }

            outW = 0;
            outH = 0;
            if (doPowerOfTwoTextures)
            {
                outW = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.w), maxDimension);
                outH = Mathf.Min(CeilToNearestPowerOfTwo(bestRoot.h), maxDimension);
                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 = bestRoot.w;
                outH = bestRoot.h;
            }
            if (bestRoot == null)
            {
                return(null);
            }
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("Best fit found: atlasW=" + outW + " atlasH" + outH + " w=" + bestRoot.w + " h=" + bestRoot.h + " efficiency=" + bestRoot.efficiency + " squareness=" + bestRoot.squareness + " fits in max dimension=" + bestRoot.fitsInMaxSize);
            }

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

            flattenTree(bestRoot.root, images);
            images.Sort(new ImgIDComparer());
            if (images.Count != imgsToAdd.Length)
            {
                Debug.LogError("Result images not the same lentgh as source");
            }

            //scale images if too large
            int   newMinSizeX = minImageSizeX;
            int   newMinSizeY = minImageSizeY;
            bool  redoPacking = false;
            float padX        = (float)padding / (float)outW;

            if (bestRoot.w > maxDimension)
            {
                //float minSizeX = ((float)minImageSizeX + 1) / maxDimension;
                padX = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)bestRoot.w;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas width shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image 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
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            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 = maxDimension;
            }

            float padY = (float)padding / (float)outH;

            if (bestRoot.h > maxDimension)
            {
                //float minSizeY = ((float)minImageSizeY + 1) / maxDimension;
                padY = (float)padding / (float)maxDimension;
                float scaleFactor = (float)maxDimension / (float)bestRoot.h;
                if (LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Packing exceeded atlas height shrinking to " + scaleFactor);
                }
                for (int i = 0; i < images.Count; i++)
                {
                    Image 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
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            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 = maxDimension;
            }

            Rect[] rs;
            if (!redoPacking)
            {
                rs = new Rect[images.Count];
                for (int i = 0; i < images.Count; i++)
                {
                    Image im = images[i];
                    Rect  r  = rs[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);
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        MB2_Log.LogDebug("Image: " + i + " imgID=" + im.imgId + " x=" + r.x * outW +
                                         " y=" + r.y * outH + " w=" + r.width * outW +
                                         " h=" + r.height * outH + " padding=" + padding);
                    }
                }
            }
            else
            {
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("==================== REDOING PACKING ================");
                }
                bestRoot = null;
                rs       = _GetRects(imgWidthHeights, maxDimension, padding, newMinSizeX, newMinSizeY, masterImageSizeX, masterImageSizeY, out outW, out outH, recursionDepth + 1);
            }

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                MB2_Log.LogDebug("Done GetRects");
            }
            return(rs);
        }