Example #1
0
//    private static float timestart;

    /// <summary>
    /// Custom BuildR texture packer. Uses the BuildR Data class to create a single texture used by the generated building, taking into account tiling.
    /// </summary>
    /// <param name="data">BuildR Building Data</param>
    public static void Pack(BuildrData data)
    {
//        timestart = Time.realtimeSinceStartup;
        data.texturesNotPacked.Clear();
        data.texturesPacked.Clear();

        int         numberOfTextures       = data.textures.Count;
        List <Rect> packedTexturePositions = new List <Rect>();
        List <int>  texturePacked          = new List <int>();

        for (int t = 0; t < numberOfTextures; t++)
        {
            BuildrTexture texture = data.textures[t];
            if (texture.tiled)
            {
                int   textureWidth        = texture.texture.width;
                int   textureHeight       = texture.texture.height;
                int   targetTextureWidth  = Mathf.RoundToInt(textureWidth * texture.maxUVTile.x);
                int   targetTextureHeight = Mathf.RoundToInt(textureHeight * texture.maxUVTile.y);
                float resizeToLargest     = Mathf.Min((float)MAX_SOURCE_TEXTURE_SIZE / (float)targetTextureWidth, (float)MAX_SOURCE_TEXTURE_SIZE / (float)targetTextureHeight, 1);//ensure texture fits smallest size
                int   useTextureWidth     = Mathf.RoundToInt(resizeToLargest * targetTextureWidth);
                int   useTextureHeight    = Mathf.RoundToInt(resizeToLargest * targetTextureHeight);

                if (useTextureWidth == 0 || useTextureHeight == 0)//texture no used on model
                {
                    data.texturesNotPacked.Add(t);
                    continue;
                }
                packedTexturePositions.Add(new Rect(0, 0, useTextureWidth, useTextureHeight));
                texturePacked.Add(t);
            }
            else
            {
                int useTextureWidth  = texture.texture.width;
                int useTextureHeight = texture.texture.height;
                packedTexturePositions.Add(new Rect(0, 0, useTextureWidth, useTextureHeight));
                texturePacked.Add(t);
            }
        }

        int atlasedTextureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING);

        //determine the resize scale and apply that to the rects
        float packedScale   = 1;
        int   numberOfRects = packedTexturePositions.Count;

        if (atlasedTextureWidth > MAXIMUM_TEXTURESIZE)
        {
            packedScale = MAXIMUM_TEXTURESIZE / (float)atlasedTextureWidth;
            for (int i = 0; i < numberOfRects; i++)
            {
                Rect thisRect = packedTexturePositions[i];
                thisRect.x               *= packedScale;
                thisRect.y               *= packedScale;
                thisRect.width           *= packedScale;
                thisRect.height          *= packedScale;
                packedTexturePositions[i] = thisRect;
            }
            atlasedTextureWidth = Mathf.RoundToInt(packedScale * atlasedTextureWidth);
        }
        else
        {
            atlasedTextureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(atlasedTextureWidth - 1, 2)) + 1));//find the next power of two
        }

        int textureSize = atlasedTextureWidth * atlasedTextureWidth;

        Color32[] colourArray = new Color32[textureSize];

        //Build colour array
        for (int t = 0; t < numberOfTextures; t++)
        {
            BuildrTexture texture             = data.textures[t];
            Rect          packedPosition      = packedTexturePositions[t];
            int           targetTextureWidth  = (int)packedPosition.width;
            int           targetTextureHeight = (int)packedPosition.height;
            int           sourceTextureWidth  = texture.texture.width;
            int           sourceTextureHeight = texture.texture.height;
//            int sourceTextureSize = sourceTextureWidth * sourceTextureHeight;
            int       paintTextureWidth  = Mathf.RoundToInt(targetTextureWidth / (texture.tiled ? texture.maxUVTile.x : texture.tiledX));
            int       paintTextureHeight = Mathf.RoundToInt(targetTextureHeight / (texture.tiled ? texture.maxUVTile.y : texture.tiledY));
            int       paintTextureSize   = paintTextureWidth * paintTextureHeight;
            Color32[] paintColourArray   = TextureScale.NearestNeighbourSample(texture.texture.GetPixels32(), sourceTextureWidth, sourceTextureHeight, paintTextureWidth, paintTextureHeight);

            for (int x = 0; x < targetTextureWidth; x++)
            {
                for (int y = 0; y < targetTextureHeight; y++)
                {
                    int drawX       = Mathf.FloorToInt(x + packedPosition.x);
                    int drawY       = Mathf.FloorToInt(y + packedPosition.y);
                    int colourIndex = drawX + drawY * atlasedTextureWidth;

                    int sx         = x % paintTextureWidth;
                    int sy         = y % paintTextureHeight;
                    int paintIndex = sx + sy * paintTextureWidth;
                    if (paintIndex >= paintTextureSize)
                    {
                        Debug.Log("Source Index too big " + sx + " " + sy + " " + paintTextureWidth + " " + paintTextureSize + " " + texture.maxUVTile + " " + texture.name);
                    }
                    Color32 sourceColour = paintColourArray[paintIndex];
                    if (colourIndex >= textureSize)
                    {
                        Debug.Log("Output Index Too big " + drawX + " " + drawY + " " + colourIndex + " " + textureSize + " " + packedPosition);
                    }
                    colourArray[colourIndex] = sourceColour;
                }
            }
        }

        Texture2D packedTexture = new Texture2D(atlasedTextureWidth, atlasedTextureWidth, TextureFormat.ARGB32, true);

        packedTexture.filterMode = FilterMode.Bilinear;
        packedTexture.SetPixels32(colourArray);
        packedTexture.Apply(true, false);

        //remove textures from memory
        if (data.textureAtlas != null)
        {
            DestroyImmediate(data.textureAtlas);
        }

        data.textureAtlas   = packedTexture;
        data.texturesPacked = texturePacked;
        data.atlasCoords    = RectanglePack.ConvertToUVSpace(packedTexturePositions.ToArray(), atlasedTextureWidth);

        System.GC.Collect();

        //Debug.Log("BuildR Texutre Pack Complete: " + (Time.realtimeSinceStartup - timestart)+" sec");
    }
