/// <summary>Creates a new Texture2D object based on an AtlasRegion.
        /// If applyImmediately is true, Texture2D.Apply is called immediately after the Texture2D is filled with data.</summary>
        public static Texture2D ToTexture(this AtlasRegion ar, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
                                          int texturePropertyId = 0, bool linear = false, bool applyPMA = false)
        {
            Texture2D output;

            IntAndAtlasRegionKey cacheKey = new IntAndAtlasRegionKey(texturePropertyId, ar);

            CachedRegionTextures.TryGetValue(cacheKey, out output);
            if (output == null)
            {
                Texture2D sourceTexture = texturePropertyId == 0 ? ar.GetMainTexture() : ar.GetTexture(texturePropertyId);
                Rect      r             = ar.GetUnityRect();
                int       width         = (int)r.width;
                int       height        = (int)r.height;
                output = new Texture2D(width, height, textureFormat, mipmaps, linear)
                {
                    name = ar.name
                };
                output.CopyTextureAttributesFrom(sourceTexture);
                if (applyPMA)
                {
                    AtlasUtilities.CopyTextureApplyPMA(sourceTexture, r, output);
                }
                else
                {
                    AtlasUtilities.CopyTexture(sourceTexture, r, output);
                }
                CachedRegionTextures.Add(cacheKey, output);
                CachedRegionTexturesList.Add(output);
            }

            return(output);
        }
Exemple #2
0
        static Texture2D GetClone(this Texture2D t, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps)
        {
            var newTexture = new Texture2D((int)t.width, (int)t.height, textureFormat, mipmaps);

            AtlasUtilities.CopyTexture(t, new Rect(0, 0, t.width, t.height), newTexture);
            return(newTexture);
        }
Exemple #3
0
        static Texture2D GetClone(this Texture2D t, TextureFormat textureFormat = SpineTextureFormat,
                                  bool mipmaps = UseMipMaps, bool linear = false)
        {
            var newTexture = new Texture2D((int)t.width, (int)t.height, textureFormat, mipmaps, linear);

            newTexture.CopyTextureAttributesFrom(t);
            AtlasUtilities.CopyTexture(t, new Rect(0, 0, t.width, t.height), newTexture);
            return(newTexture);
        }
Exemple #4
0
        static Texture2D ToTexture(this Sprite s, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps)
        {
            var spriteTexture = s.texture;
            var r             = s.textureRect;
            var newTexture    = new Texture2D((int)r.width, (int)r.height, textureFormat, mipmaps);

            AtlasUtilities.CopyTexture(spriteTexture, r, newTexture);
            return(newTexture);
        }
Exemple #5
0
        static Texture2D ToTexture(this Sprite s, TextureFormat textureFormat = SpineTextureFormat,
                                   bool mipmaps = UseMipMaps, bool linear = false, bool applyPMA = false)
        {
            var spriteTexture = s.texture;
            var r             = s.textureRect;
            var newTexture    = new Texture2D((int)r.width, (int)r.height, textureFormat, mipmaps, linear);

            newTexture.CopyTextureAttributesFrom(spriteTexture);
            if (applyPMA)
            {
                AtlasUtilities.CopyTextureApplyPMA(spriteTexture, r, newTexture);
            }
            else
            {
                AtlasUtilities.CopyTexture(spriteTexture, r, newTexture);
            }
            return(newTexture);
        }
