Ejemplo n.º 1
0
    //Awake.
    void Awake()
    {
        //Detect whether the materials can be found. If not, report an error.
        if (shapeMaterial == null || pillowAndGlowMeshMaterial == null || pillowAndGlowRenderTextureMaterial == null)
        {
            Debug.LogError("At least one of the material properties on this Vector Sprites instance have been removed. The materials need to be assigned in " +
                           "order to create the sprites. Please re-assign them to this Vector Sprites instance (you may need to comment out the [HideInInspector] " +
                           "attributes on the material properties in \"VectorSprites.cs\" in order to assign them again).");
            return;
        }

        //Clear the sprites dictionary.
        sprites.Clear();

        //If the version is not up to date, don't do anything.
        if (!vectorSpritesProperties.updateVersion())
        {
            return;
        }

        //Set all meshes to dirty to ensure they are re-generated (the game quality might not match the editor quality).
        for (int i = 0; i < vectorSpritesProperties.shapeGroups.Count; i++)
        {
            for (int j = 0; j < vectorSpritesProperties.shapeGroups[i].shapes.Count; j++)
            {
                vectorSpritesProperties.shapeGroups[i].shapes[j].resetAllMeshes();
            }
        }

        //Create a Vector Sprites Renderer game object so the Vector Sprites can be rendered to textures.
        GameObject vectorSpritesRendererGameObject = new GameObject("Vector Sprites Renderer");

        vectorSpritesRendererGameObject.hideFlags = HideFlags.HideAndDontSave;
        VectorSpritesRenderer vectorSpritesRenderer = vectorSpritesRendererGameObject.AddComponent <VectorSpritesRenderer>();

        vectorSpritesRenderer.createdFromVectorSpritesInstance.flag = true;

        //Store the old selection so it can be restored after the sprites are generated.
        SelectableEntity oldSelectedEntity             = vectorSpritesProperties.selectedEntity;
        List <int>       oldSelectedEntityPrimaryIDs   = new List <int>();
        List <int>       oldSelectedEntitySecondaryIDs = new List <int>();

        for (int i = 0; i < vectorSpritesProperties.selectedEntities.Count; i++)
        {
            oldSelectedEntityPrimaryIDs.Add(vectorSpritesProperties.selectedEntities[i].primaryID);
            oldSelectedEntitySecondaryIDs.Add(vectorSpritesProperties.selectedEntities[i].secondaryID);
        }

        //Create the array of sprites, one for each Vector Sprite and loop over them in order to create them.
        for (int i = 0; i < vectorSpritesProperties.vectorSprites.Count; i++)
        {
            //Work out the sprite's scale.
            Vector2 meshScale = new Vector2(2, 2);
            if (vectorSpritesProperties.vectorSprites[i].spriteRectangleTransform == SpriteRectangleTransform.Crop)
            {
                if (vectorSpritesProperties.vectorSprites[i].width > vectorSpritesProperties.vectorSprites[i].height)
                {
                    meshScale.y *= (float)vectorSpritesProperties.vectorSprites[i].width / vectorSpritesProperties.vectorSprites[i].height;
                }
                else
                {
                    meshScale.x *= (float)vectorSpritesProperties.vectorSprites[i].height / vectorSpritesProperties.vectorSprites[i].width;
                }
            }

            //Render the sprite to a render texture. Double the size of the render texture if anti-aliasing is enabled (so it can be scaled back down).
            RenderTexture renderTexture = new RenderTexture(vectorSpritesProperties.vectorSprites[i].width *
                                                            (vectorSpritesProperties.vectorSprites[i].antialias ? 2 : 1), vectorSpritesProperties.vectorSprites[i].height *
                                                            (vectorSpritesProperties.vectorSprites[i].antialias ? 2 : 1), 16, RenderTextureFormat.ARGB32);
            renderTexture.hideFlags = HideFlags.HideAndDontSave;
            vectorSpritesProperties.selectedEntity = SelectableEntity.Sprite;
            vectorSpritesProperties.selectedEntities.Clear();
            vectorSpritesProperties.selectedEntities.Add(new SelectedEntity(i));
            vectorSpritesRenderer.render(vectorSpritesProperties, shapeMaterial, pillowAndGlowMeshMaterial, pillowAndGlowRenderTextureMaterial, renderTexture,
                                         meshScale, false);

            //Get the texture directly from the render texture.
            RenderTexture.active = renderTexture;
            Texture2D texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
            texture.wrapMode = TextureWrapMode.Clamp;
            texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0, false);
            texture.Apply();
            RenderTexture.active = null;
            DestroyImmediate(renderTexture);

            //Copy the texture to the master texture, scaling down for anti-aliasing purposes if required.
            if (vectorSpritesProperties.vectorSprites[i].antialias)
            {
                renderTexture = new RenderTexture(vectorSpritesProperties.vectorSprites[i].width, vectorSpritesProperties.vectorSprites[i].height, 16,
                                                  RenderTextureFormat.ARGB32);
                renderTexture.hideFlags = HideFlags.HideAndDontSave;
                Graphics.Blit(texture, renderTexture);
                DestroyImmediate(texture);
                texture = new Texture2D(vectorSpritesProperties.vectorSprites[i].width, vectorSpritesProperties.vectorSprites[i].height, TextureFormat.ARGB32,
                                        false);
                RenderTexture.active = renderTexture;
                texture.ReadPixels(new Rect(0, 0, vectorSpritesProperties.vectorSprites[i].width, vectorSpritesProperties.vectorSprites[i].height), 0, 0,
                                   false);
                RenderTexture.active = null;
                DestroyImmediate(renderTexture);
                texture.Apply();
            }

            //Create the sprite.
            vectorSpritesProperties.vectorSprites[i].sprite = Sprite.Create(texture, new Rect(0, 0, vectorSpritesProperties.vectorSprites[i].width,
                                                                                              vectorSpritesProperties.vectorSprites[i].height), new Vector2(0.5f, 0.5f));

            //Add the sprite to the dictionary if it doesn't contain one with the same name.
            if (!sprites.ContainsKey(vectorSpritesProperties.vectorSprites[i].name))
            {
                sprites.Add(vectorSpritesProperties.vectorSprites[i].name, vectorSpritesProperties.vectorSprites[i].sprite);
            }
        }

        //Restore the previous selected entity.
        vectorSpritesProperties.selectedEntity = oldSelectedEntity;
        vectorSpritesProperties.selectedEntities.Clear();
        for (int i = 0; i < oldSelectedEntityPrimaryIDs.Count; i++)
        {
            vectorSpritesProperties.selectedEntities.Add(new VectorSprites.SelectedEntity(oldSelectedEntityPrimaryIDs[i], oldSelectedEntitySecondaryIDs[i]));
        }

        //Reset all shapes' meshes and render textures now that it has been rendered.
        for (int i = 0; i < vectorSpritesProperties.shapeGroups.Count; i++)
        {
            for (int j = 0; j < vectorSpritesProperties.shapeGroups[i].shapes.Count; j++)
            {
                vectorSpritesProperties.shapeGroups[i].shapes[j].resetAllMeshes();
            }
        }

        //Destroy the temporary Vector Sprites Renderer game object.
        Destroy(vectorSpritesRendererGameObject);
    }
    //Initialise.
    public void initialise(VectorSprites.VectorSpritesProperties vectorSpritesProperties, Material shapeMaterial, Material pillowAndGlowMeshMaterial,
                           Material pillowAndGlowRenderTextureMaterial, VectorSpritesRenderer vectorSpritesRenderer)
    {
        //Store properties.
        this.vectorSpritesProperties = vectorSpritesProperties;
        if (vectorSpritesProperties.selectedEntity == VectorSprites.SelectableEntity.SpriteSheet)
        {
            spriteSheetIndex = vectorSpritesProperties.selectedEntities[0].primaryID;
            spriteIndex      = -1;
        }
        else
        {
            spriteSheetIndex = -1;
            spriteIndex      = vectorSpritesProperties.selectedEntities[0].primaryID;
        }

        //Set all meshes to dirty to ensure they are re-generated (the export quality might not match the editor quality).
        for (int i = 0; i < vectorSpritesProperties.shapeGroups.Count; i++)
        {
            for (int j = 0; j < vectorSpritesProperties.shapeGroups[i].shapes.Count; j++)
            {
                vectorSpritesProperties.shapeGroups[i].shapes[j].resetAllMeshes();
            }
        }

        //Create a list of packing spaces to pack all sprites in. If there is a single sprite, just create a single packing space, otherwise try to fit all
        //sprites in as smaller space as possible.
        packingSpaces.Clear();
        if (spriteSheetIndex == -1)
        {
            packingSpaces.Add(new PackingSpace(0, 0, vectorSpritesProperties.vectorSprites[vectorSpritesProperties.selectedEntities[0].primaryID].width,
                                               vectorSpritesProperties.vectorSprites[vectorSpritesProperties.selectedEntities[0].primaryID].height,
                                               vectorSpritesProperties.selectedEntities[0].primaryID));
        }

        //If multiple sprites are being added to the sprite sheet, pack the sprites on the sprite sheet in the most efficient way possible.
        else
        {
            //Sort the sprites in descending order of size (maximum dimension), which should produce more efficient packing.
            List <int> spriteOrder = new List <int>();
            for (int i = 0; i < vectorSpritesProperties.vectorSprites.Count; i++)
            {
                if (vectorSpritesProperties.vectorSprites[i].spriteSheet == spriteSheetIndex)
                {
                    spriteOrder.Add(i);
                }
            }
            bool spriteOrderSwapChanges = true;
            while (spriteOrderSwapChanges)
            {
                spriteOrderSwapChanges = false;
                for (int i = 0; i < spriteOrder.Count - 1; i++)
                {
                    int thisMaxCoordinate = Math.Max(vectorSpritesProperties.vectorSprites[spriteOrder[i]].width,
                                                     vectorSpritesProperties.vectorSprites[spriteOrder[i]].height);
                    int nextMaxCoordinate = Math.Max(vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].width,
                                                     vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].height);
                    int thisMinCoordinate = Math.Min(vectorSpritesProperties.vectorSprites[spriteOrder[i]].width,
                                                     vectorSpritesProperties.vectorSprites[spriteOrder[i]].height);
                    int nextMinCoordinate = Math.Min(vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].width,
                                                     vectorSpritesProperties.vectorSprites[spriteOrder[i + 1]].height);
                    if (thisMaxCoordinate < nextMaxCoordinate || (thisMaxCoordinate == nextMaxCoordinate && thisMinCoordinate < nextMinCoordinate))
                    {
                        int spriteOrderSwap = spriteOrder[i];
                        spriteOrder[i]         = spriteOrder[i + 1];
                        spriteOrder[i + 1]     = spriteOrderSwap;
                        spriteOrderSwapChanges = true;
                    }
                }
            }

            //Start with a single packing space, and loop over the sprites to place into spaces.
            packingSpaces.Add(new PackingSpace(0, 0, 65536, 65536));
            for (int j = 0; j < spriteOrder.Count; j++)
            {
                //Get the Vector Sprite.
                VectorSprites.VectorSprite vectorSprite = vectorSpritesProperties.vectorSprites[spriteOrder[j]];

                //Find the best space to put this sprite such that it keeps the overall area as small as possible.
                ulong lowestTotalArea       = ulong.MaxValue;
                int   smallestWastedArea    = int.MaxValue;
                int   bestPackingSpaceIndex = -1;
                for (int k = 0; k < packingSpaces.Count; k++)
                {
                    if (packingSpaces[k].vectorSpriteIndex == -1)
                    {
                        packingSpaces[k].vectorSpriteIndex = spriteOrder[j];
                        int oldWidth = packingSpaces[k].width, oldHeight = packingSpaces[k].height;
                        packingSpaces[k].width  = vectorSprite.width;
                        packingSpaces[k].height = vectorSprite.height;
                        int newTextureSizeX, newTextureSizeY;
                        getMaximumPackingSize(out newTextureSizeX, out newTextureSizeY);
                        ulong newArea       = ((ulong)newTextureSizeX * (ulong)newTextureSizeX) + ((ulong)newTextureSizeY * (ulong)newTextureSizeY);
                        int   newWastedArea = (oldWidth * oldHeight) - (vectorSprite.width * vectorSprite.height);
                        if (newArea < lowestTotalArea || (newArea == lowestTotalArea && newWastedArea < smallestWastedArea))
                        {
                            lowestTotalArea       = newArea;
                            smallestWastedArea    = newWastedArea;
                            bestPackingSpaceIndex = k;
                        }
                        packingSpaces[k].vectorSpriteIndex = -1;
                        packingSpaces[k].width             = oldWidth;
                        packingSpaces[k].height            = oldHeight;
                    }
                }

                //Put the sprite in the assigned space.
                int originalWidth = packingSpaces[bestPackingSpaceIndex].width, originalHeight = packingSpaces[bestPackingSpaceIndex].height;
                packingSpaces[bestPackingSpaceIndex].width             = vectorSprite.width;
                packingSpaces[bestPackingSpaceIndex].height            = vectorSprite.height;
                packingSpaces[bestPackingSpaceIndex].vectorSpriteIndex = spriteOrder[j];
                if (originalWidth - packingSpaces[bestPackingSpaceIndex].width > 0)
                {
                    packingSpaces.Add(new PackingSpace(packingSpaces[bestPackingSpaceIndex].X + packingSpaces[bestPackingSpaceIndex].width,
                                                       packingSpaces[bestPackingSpaceIndex].Y, originalWidth - packingSpaces[bestPackingSpaceIndex].width,
                                                       packingSpaces[bestPackingSpaceIndex].height));
                }
                if (originalHeight - packingSpaces[bestPackingSpaceIndex].height > 0)
                {
                    packingSpaces.Add(new PackingSpace(packingSpaces[bestPackingSpaceIndex].X, packingSpaces[bestPackingSpaceIndex].Y +
                                                       packingSpaces[bestPackingSpaceIndex].height, originalWidth, originalHeight - packingSpaces[bestPackingSpaceIndex].height));
                }
            }
        }

        //Create an output texture, the size of which is the maximum size of all packing spaces.
        int textureSizeX, textureSizeY;

        getMaximumPackingSize(out textureSizeX, out textureSizeY);
        if (textureSizeX > 4096 || textureSizeY > 4096)
        {
            Close();
            EditorUtility.DisplayDialog("Texture Too Big", "The sprite sheet cannot fit within a texture of size 4096 by 4096 pixels. Try reducing the size " +
                                        "of some of the individual sprites, or split the sprites into two sprite sheets.", "OK");
            return;
        }
        texture           = new Texture2D(textureSizeX, textureSizeY, TextureFormat.ARGB32, false);
        texture.hideFlags = HideFlags.HideAndDontSave;
        texture.wrapMode  = TextureWrapMode.Clamp;
        RenderTexture clearRenderTexture = new RenderTexture(textureSizeX, textureSizeY, 16, RenderTextureFormat.ARGB32);

        clearRenderTexture.hideFlags = HideFlags.HideAndDontSave;
        RenderTexture.active         = clearRenderTexture;
        GL.Clear(true, true, new Color(0, 0, 0, 0));
        texture.ReadPixels(new Rect(0, 0, textureSizeX, textureSizeY), 0, 0, false);
        RenderTexture.active = null;
        DestroyImmediate(clearRenderTexture);

        //Loop over all the packing spaces that contain sprites, and add those sprites to the sprite sheet.
        VectorSprites.SelectableEntity oldSelectedEntity = vectorSpritesProperties.selectedEntity;
        List <int> oldSelectedEntityPrimaryIDs           = new List <int>();
        List <int> oldSelectedEntitySecondaryIDs         = new List <int>();

        for (int i = 0; i < vectorSpritesProperties.selectedEntities.Count; i++)
        {
            oldSelectedEntityPrimaryIDs.Add(vectorSpritesProperties.selectedEntities[i].primaryID);
            oldSelectedEntitySecondaryIDs.Add(vectorSpritesProperties.selectedEntities[i].secondaryID);
        }
        vectorSpritesProperties.selectedEntity = VectorSprites.SelectableEntity.Sprite;
        for (int i = 0; i < packingSpaces.Count; i++)
        {
            if (packingSpaces[i].vectorSpriteIndex == -1)
            {
                continue;
            }

            //Get the sprite and work out its scale.
            VectorSprites.VectorSprite vectorSprite = vectorSpritesProperties.vectorSprites[packingSpaces[i].vectorSpriteIndex];
            Vector2 meshScale = new Vector2(2, 2);
            if (vectorSprite.spriteRectangleTransform == VectorSprites.SpriteRectangleTransform.Crop)
            {
                if (vectorSprite.width > vectorSprite.height)
                {
                    meshScale.y *= (float)vectorSprite.width / vectorSprite.height;
                }
                else
                {
                    meshScale.x *= (float)vectorSprite.height / vectorSprite.width;
                }
            }

            //Render the sprite to a render texture. Double the size of the render texture if anti-aliasing is enabled (so it can be scaled back down).
            RenderTexture renderTexture = new RenderTexture(vectorSprite.width * (vectorSprite.antialias ? 2 : 1),
                                                            vectorSprite.height * (vectorSprite.antialias ? 2 : 1), 16, RenderTextureFormat.ARGB32);
            renderTexture.hideFlags = HideFlags.HideAndDontSave;
            vectorSpritesProperties.selectedEntities.Clear();
            vectorSpritesProperties.selectedEntities.Add(new VectorSprites.SelectedEntity(packingSpaces[i].vectorSpriteIndex));
            vectorSpritesRenderer.render(vectorSpritesProperties, shapeMaterial, pillowAndGlowMeshMaterial, pillowAndGlowRenderTextureMaterial, renderTexture,
                                         meshScale, false);

            //Get the texture directly from the render texture.
            RenderTexture.active = renderTexture;
            Texture2D textureFromRenderTexture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
            textureFromRenderTexture.hideFlags = HideFlags.HideAndDontSave;
            textureFromRenderTexture.wrapMode  = TextureWrapMode.Clamp;
            textureFromRenderTexture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0, false);
            textureFromRenderTexture.Apply();
            RenderTexture.active = null;
            DestroyImmediate(renderTexture);

            //Copy the texture to the master texture, scaling down for anti-aliasing purposes if required.
            renderTexture           = new RenderTexture(vectorSprite.width, vectorSprite.height, 16, RenderTextureFormat.ARGB32);
            renderTexture.hideFlags = HideFlags.HideAndDontSave;
            Graphics.Blit(textureFromRenderTexture, renderTexture);
            RenderTexture.active = renderTexture;
            texture.ReadPixels(new Rect(0, 0, vectorSprite.width, vectorSprite.height), packingSpaces[i].X, packingSpaces[i].Y, false);
            RenderTexture.active = null;
            DestroyImmediate(textureFromRenderTexture);
            DestroyImmediate(renderTexture);
        }

        //Apply the changes to the texture.
        texture.Apply();

        //Restore the previous selected entity.
        vectorSpritesProperties.selectedEntity = oldSelectedEntity;
        vectorSpritesProperties.selectedEntities.Clear();
        for (int i = 0; i < oldSelectedEntityPrimaryIDs.Count; i++)
        {
            vectorSpritesProperties.selectedEntities.Add(new VectorSprites.SelectedEntity(oldSelectedEntityPrimaryIDs[i], oldSelectedEntitySecondaryIDs[i]));
        }

        //Set all meshes to dirty again so they can be re-generated in the editor, which may have different quality settings from export.
        for (int i = 0; i < vectorSpritesProperties.shapeGroups.Count; i++)
        {
            for (int j = 0; j < vectorSpritesProperties.shapeGroups[i].shapes.Count; j++)
            {
                vectorSpritesProperties.shapeGroups[i].shapes[j].resetAllMeshes();
            }
        }
    }