Example #2
0
    private static void BuildTextures()
    {
        List <TexturePaintObject> buildSourceTextures = new List <TexturePaintObject>();

        foreach (BuildrTexture btexture in data.textures)//Gather the source textures, resized into Color32 arrays
        {
            TexturePaintObject texturePaintObject = new TexturePaintObject();
            texturePaintObject.pixels = ((Texture2D)btexture.texture).GetPixels32();
            texturePaintObject.width  = btexture.texture.width;
            texturePaintObject.height = btexture.texture.height;
            texturePaintObject.tiles  = new Vector2(btexture.tiledX, btexture.tiledY);
            if (btexture.tiled)
            {
                int resizedTextureWidth  = Mathf.RoundToInt(btexture.textureUnitSize.x * PIXELS_PER_METER * packedScale);
                int resizedTextureHeight = Mathf.RoundToInt(btexture.textureUnitSize.y * PIXELS_PER_METER * packedScale);
                texturePaintObject.pixels = TextureScale.NearestNeighbourSample(texturePaintObject.pixels, texturePaintObject.width, texturePaintObject.height, resizedTextureWidth, resizedTextureHeight);
                texturePaintObject.width  = resizedTextureWidth;
                texturePaintObject.height = resizedTextureHeight;
            }
            else
            {
                texturePaintObject.tiled = false;
            }
            buildSourceTextures.Add(texturePaintObject);
        }
        LogTimer("Gather Source into Arrays");
        TexturePaintObject[] sourceTextures = buildSourceTextures.ToArray();
        textures = data.textures.ToArray();
        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan         plan         = data.plan;

        int numberOfVolumes = data.plan.numberOfVolumes;
        int facadeNumber    = 0;

        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int     indexA, indexB;
                Vector3 p0, p1;
                indexA = f;
                indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                p0     = plan.points[volume.points[indexA]].vector3;
                p1     = plan.points[volume.points[indexB]].vector3;
                Rect packedPosition = packedTexturePositions[facadeNumber];

                float facadeWidth    = Vector3.Distance(p0, p1);
                int   floorBase      = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int   numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int        floorPatternSize         = 0;
                List <int> facadePatternReference   = new List <int>();  //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int        patternCount             = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                    {
                        facadePatternReference.Add(patternCount);
                    }
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                Vector2 bayBase          = Vector2.zero;
                float   currentFloorBase = 0;
                for (int r = 0; r < rows; r++)
                {
                    currentFloorBase = floorHeight * r;
                    int modFloor = (r % floorPatternSize);

                    facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                        if (firstBay.openingWidth > facadeWidth)
                        {
                            isBlankWall = true;
                        }
                        if (facadeDesign.bayPattern.Count == 0)
                        {
                            isBlankWall = true;
                        }
                    }
                    else
                    {
                        if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                        {
                            isBlankWall = true;
                        }
                    }
                    if (!isBlankWall)
                    {
                        float       patternSize  = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int         numberOfBays = 0;
                        BuildrBay[] bays;
                        int         numberOfBayDesigns = 0;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bays = new BuildrBay[numberOfBayDesigns];
                            for (int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bays[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bays = new[] { facadeDesign.simpleBay };
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while (true)
                        {
                            int   patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bays[patternModIndex].openingWidth + bays[patternModIndex].minimumBayWidth;
                            if (patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                            {
                                break;
                            }
                            it--;
                            if (it < 0)
                            {
                                break;
                            }
                        }
                        float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;

                        float windowXBase = 0;
                        for (int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;
                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bays[c % numberOfBayStyles];
                            }
                            else
                            {
                                bayStyle = facadeDesign.simpleBay;
                            }
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftSpace           = actualWindowSpacing * bayStyle.openingWidthRatio;
                            float rightSpace          = actualWindowSpacing - leftSpace;
                            float openingSpace        = bayStyle.openingWidth;

                            Vector3 bayDimensions;
                            int     subMesh;
                            bool    flipped;

                            if (!bayStyle.isOpening)
                            {
                                subMesh   = bayStyle.GetTexture(BuildrBay.TextureNames.WallTexture);
                                flipped   = bayStyle.IsFlipped(BuildrBay.TextureNames.WallTexture);
                                bayBase.x = windowXBase;
                                bayBase.y = currentFloorBase;
                                float bayWidth  = (openingSpace + actualWindowSpacing);
                                float bayHeight = floorHeight;
                                bayDimensions = new Vector2(bayWidth, bayHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                windowXBase += bayWidth; //move base vertor to next bay
                                continue;                //bay filled - move onto next bay
                            }

                            float rowBottomHeight = ((floorHeight - bayStyle.openingHeight) * bayStyle.openingHeightRatio);
                            float rowTopHeight    = (floorHeight - rowBottomHeight - bayStyle.openingHeight);

                            //Window
                            subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                            flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                            bayBase.x     = windowXBase + leftSpace;
                            bayBase.y     = currentFloorBase + rowBottomHeight;
                            bayDimensions = new Vector2(bayStyle.openingWidth, bayStyle.openingHeight);
                            DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                            //Column Left
                            if (leftSpace > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                                bayBase.x     = windowXBase;
                                bayBase.y     = currentFloorBase + rowBottomHeight;
                                bayDimensions = new Vector2(leftSpace, bayStyle.openingHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Column Right
                            if (rightSpace > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                                bayBase.x     = windowXBase + leftSpace + openingSpace;
                                bayBase.y     = currentFloorBase + rowBottomHeight;
                                bayDimensions = new Vector2(rightSpace, bayStyle.openingHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Row Bottom
                            if (rowBottomHeight > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                                bayBase.x     = windowXBase + leftSpace;
                                bayBase.y     = currentFloorBase;
                                bayDimensions = new Vector2(openingSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Row Top
                            if (rowTopHeight > 0)
                            {
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                                bayBase.x     = windowXBase + leftSpace;
                                bayBase.y     = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(openingSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Cross Left
                            if (leftSpace > 0)
                            {
                                //Cross Left Bottom
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase;
                                bayBase.y     = currentFloorBase;
                                bayDimensions = new Vector2(leftSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                //Cross Left Top
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase;
                                bayBase.y     = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(leftSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            //Cross Right
                            if (rightSpace > 0)
                            {
                                //Cross Left Bottom
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase + leftSpace + openingSpace;
                                bayBase.y     = currentFloorBase;
                                bayDimensions = new Vector2(rightSpace, rowBottomHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);

                                //Cross Left Top
                                subMesh       = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                                flipped       = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                                bayBase.x     = windowXBase + leftSpace + openingSpace;
                                bayBase.y     = currentFloorBase + rowBottomHeight + bayStyle.openingHeight;
                                bayDimensions = new Vector2(rightSpace, rowTopHeight);
                                DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition);
                            }

                            windowXBase += leftSpace + openingSpace + rightSpace;//move base vertor to next bay
                        }
                    }
                    else
                    {
                        // windowless wall
                        int  subMesh = facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture);
                        bool flipped = facadeDesign.simpleBay.IsFlipped(BuildrBay.TextureNames.WallTexture);
                        bayBase.x = 0;
                        bayBase.y = currentFloorBase;
                        Vector2 dimensions = new Vector2(facadeWidth, floorHeight);
                        DrawFacadeTexture(sourceTextures, bayBase, dimensions, subMesh, flipped, packedPosition);
                    }
                }
                facadeNumber++;
            }
        }
        LogTimer("generate facade textures");

        //add roof textures
        int numberOfroofTextures = roofTextures.Count;
        int scaledPadding        = Mathf.FloorToInt(ATLAS_PADDING * packedScale);

        for (int i = 0; i < numberOfroofTextures; i++)
        {
            Rect          roofTexturePosition = packedTexturePositions[i + facadeNumber];
            BuildrTexture bTexture            = roofTextures[i];
            int           roofTextureWidth    = bTexture.texture.width;
            int           roofTextureHeight   = bTexture.texture.height;
            int           targetTextureWidth  = Mathf.RoundToInt(roofTexturePosition.width);
            int           targetTextureHeight = Mathf.RoundToInt(roofTexturePosition.height);
            if (bTexture.maxUVTile == Vector2.zero)
            {
                LogTimer("BuildTextures: Skip texture " + bTexture.name + " as it appears it's not used");
                continue;
            }
            int sourceTextureWidth  = Mathf.RoundToInt(targetTextureWidth / (bTexture.tiled ? bTexture.maxUVTile.x : bTexture.tiledX));
            int sourceTextureHeight = Mathf.RoundToInt(targetTextureHeight / (bTexture.tiled ? bTexture.maxUVTile.y : bTexture.tiledY));
            int sourceTextureSize   = sourceTextureWidth * sourceTextureHeight;
            if (sourceTextureSize == 0)
            {
                //Debug.Log(sourceTextureWidth+" "+sourceTextureHeight+" "+bTexture.tiledX+" "+bTexture.maxUVTile+" "+bTexture.tiledX+","+bTexture.tiledY);
                continue;
            }
            Color32[] roofColourArray = TextureScale.NearestNeighbourSample(((Texture2D)bTexture.texture).GetPixels32(), roofTextureWidth, roofTextureHeight, sourceTextureWidth, sourceTextureHeight);
            //Color32[] roofColourArray = bTexture.texture.GetPixels32();

            for (int x = 0; x < targetTextureWidth; x++)
            {
                for (int y = 0; y < targetTextureHeight; y++)
                {
                    int drawX       = Mathf.FloorToInt(x + roofTexturePosition.x);
                    int drawY       = Mathf.FloorToInt(y + roofTexturePosition.y);
                    int colourIndex = drawX + drawY * textureWidth;

                    int sx          = x % sourceTextureWidth;
                    int sy          = y % sourceTextureHeight;
                    int sourceIndex = sx + sy * sourceTextureWidth;
                    if (sourceIndex >= sourceTextureSize)
                    {
                        Debug.Log("Source Index too big " + sx + " " + sy + " " + sourceTextureWidth + " " + sourceTextureSize + " " + bTexture.maxUVTile + " " + bTexture.name);
                    }
                    Color32 sourceColour = roofColourArray[sourceIndex];
                    if (colourIndex >= textureSize)
                    {
                        Debug.Log("Output Index Too big " + drawX + " " + drawY + " " + colourIndex + " " + textureSize + " " + roofTexturePosition);
                    }
                    colourArray[colourIndex] = sourceColour;

                    //Padding
                    if (x == 0)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex - p] = sourceColour;
                        }
                    }
                    if (x == targetTextureWidth - 1)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex + p] = sourceColour;
                        }
                    }

                    if (y == 0)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex - (p * textureWidth)] = sourceColour;
                        }
                    }

                    if (y == targetTextureHeight - 1)
                    {
                        for (int p = 0; p < scaledPadding; p++)
                        {
                            colourArray[colourIndex + (p * textureWidth)] = sourceColour;
                        }
                    }
                }
            }
        }
        LogTimer("generate roof textures");
    }