Exemple #6
0
        /// <summary>Creates a new Texture2D object based on an AtlasRegion.
        /// If applyImmediately is true, Texture2D.Apply is called immediately after the Texture2D is filled with data.</summary>
        public static Texture2D ToTexture(this AtlasRegion ar, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
                                          int texturePropertyId = 0, bool linear = false, bool applyPMA = false)
        {
            Texture2D output;

            IntAndAtlasRegionKey cacheKey = new IntAndAtlasRegionKey(texturePropertyId, ar);

            CachedRegionTextures.TryGetValue(cacheKey, out output);
            if (output == null)
            {
                Texture2D sourceTexture = texturePropertyId == 0 ? ar.GetMainTexture() : ar.GetTexture(texturePropertyId);
                Rect      r             = ar.GetUnityRect();
                // Compensate any image resizing due to Texture 'Max Size' import settings.
                // sourceTexture.width returns the resized image dimensions, at least in newer Unity versions.
                if (sourceTexture.width < ar.page.width)
                {
                    float scaleX = (float)(sourceTexture.width) / (float)(ar.page.width);
                    float scaleY = (float)(sourceTexture.height) / (float)(ar.page.height);
                    var   scale  = new Vector2(scaleX, scaleY);
                    r = new Rect(Vector2.Scale(r.position, scale), Vector2.Scale(r.size, scale));
                }

                int width  = (int)r.width;
                int height = (int)r.height;
                output = new Texture2D(width, height, textureFormat, mipmaps, linear)
                {
                    name = ar.name
                };
                output.CopyTextureAttributesFrom(sourceTexture);
                if (applyPMA)
                {
                    AtlasUtilities.CopyTextureApplyPMA(sourceTexture, r, output);
                }
                else
                {
                    AtlasUtilities.CopyTexture(sourceTexture, r, output);
                }
                CachedRegionTextures.Add(cacheKey, output);
                CachedRegionTexturesList.Add(output);
            }

            return(output);
        }
