// multiAtlas=true, powerOfTwo, padding=8 in X
    void Test1()
    {
        texturePacker = new MB2_TexturePacker();
        texturePacker.doPowerOfTwoTextures = true;
        List <Vector2> images = new List <Vector2>();

        images.Add(new Vector2(450, 200));
        images.Add(new Vector2(450, 200));
        images.Add(new Vector2(450, 80));
        texturePacker.LOG_LEVEL = logLevel;
        rs = texturePacker.GetRects(images, 512, 8, true);
        Debug.Assert(rs.Length == 2);

        /*
         * Debug.Assert(rs[0].atlasX == 512, rs[0].atlasX);
         * Debug.Assert(rs[0].atlasY == 512, rs[0].atlasY);
         * Debug.Assert(rs[0].usedW == 466, rs[0].usedW);
         * Debug.Assert(rs[0].usedH == 432, rs[0].usedH);
         * Debug.Assert(rs[1].atlasX == 512, rs[1].atlasX);
         * Debug.Assert(rs[1].atlasY == 256, rs[1].atlasY);
         * Debug.Assert(rs[1].usedW == 466, rs[1].usedW);
         * Debug.Assert(rs[1].usedH == 96, rs[1].usedH);
         */
        Debug.Log("Success! ");
    }
    public void RunTestHarness()
    {
        texturePacker = new MB2_TexturePacker();

        texturePacker.doPowerOfTwoTextures = doPowerOfTwoTextures;
        texturePacker.LOG_LEVEL            = logLevel;

        rs = texturePacker.GetRects(imgsToAdd, maxDim, padding, doMultiAtlas);
        if (rs != null)
        {
            Debug.Log("NumAtlas= " + rs.Length);
            for (int i = 0; i < rs.Length; i++)
            {
                for (int j = 0; j < rs[i].rects.Length; j++)
                {
                    Rect r = rs[i].rects[j];
                    r.x      *= rs[i].atlasX;
                    r.y      *= rs[i].atlasY;
                    r.width  *= rs[i].atlasX;
                    r.height *= rs[i].atlasY;
                    Debug.Log(r.ToString("f5"));
                }
                Debug.Log("===============");
            }
            res = "mxX= " + rs[0].atlasX + " mxY= " + rs[0].atlasY;
        }
        else
        {
            res = "ERROR: PACKING FAILED";
        }
    }
Example #3
0
    // multiAtlas=true, powerOfTwo=false, padding=8 in Y
    void Test4()
    {
        texturePacker = new MB2_TexturePackerRegular();
        texturePacker.atlasMustBePowerOfTwo = false;
        List <Vector2> images = new List <Vector2>();

        images.Add(new Vector2(200, 450));
        images.Add(new Vector2(200, 450));
        images.Add(new Vector2(80, 450));
        texturePacker.LOG_LEVEL = logLevel;
        rs = texturePacker.GetRects(images, 512, 8, true);
        Debug.Assert(rs.Length == 2);

        /*
         * Debug.Assert(rs[0].atlasX == 432, rs[0].atlasX);
         * Debug.Assert(rs[0].atlasY == 466, rs[0].atlasY);
         * Debug.Assert(rs[0].usedW == 432, rs[0].usedW);
         * Debug.Assert(rs[0].usedH == 466, rs[0].usedH);
         * Debug.Assert(rs[1].atlasX == 96, rs[1].atlasX);
         * Debug.Assert(rs[1].atlasY == 466, rs[1].atlasY);
         * Debug.Assert(rs[1].usedW == 96, rs[1].usedW);
         * Debug.Assert(rs[1].usedH == 466, rs[1].usedH);
         */
        Debug.Log("Success! ");
    }