Example #3
0
    /// <summary>
    /// Packs an array of Texture2Ds into a sinlgle Texture2D with a maximum size specified.
    /// </summary>
    /// <param name="output">The output Texture2D</param>
    /// <param name="data">And array of input Texture2Ds</param>
    /// <param name="maximumSize">The maximum size of the output texture</param>
    /// <returns></returns>
    public static Rect[] Pack(out Texture2D output, Texture2D[] data, int maximumSize)
    {
//        timestart = Time.realtimeSinceStartup;

        int         numberOfTextures       = data.Length;
        List <Rect> packedTexturePositions = new List <Rect>();
        List <int>  texturePacked          = new List <int>();

        for (int t = 0; t < numberOfTextures; t++)
        {
            Texture2D texture          = data[t];
            int       useTextureWidth  = texture.width;
            int       useTextureHeight = texture.height;
            packedTexturePositions.Add(new Rect(0, 0, useTextureWidth, useTextureHeight));
            texturePacked.Add(t);
        }

        int atlasedTextureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING);

        //determine the resize scale and apply that to the rects
        int numberOfRects = packedTexturePositions.Count;

        if (atlasedTextureWidth > maximumSize)
        {
            float packedScale = maximumSize / (float)atlasedTextureWidth;
            for (int i = 0; i < numberOfRects; i++)
            {
                Rect thisRect = packedTexturePositions[i];
                thisRect.x               *= packedScale;
                thisRect.y               *= packedScale;
                thisRect.width           *= packedScale;
                thisRect.height          *= packedScale;
                packedTexturePositions[i] = thisRect;
            }
            atlasedTextureWidth = Mathf.RoundToInt(packedScale * atlasedTextureWidth);
        }
        else
        {
            atlasedTextureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(atlasedTextureWidth - 1, 2)) + 1));//find the next power of two
        }

        int textureSize = atlasedTextureWidth * atlasedTextureWidth;

        Color32[] colourArray = new Color32[textureSize];

        //Build colour array
        for (int t = 0; t < numberOfTextures; t++)
        {
            Texture2D texture             = data[t];
            Rect      packedPosition      = packedTexturePositions[t];
            int       targetTextureWidth  = (int)packedPosition.width;
            int       targetTextureHeight = (int)packedPosition.height;
            int       sourceTextureWidth  = texture.width;
            int       sourceTextureHeight = texture.height;
            Color32[] paintColourArray    = TextureScale.NearestNeighbourSample(texture.GetPixels32(), sourceTextureWidth, sourceTextureHeight, targetTextureWidth, targetTextureHeight);

            for (int x = 0; x < targetTextureWidth; x++)
            {
                for (int y = 0; y < targetTextureHeight; y++)
                {
                    int     drawX        = Mathf.FloorToInt(x + packedPosition.x);
                    int     drawY        = Mathf.FloorToInt(y + packedPosition.y);
                    int     colourIndex  = drawX + drawY * atlasedTextureWidth;
                    int     paintIndex   = x + y * targetTextureWidth;
                    Color32 sourceColour = paintColourArray[paintIndex];
                    colourArray[colourIndex] = sourceColour;
                }
            }
        }

        output            = new Texture2D(atlasedTextureWidth, atlasedTextureWidth, TextureFormat.ARGB32, true);
        output.filterMode = FilterMode.Bilinear;
        output.SetPixels32(colourArray);
        output.Apply(true, false);

        //Debug.Log("BuildR Texutre Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec");

        return(RectanglePack.ConvertToUVSpace(packedTexturePositions.ToArray(), atlasedTextureWidth));
    }