Exemple #7
0
        /// <summary>Creates a new Texture2D object based on an AtlasRegion.
        /// If applyImmediately is true, Texture2D.Apply is called immediately after the Texture2D is filled with data.</summary>
        public static Texture2D ToTexture(this AtlasRegion ar, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps)
        {
            Texture2D output;

            CachedRegionTextures.TryGetValue(ar, out output);
            if (output == null)
            {
                Texture2D sourceTexture = ar.GetMainTexture();
                Rect      r             = ar.GetUnityRect(sourceTexture.height);
                int       width         = (int)r.width;
                int       height        = (int)r.height;
                output = new Texture2D(width, height, textureFormat, mipmaps)
                {
                    name = ar.name
                };
                AtlasUtilities.CopyTexture(sourceTexture, r, output);
                CachedRegionTextures.Add(ar, output);
                CachedRegionTexturesList.Add(output);
            }

            return(output);
        }
        static Texture2D ToTexture(this Sprite s, TextureFormat textureFormat = SpineTextureFormat,
                                   bool mipmaps = UseMipMaps, bool linear = false, bool applyPMA = false)
        {
            var  spriteTexture = s.texture;
            Rect r;

            if (!s.packed || s.packingMode == SpritePackingMode.Rectangle)
            {
                r = s.textureRect;
            }
            else
            {
                r      = new Rect();
                r.xMin = Math.Min(s.uv[0].x, s.uv[1].x) * spriteTexture.width;
                r.xMax = Math.Max(s.uv[0].x, s.uv[1].x) * spriteTexture.width;
                r.yMin = Math.Min(s.uv[0].y, s.uv[2].y) * spriteTexture.height;
                r.yMax = Math.Max(s.uv[0].y, s.uv[2].y) * spriteTexture.height;
#if UNITY_EDITOR
                if (s.uv.Length > 4)
                {
                    Debug.LogError("When using a tightly packed SpriteAtlas with Spine, you may only access Sprites that are packed as 'FullRect' from it! " +
                                   "You can either disable 'Tight Packing' at the whole SpriteAtlas, or change the single Sprite's TextureImporter Setting 'MeshType' to 'Full Rect'." +
                                   "Sprite Asset: " + s.name, s);
                }
#endif
            }
            var newTexture = new Texture2D((int)r.width, (int)r.height, textureFormat, mipmaps, linear);
            newTexture.CopyTextureAttributesFrom(spriteTexture);
            if (applyPMA)
            {
                AtlasUtilities.CopyTextureApplyPMA(spriteTexture, r, newTexture);
            }
            else
            {
                AtlasUtilities.CopyTexture(spriteTexture, r, newTexture);
            }
            return(newTexture);
        }
 static void Init()
 {
     // handle disabled domain reload
     AtlasUtilities.ClearCache();
 }
        /// <summary>
        /// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments,
        /// but mapped to a new single texture using the same material.</summary>
        /// <remarks>Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
        /// to free resources.</remarks>
        /// <param name="sourceAttachments">The list of attachments to be repacked.</param>
        /// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.
        /// May be equal to <c>sourceAttachments</c> for in-place operation.</param>
        /// <param name="materialPropertySource">May be null. If no Material property source is provided, a material with
        /// default parameters using the provided <c>shader</c> will be created.</param>
        /// <param name="additionalTexturePropertyIDsToCopy">Optional additional textures (such as normal maps) to copy while repacking.
        /// To copy e.g. the main texture and normal maps, pass 'new int[] { Shader.PropertyToID("_BumpMap") }' at this parameter.</param>
        /// <param name="additionalOutputTextures">When <c>additionalTexturePropertyIDsToCopy</c> is non-null,
        /// this array will be filled with the resulting repacked texture for every property,
        /// just as the main repacked texture is assigned to <c>outputTexture</c>.</param>
        /// <param name="additionalTextureFormats">When <c>additionalTexturePropertyIDsToCopy</c> is non-null,
        /// this array will be used as <c>TextureFormat</c> at the Texture at the respective property.
        /// When <c>additionalTextureFormats</c> is <c>null</c> or when its array size is smaller,
        /// <c>textureFormat</c> is used where there exists no corresponding array item.</param>
        /// <param name="additionalTextureIsLinear">When <c>additionalTexturePropertyIDsToCopy</c> is non-null,
        /// this array will be used to determine whether <c>linear</c> or <c>sRGB</c> color space is used at the
        /// Texture at the respective property. When <c>additionalTextureIsLinear</c> is <c>null</c>, <c>linear</c> color space
        /// is assumed at every additional Texture element.
        /// When e.g. packing the main texture and normal maps, pass 'new bool[] { true }' at this parameter, because normal maps use
        /// linear color space.</param>
        public static void GetRepackedAttachments(List <Attachment> sourceAttachments, List <Attachment> outputAttachments, Shader shader,
                                                  out Material outputMaterial, out Texture2D outputTexture,
                                                  int maxAtlasSize                         = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
                                                  string newAssetName                      = "Repacked Attachments",
                                                  Material materialPropertySource          = null, bool clearCache = false, bool useOriginalNonrenderables = true,
                                                  int[] additionalTexturePropertyIDsToCopy = null, Texture2D[] additionalOutputTextures = null,
                                                  TextureFormat[] additionalTextureFormats = null, bool[] additionalTextureIsLinear     = null)
        {
            if (sourceAttachments == null)
            {
                throw new System.ArgumentNullException("sourceAttachments");
            }
            if (outputAttachments == null)
            {
                throw new System.ArgumentNullException("outputAttachments");
            }
            outputTexture = null;
            if (additionalTexturePropertyIDsToCopy != null && additionalTextureIsLinear == null)
            {
                additionalTextureIsLinear = new bool[additionalTexturePropertyIDsToCopy.Length];
                for (int i = 0; i < additionalTextureIsLinear.Length; ++i)
                {
                    additionalTextureIsLinear[i] = true;
                }
            }

            // Use these to detect and use shared regions.
            existingRegions.Clear();
            regionIndices.Clear();

            // Collect all textures from original attachments.
            int numTextureParamsToRepack = 1 + (additionalTexturePropertyIDsToCopy == null ? 0 : additionalTexturePropertyIDsToCopy.Length);

            additionalOutputTextures = (additionalTexturePropertyIDsToCopy == null ? null : new Texture2D[additionalTexturePropertyIDsToCopy.Length]);
            if (texturesToPackAtParam.Length < numTextureParamsToRepack)
            {
                Array.Resize(ref texturesToPackAtParam, numTextureParamsToRepack);
            }
            for (int i = 0; i < numTextureParamsToRepack; ++i)
            {
                if (texturesToPackAtParam[i] != null)
                {
                    texturesToPackAtParam[i].Clear();
                }
                else
                {
                    texturesToPackAtParam[i] = new List <Texture2D>();
                }
            }
            originalRegions.Clear();

            if (!object.ReferenceEquals(sourceAttachments, outputAttachments))
            {
                outputAttachments.Clear();
                outputAttachments.AddRange(sourceAttachments);
            }

            int newRegionIndex = 0;

            for (int attachmentIndex = 0, n = sourceAttachments.Count; attachmentIndex < n; attachmentIndex++)
            {
                var originalAttachment = sourceAttachments[attachmentIndex];

                if (originalAttachment is IHasRendererObject)
                {
                    var        originalMeshAttachment = originalAttachment as MeshAttachment;
                    Attachment newAttachment          = (originalMeshAttachment != null) ? originalMeshAttachment.NewLinkedMesh() : originalAttachment.Copy();
                    var        region = ((IHasRendererObject)newAttachment).RendererObject as AtlasRegion;
                    int        existingIndex;
                    if (existingRegions.TryGetValue(region, out existingIndex))
                    {
                        regionIndices.Add(existingIndex);
                    }
                    else
                    {
                        originalRegions.Add(region);
                        for (int i = 0; i < numTextureParamsToRepack; ++i)
                        {
                            Texture2D regionTexture = (i == 0 ?
                                                       region.ToTexture(textureFormat, mipmaps) :
                                                       region.ToTexture((additionalTextureFormats != null && i - 1 < additionalTextureFormats.Length) ?
                                                                        additionalTextureFormats[i - 1] : textureFormat,
                                                                        mipmaps, additionalTexturePropertyIDsToCopy[i - 1], additionalTextureIsLinear[i - 1]));
                            texturesToPackAtParam[i].Add(regionTexture);
                        }

                        existingRegions.Add(region, newRegionIndex);
                        regionIndices.Add(newRegionIndex);
                        newRegionIndex++;
                    }

                    outputAttachments[attachmentIndex] = newAttachment;
                }
                else
                {
                    outputAttachments[attachmentIndex] = useOriginalNonrenderables ? originalAttachment : originalAttachment.Copy();
                    regionIndices.Add(NonrenderingRegion);                     // Output attachments pairs with regionIndices list 1:1. Pad with a sentinel if the attachment doesn't have a region.
                }
            }

            // Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
            var newMaterial = new Material(shader);

            if (materialPropertySource != null)
            {
                newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
                newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
            }
            newMaterial.name = newAssetName;

            Rect[] rects = null;
            for (int i = 0; i < numTextureParamsToRepack; ++i)
            {
                // Fill a new texture with the collected attachment textures.
                var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize,
                                               (i > 0 && additionalTextureFormats != null && i - 1 < additionalTextureFormats.Length) ?
                                               additionalTextureFormats[i - 1] : textureFormat,
                                               mipmaps,
                                               (i > 0) ? additionalTextureIsLinear[i - 1] : false);
                newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;

                var texturesToPack = texturesToPackAtParam[i];
                if (texturesToPack.Count > 0)
                {
                    var sourceTexture = texturesToPack[0];
                    newTexture.CopyTextureAttributesFrom(sourceTexture);
                }
                newTexture.name = newAssetName;
                var rectsForTexParam = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
                if (i == 0)
                {
                    rects = rectsForTexParam;
                    newMaterial.mainTexture = newTexture;
                    outputTexture           = newTexture;
                }
                else
                {
                    newMaterial.SetTexture(additionalTexturePropertyIDsToCopy[i - 1], newTexture);
                    additionalOutputTextures[i - 1] = newTexture;
                }
            }

            var page = newMaterial.ToSpineAtlasPage();

            page.name = newAssetName;

            repackedRegions.Clear();
            for (int i = 0, n = originalRegions.Count; i < n; i++)
            {
                var oldRegion = originalRegions[i];
                var newRegion = UVRectToAtlasRegion(rects[i], oldRegion, page);
                repackedRegions.Add(newRegion);
            }

            // Map the cloned attachments to the repacked atlas.
            for (int i = 0, n = outputAttachments.Count; i < n; i++)
            {
                var a = outputAttachments[i];
                if (a is IHasRendererObject)
                {
                    a.SetRegion(repackedRegions[regionIndices[i]]);
                }
            }

            // Clean up.
            if (clearCache)
            {
                AtlasUtilities.ClearCache();
            }

            outputMaterial = newMaterial;
        }