Example #4
0
    public void RunTestHarness()
    {
        if (packerType == PackerType.regular)
        {
            texturePacker = new MB2_TexturePackerRegular();
        }
        else if (packerType == PackerType.horizontal)
        {
            MB2_TexturePackerHorizontalVert tp = new MB2_TexturePackerHorizontalVert();
            tp.packingOrientation = MB2_TexturePackerHorizontalVert.TexturePackingOrientation.horizontal;
            texturePacker         = tp;
        }
        else if (packerType == PackerType.vertical)
        {
            MB2_TexturePackerHorizontalVert tp = new MB2_TexturePackerHorizontalVert();
            tp.packingOrientation = MB2_TexturePackerHorizontalVert.TexturePackingOrientation.vertical;
            texturePacker         = tp;
        }

        texturePacker.atlasMustBePowerOfTwo = atlasMustBePowerOfTwo;
        texturePacker.LOG_LEVEL             = logLevel;

        rs = texturePacker.GetRects(imgsToAdd, maxDim, padding, doMultiAtlas);
        if (rs != null)
        {
            Debug.Log("NumAtlas= " + rs.Length);
            for (int i = 0; i < rs.Length; i++)
            {
                Debug.Log("AtlasSize " + rs[i].atlasX + " mxY= " + rs[i].atlasY);
                for (int j = 0; j < rs[i].rects.Length; j++)
                {
                    Rect r = rs[i].rects[j];
                    r.x      *= rs[i].atlasX;
                    r.y      *= rs[i].atlasY;
                    r.width  *= rs[i].atlasX;
                    r.height *= rs[i].atlasY;
                    Debug.Log(r.ToString("f5"));
                }
                Vector2            offset = new Vector2((i * 1.5f) * maxDim, 0);
                AtlasPackingResult apr    = rs[i];
                Vector2            center = new Vector2(offset.x + apr.atlasX / 2, offset.y + apr.atlasY / 2);
                Vector2            sz     = new Vector2(apr.atlasX, apr.atlasY);

                Debug.Log("===============");
            }
            if (rs.Length > 0)
            {
                res = "mxX= " + rs[0].atlasX + " mxY= " + rs[0].atlasY;
            }
        }
        else
        {
            res = "ERROR: PACKING FAILED";
        }
    }
 public void GenerateListOfImagesToAdd()
 {
     imgsToAdd = new List <Vector2>();
     for (int i = 0; i < numTex; i++)
     {
         Vector2 img = new Vector2(Mathf.RoundToInt(UnityEngine.Random.Range(min, max) * xMult), Mathf.RoundToInt(UnityEngine.Random.Range(min, max) * yMult));
         if (imgsMustBePowerOfTwo)
         {
             img.x = MB2_TexturePacker.RoundToNearestPositivePowerOfTwo((int)img.x);
             img.y = MB2_TexturePacker.RoundToNearestPositivePowerOfTwo((int)img.y);
         }
         imgsToAdd.Add(img);
     }
 }
		Rect[] __CreateAtlasesMBTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<string> texPropertyNames, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding){
			Rect[] uvRects;
			if (distinctMaterialTextures.Count == 1){
				if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
				uvRects = new Rect[1];
				uvRects[0] = new Rect(0f,0f,1f,1f);
				for (int i = 0; i < numAtlases; i++){
					MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
					atlases[i] = dmt.t;
					resultMaterial.SetTexture(texPropertyNames[i],atlases[i]);
					resultMaterial.SetTextureScale(texPropertyNames[i],dmt.scale);
					resultMaterial.SetTextureOffset(texPropertyNames[i],dmt.offset);
				}
			} else {
				List<Vector2> imageSizes = new List<Vector2>();
				for (int i = 0; i < distinctMaterialTextures.Count; i++){
					imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight));	
				}
				MB2_TexturePacker tp = new MB2_TexturePacker();
				int atlasSizeX = 1;
				int atlasSizeY = 1;
				
				//todo add sanity warnings for huge atlasesr
				int atlasMaxDimension = 4096;
				
				if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension();
				
				uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY);
				if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")");
				for (int i = 0; i < numAtlases; i++){
					GC.Collect();
					if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i] + "'", .01f);
					Color[] atlasPixels = new Color[atlasSizeX * atlasSizeY];//atlas.GetPixels();
					for (int j = 0; j < atlasPixels.Length; j++) atlasPixels[j] = Color.clear;
					for (int j = 0; j < distinctMaterialTextures.Count; j++){
						if (LOG_LEVEL >= MB2_LogLevel.trace) MB2_Log.Trace("Adding texture {0} to atlas {1}", distinctMaterialTextures[j].ts[i].t == null ? "null" : distinctMaterialTextures[j].ts[i].t.ToString(),texPropertyNames[i]);
						Rect r = uvRects[j];
						Texture2D t = distinctMaterialTextures[j].ts[i].t;
						int x = Mathf.RoundToInt(r.x * atlasSizeX);
						int y = Mathf.RoundToInt(r.y * atlasSizeY);
						int ww = Mathf.RoundToInt(r.width * atlasSizeX);
						int hh = Mathf.RoundToInt(r.height * atlasSizeY);
						if (ww == 0 || hh == 0) Debug.LogError("Image in atlas has no height or width");
						if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(t, true, true);
						if (progressInfo != null) progressInfo("Copying to atlas: '" + distinctMaterialTextures[j].ts[i].t + "'", .02f);
						CopyScaledAndTiledToAtlas(distinctMaterialTextures[j].ts[i],x,y,ww,hh,fixOutOfBoundsUVs,maxTilingBakeSize,atlasPixels,atlasSizeX,progressInfo);
					}
					if (progressInfo != null) progressInfo("Applying changes to atlas: '" + texPropertyNames[i] + "'", .03f);
					Texture2D atlas = new Texture2D(atlasSizeX, atlasSizeY,TextureFormat.ARGB32, true);
					atlas.SetPixels(atlasPixels);
					atlas.Apply();
					if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i] + " w=" + atlas.width + " h=" + atlas.height);
					atlases[i] = atlas;
					if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i] + "'", .04f);
					if (saveAtlasesAsAssets && textureEditorMethods != null){
						textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
					} else {
						resultMaterial.SetTexture(texPropertyNames[i], atlases[i]);
					}
					resultMaterial.SetTextureOffset(texPropertyNames[i], Vector2.zero);
					resultMaterial.SetTextureScale(texPropertyNames[i],Vector2.one);
					_destroyTemporaryTextures(); // need to save atlases before doing this				
				}
			}
			return uvRects;
		}
        Rect[] __CreateAtlasesMBTexturePackerFast(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding)
        {
            Rect[] uvRects;
            if (distinctMaterialTextures.Count == 1){
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
                uvRects = new Rect[1];
                uvRects[0] = new Rect(0f,0f,1f,1f);
                for (int i = 0; i < numAtlases; i++){
                    MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.t;
                    resultMaterial.SetTexture(texPropertyNames[i].name,atlases[i]);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,dmt.scale);
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name,dmt.offset);
                }
            } else {
                List<Vector2> imageSizes = new List<Vector2>();
                for (int i = 0; i < distinctMaterialTextures.Count; i++){
                    imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight));
                }
                MB2_TexturePacker tp = new MB2_TexturePacker();
                tp.doPowerOfTwoTextures = _meshBakerTexturePackerForcePowerOfTwo;
                int atlasSizeX = 1;
                int atlasSizeY = 1;

                //todo add sanity warnings for huge atlasesr
                int atlasMaxDimension = _maxAtlasSize;

                //if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension();

                uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY);
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")");

                //create a game object
                GameObject renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent<MB3_AtlasPackerRenderTexture>();
                for (int i = 0; i < numAtlases; i++){
                    Texture2D atlas = null;
                    if (allTexturesAreNullAndSameColor[i]){
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Not creating atlas for " + texPropertyNames[i].name + " because textures are null and default value parameters are the same.");
                    } else {
                        GC.Collect();
                        if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i].name + "'", .01f);
                        // ===========
                        // configure it
                        atlasRenderTexture.width = atlasSizeX;
                        atlasRenderTexture.height = atlasSizeY;
                        atlasRenderTexture.padding = _padding;
                        atlasRenderTexture.rects = uvRects;
                        atlasRenderTexture.textureSets = distinctMaterialTextures;
                        atlasRenderTexture.indexOfTexSetToRender = 0;
                        // call render on it
                        atlas = atlasRenderTexture.OnRenderAtlas();
                        // destroy it
                        // =============
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height);
                    }
                    atlases[i] = atlas;
                    if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i].name + "'", .04f);
                    if (_saveAtlasesAsAssets && textureEditorMethods != null){
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
                    } else {
                        resultMaterial.SetTexture(texPropertyNames[i].name, atlases[i]);
                    }
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name, Vector2.zero);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,Vector2.one);
                    _destroyTemporaryTextures(); // need to save atlases before doing this
                }
            }
            return uvRects;
        }
        Rect[] __CreateAtlasesMBTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding)
        {
            Rect[] uvRects;
            if (distinctMaterialTextures.Count == 1){
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
                uvRects = new Rect[1];
                uvRects[0] = new Rect(0f,0f,1f,1f);
                for (int i = 0; i < numAtlases; i++){
                    MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.t;
                    resultMaterial.SetTexture(texPropertyNames[i].name,atlases[i]);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,dmt.scale);
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name,dmt.offset);
                }
            } else {
                List<Vector2> imageSizes = new List<Vector2>();
                for (int i = 0; i < distinctMaterialTextures.Count; i++){
                    imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight));
                }
                MB2_TexturePacker tp = new MB2_TexturePacker();
                tp.doPowerOfTwoTextures = _meshBakerTexturePackerForcePowerOfTwo;
                int atlasSizeX = 1;
                int atlasSizeY = 1;

                //todo add sanity warnings for huge atlasesr
                int atlasMaxDimension = _maxAtlasSize;

                //if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension();

                uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY);
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")");
                for (int i = 0; i < numAtlases; i++){
                    Texture2D atlas = null;
                    if (allTexturesAreNullAndSameColor[i]){
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Not creating atlas for " + texPropertyNames[i].name + " because textures are null and default value parameters are the same.");
                    } else {
                        GC.Collect();
                        if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i].name + "'", .01f);
                        //use a jagged array because it is much more efficient in memory
                        Color[][] atlasPixels = new Color[atlasSizeY][];
                        for (int j = 0; j < atlasPixels.Length; j++){
                            atlasPixels[j] = new Color[atlasSizeX];
                        }
                        bool isNormalMap = false;
                        if (texPropertyNames[i].isNormalMap) isNormalMap = true;
            //						for (int j = 0; j < atlasPixels.Length; j++) {
            //							for (int k = 0; k < atlasSizeX; k++){
            //								atlasPixels[j][k] = GetColorIfNoTexture(
            //								if (isNormalMap){
            //									atlasPixels[j][k] = new Color(.5f,.5f,1f); //neutral bluish for normal maps
            //								} else {
            //									atlasPixels[j][k] = Color.clear;
            //								}
            //							}
            //						}
                        for (int j = 0; j < distinctMaterialTextures.Count; j++){
                            if (LOG_LEVEL >= MB2_LogLevel.trace) MB2_Log.Trace("Adding texture {0} to atlas {1}", distinctMaterialTextures[j].ts[i].t == null ? "null" : distinctMaterialTextures[j].ts[i].t.ToString(),texPropertyNames[i]);
                            Rect r = uvRects[j];
                            Texture2D t = distinctMaterialTextures[j].ts[i].t;
                            int x = Mathf.RoundToInt(r.x * atlasSizeX);
                            int y = Mathf.RoundToInt(r.y * atlasSizeY);
                            int ww = Mathf.RoundToInt(r.width * atlasSizeX);
                            int hh = Mathf.RoundToInt(r.height * atlasSizeY);
                            if (ww == 0 || hh == 0) Debug.LogError("Image in atlas has no height or width");
                            if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(t, true, true);
                            if (progressInfo != null) progressInfo("Copying to atlas: '" + distinctMaterialTextures[j].ts[i].t + "'", .02f);
                            CopyScaledAndTiledToAtlas(distinctMaterialTextures[j].ts[i],x,y,ww,hh,_fixOutOfBoundsUVs,_maxTilingBakeSize,atlasPixels,atlasSizeX,isNormalMap,progressInfo);
                        }
                        if (progressInfo != null) progressInfo("Applying changes to atlas: '" + texPropertyNames[i].name + "'", .03f);
                        atlas = new Texture2D(atlasSizeX, atlasSizeY,TextureFormat.ARGB32, true);
                        for (int j = 0; j < atlasPixels.Length; j++){
                            atlas.SetPixels(0,j,atlasSizeX,1,atlasPixels[j]);
                        }
                        atlas.Apply();
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height);
                    }
                    atlases[i] = atlas;
                    if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i].name + "'", .04f);
                    if (_saveAtlasesAsAssets && textureEditorMethods != null){
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
                    } else {
                        resultMaterial.SetTexture(texPropertyNames[i].name, atlases[i]);
                    }
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name, Vector2.zero);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,Vector2.one);
                    _destroyTemporaryTextures(); // need to save atlases before doing this
                }
            }
            return uvRects;
        }