Exemple #11
0
        /// <summary>
        /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary>
        /// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time. No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
        public static Skin GetRepackedSkin(this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true)
        {
            if (o == null)
            {
                throw new System.NullReferenceException("Skin was null");
            }
            var skinAttachments = o.Attachments;
            var newSkin         = new Skin(newName);

            newSkin.bones.AddRange(o.bones);
            newSkin.constraints.AddRange(o.constraints);

            // Use these to detect and use shared regions.
            var existingRegions = new Dictionary <AtlasRegion, int>();
            var regionIndexes   = new List <int>();

            // Collect all textures from the attachments of the original skin.
            var repackedAttachments = new List <Attachment>();
            var texturesToPack      = new List <Texture2D>();
            var originalRegions     = new List <AtlasRegion>();
            int newRegionIndex      = 0;

            foreach (var skinEntry in skinAttachments)
            {
                var originalKey        = skinEntry.Key;
                var originalAttachment = skinEntry.Value;

                Attachment newAttachment;
                if (IsRenderable(originalAttachment))
                {
                    newAttachment = originalAttachment.GetCopy(true);
                    var region = newAttachment.GetRegion();
                    int existingIndex;
                    if (existingRegions.TryGetValue(region, out existingIndex))
                    {
                        regionIndexes.Add(existingIndex);                         // Store the region index for the eventual new attachment.
                    }
                    else
                    {
                        originalRegions.Add(region);
                        texturesToPack.Add(region.ToTexture());                    // Add the texture to the PackTextures argument
                        existingRegions.Add(region, newRegionIndex);               // Add the region to the dictionary of known regions
                        regionIndexes.Add(newRegionIndex);                         // Store the region index for the eventual new attachment.
                        newRegionIndex++;
                    }

                    repackedAttachments.Add(newAttachment);
                    newSkin.SetAttachment(originalKey.SlotIndex, originalKey.Name, newAttachment);
                }
                else
                {
                    newSkin.SetAttachment(originalKey.SlotIndex, originalKey.Name, useOriginalNonrenderables ? originalAttachment : originalAttachment.GetCopy(true));
                }
            }

            // Fill a new texture with the collected attachment textures.
            var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);

            newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;

            if (texturesToPack.Count > 0)
            {
                var sourceTexture = texturesToPack[0];
                newTexture.CopyTextureAttributesFrom(sourceTexture);
            }
            newTexture.name = newName;
            var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);

            // Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
            var newMaterial = new Material(shader);

            if (materialPropertySource != null)
            {
                newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
                newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
            }

            newMaterial.name        = newName;
            newMaterial.mainTexture = newTexture;
            var page = newMaterial.ToSpineAtlasPage();

            page.name = newName;

            var repackedRegions = new List <AtlasRegion>();

            for (int i = 0, n = originalRegions.Count; i < n; i++)
            {
                var oldRegion = originalRegions[i];
                var newRegion = UVRectToAtlasRegion(rects[i], oldRegion, page);
                repackedRegions.Add(newRegion);
            }

            // Map the cloned attachments to the repacked atlas.
            for (int i = 0, n = repackedAttachments.Count; i < n; i++)
            {
                var a = repackedAttachments[i];
                if (IsRenderable(a))
                {
                    a.SetRegion(repackedRegions[regionIndexes[i]]);
                }
            }

            // Clean up.
            if (clearCache)
            {
                AtlasUtilities.ClearCache();
            }

            outputTexture  = newTexture;
            outputMaterial = newMaterial;
            return(newSkin);
        }
Exemple #12
0
        /// <summary>
        /// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments, but mapped to a new single texture using the same material.</summary>
        /// <param name="sourceAttachments">The list of attachments to be repacked.</param>
        /// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param>
        ///
        /// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param>
        public static void GetRepackedAttachments(List <Attachment> sourceAttachments, List <Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true)
        {
            if (sourceAttachments == null)
            {
                throw new System.ArgumentNullException("sourceAttachments");
            }
            if (outputAttachments == null)
            {
                throw new System.ArgumentNullException("outputAttachments");
            }

            // Use these to detect and use shared regions.
            var existingRegions = new Dictionary <AtlasRegion, int>();
            var regionIndexes   = new List <int>();
            var texturesToPack  = new List <Texture2D>();
            var originalRegions = new List <AtlasRegion>();

            outputAttachments.Clear();
            outputAttachments.AddRange(sourceAttachments);

            int newRegionIndex = 0;

            for (int i = 0, n = sourceAttachments.Count; i < n; i++)
            {
                var originalAttachment = sourceAttachments[i];

                if (IsRenderable(originalAttachment))
                {
                    var newAttachment = originalAttachment.GetCopy(true);
                    var region        = newAttachment.GetRegion();
                    int existingIndex;
                    if (existingRegions.TryGetValue(region, out existingIndex))
                    {
                        regionIndexes.Add(existingIndex);                         // Store the region index for the eventual new attachment.
                    }
                    else
                    {
                        originalRegions.Add(region);
                        texturesToPack.Add(region.ToTexture());                    // Add the texture to the PackTextures argument
                        existingRegions.Add(region, newRegionIndex);               // Add the region to the dictionary of known regions
                        regionIndexes.Add(newRegionIndex);                         // Store the region index for the eventual new attachment.
                        newRegionIndex++;
                    }

                    outputAttachments[i] = newAttachment;
                }
                else
                {
                    outputAttachments[i] = useOriginalNonrenderables ? originalAttachment : originalAttachment.GetCopy(true);
                    regionIndexes.Add(NonrenderingRegion);                     // Output attachments pairs with regionIndexes list 1:1. Pad with a sentinel if the attachment doesn't have a region.
                }
            }

            // Fill a new texture with the collected attachment textures.
            var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);

            newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
            newTexture.name       = newAssetName;
            // Copy settings
            if (texturesToPack.Count > 0)
            {
                var sourceTexture = texturesToPack[0];
                newTexture.CopyTextureAttributesFrom(sourceTexture);
            }
            var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);

            // Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
            Shader shader = materialPropertySource == null?Shader.Find("Spine/Skeleton") : materialPropertySource.shader;

            var newMaterial = new Material(shader);

            if (materialPropertySource != null)
            {
                newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
                newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
            }

            newMaterial.name        = newAssetName;
            newMaterial.mainTexture = newTexture;
            var page = newMaterial.ToSpineAtlasPage();

            page.name = newAssetName;

            var repackedRegions = new List <AtlasRegion>();

            for (int i = 0, n = originalRegions.Count; i < n; i++)
            {
                var oldRegion = originalRegions[i];
                var newRegion = UVRectToAtlasRegion(rects[i], oldRegion, page);
                repackedRegions.Add(newRegion);
            }

            // Map the cloned attachments to the repacked atlas.
            for (int i = 0, n = outputAttachments.Count; i < n; i++)
            {
                var a = outputAttachments[i];
                if (IsRenderable(a))
                {
                    a.SetRegion(repackedRegions[regionIndexes[i]]);
                }
            }

            // Clean up.
            if (clearCache)
            {
                AtlasUtilities.ClearCache();
            }

            outputTexture  = newTexture;
            outputMaterial = newMaterial;
        }
Exemple #13
0
        /// <summary>
        /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
        /// comprised of all the regions from the original skin.</summary>
        /// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time.
        /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.
        /// Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
        /// to free resources.</remarks>
        public static Skin GetRepackedSkin(this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture,
                                           int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
                                           Material materialPropertySource          = null, bool clearCache = false, bool useOriginalNonrenderables = true,
                                           int[] additionalTexturePropertyIDsToCopy = null, Texture2D[] additionalOutputTextures = null,
                                           TextureFormat[] additionalTextureFormats = null, bool[] additionalTextureIsLinear     = null)
        {
            outputTexture = null;
            if (additionalTexturePropertyIDsToCopy != null && additionalTextureIsLinear == null)
            {
                additionalTextureIsLinear = new bool[additionalTexturePropertyIDsToCopy.Length];
                for (int i = 0; i < additionalTextureIsLinear.Length; ++i)
                {
                    additionalTextureIsLinear[i] = true;
                }
            }

            if (o == null)
            {
                throw new System.NullReferenceException("Skin was null");
            }
            var skinAttachments = o.Attachments;
            var newSkin         = new Skin(newName);

            newSkin.bones.AddRange(o.bones);
            newSkin.constraints.AddRange(o.constraints);

            // Use these to detect and use shared regions.
            existingRegions.Clear();
            regionIndices.Clear();

            // Collect all textures from the attachments of the original skin.
            repackedAttachments.Clear();
            int numTextureParamsToRepack = 1 + (additionalTexturePropertyIDsToCopy == null ? 0 : additionalTexturePropertyIDsToCopy.Length);

            additionalOutputTextures = (additionalTexturePropertyIDsToCopy == null ? null : new Texture2D[additionalTexturePropertyIDsToCopy.Length]);
            if (texturesToPackAtParam.Length < numTextureParamsToRepack)
            {
                Array.Resize(ref texturesToPackAtParam, numTextureParamsToRepack);
            }
            for (int i = 0; i < numTextureParamsToRepack; ++i)
            {
                if (texturesToPackAtParam[i] != null)
                {
                    texturesToPackAtParam[i].Clear();
                }
                else
                {
                    texturesToPackAtParam[i] = new List <Texture2D>();
                }
            }
            originalRegions.Clear();
            int newRegionIndex = 0;

            foreach (var skinEntry in skinAttachments)
            {
                var originalKey        = skinEntry.Key;
                var originalAttachment = skinEntry.Value;

                Attachment newAttachment;
                if (IsRenderable(originalAttachment))
                {
                    newAttachment = originalAttachment.GetCopy(true);
                    var region = newAttachment.GetRegion();
                    int existingIndex;
                    if (existingRegions.TryGetValue(region, out existingIndex))
                    {
                        regionIndices.Add(existingIndex);                         // Store the region index for the eventual new attachment.
                    }
                    else
                    {
                        originalRegions.Add(region);
                        for (int i = 0; i < numTextureParamsToRepack; ++i)
                        {
                            Texture2D regionTexture = (i == 0 ?
                                                       region.ToTexture(textureFormat, mipmaps) :
                                                       region.ToTexture((additionalTextureFormats != null && i - 1 < additionalTextureFormats.Length) ?
                                                                        additionalTextureFormats[i - 1] : textureFormat,
                                                                        mipmaps, additionalTexturePropertyIDsToCopy[i - 1], additionalTextureIsLinear[i - 1]));
                            texturesToPackAtParam[i].Add(regionTexture);           // Add the texture to the PackTextures argument
                        }
                        existingRegions.Add(region, newRegionIndex);               // Add the region to the dictionary of known regions
                        regionIndices.Add(newRegionIndex);                         // Store the region index for the eventual new attachment.
                        newRegionIndex++;
                    }

                    repackedAttachments.Add(newAttachment);
                    newSkin.SetAttachment(originalKey.SlotIndex, originalKey.Name, newAttachment);
                }
                else
                {
                    newSkin.SetAttachment(originalKey.SlotIndex, originalKey.Name, useOriginalNonrenderables ? originalAttachment : originalAttachment.GetCopy(true));
                }
            }

            // Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
            var newMaterial = new Material(shader);

            if (materialPropertySource != null)
            {
                newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
                newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
            }
            newMaterial.name = newName;

            Rect[] rects = null;
            for (int i = 0; i < numTextureParamsToRepack; ++i)
            {
                // Fill a new texture with the collected attachment textures.
                var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize,
                                               (i > 0 && additionalTextureFormats != null && i - 1 < additionalTextureFormats.Length) ?
                                               additionalTextureFormats[i - 1] : textureFormat,
                                               mipmaps,
                                               (i > 0) ? additionalTextureIsLinear[i - 1] : false);
                newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
                var texturesToPack = texturesToPackAtParam[i];
                if (texturesToPack.Count > 0)
                {
                    var sourceTexture = texturesToPack[0];
                    newTexture.CopyTextureAttributesFrom(sourceTexture);
                }
                newTexture.name = newName;
                var rectsForTexParam = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
                if (i == 0)
                {
                    rects = rectsForTexParam;
                    newMaterial.mainTexture = newTexture;
                    outputTexture           = newTexture;
                }
                else
                {
                    newMaterial.SetTexture(additionalTexturePropertyIDsToCopy[i - 1], newTexture);
                    additionalOutputTextures[i - 1] = newTexture;
                }
            }

            var page = newMaterial.ToSpineAtlasPage();

            page.name = newName;

            repackedRegions.Clear();
            for (int i = 0, n = originalRegions.Count; i < n; i++)
            {
                var oldRegion = originalRegions[i];
                var newRegion = UVRectToAtlasRegion(rects[i], oldRegion, page);
                repackedRegions.Add(newRegion);
            }

            // Map the cloned attachments to the repacked atlas.
            for (int i = 0, n = repackedAttachments.Count; i < n; i++)
            {
                var a = repackedAttachments[i];
                if (IsRenderable(a))
                {
                    a.SetRegion(repackedRegions[regionIndices[i]]);
                }
            }

            // Clean up.
            if (clearCache)
            {
                AtlasUtilities.ClearCache();
            }

            outputMaterial = newMaterial;
            return(newSkin);
        }