Пример #1
0
        /// <summary>
        /// Checks whether two items can be packed to the same texture
        /// </summary>
        private bool AreAtlasItemsCompatible(List <TextureTools.AtlasItem> items, TextureTools.AtlasItem item1, TextureTools.AtlasItem item2)
        {
            if (item1.CookingRules.GenerateOpacityMask != item2.CookingRules.GenerateOpacityMask)
            {
                return(false);
            }
            if (item1.CookingRules.WrapMode != item2.CookingRules.WrapMode)
            {
                return(false);
            }
            if (item1.CookingRules.MinFilter != item2.CookingRules.MinFilter)
            {
                return(false);
            }
            if (item1.CookingRules.MagFilter != item2.CookingRules.MagFilter)
            {
                return(false);
            }
            if (item1.CookingRules.MipMaps != item2.CookingRules.MipMaps)
            {
                return(false);
            }
            if (items.Count > 0)
            {
                if (item1.CookingRules.WrapMode != TextureWrapMode.Clamp || item2.CookingRules.WrapMode != TextureWrapMode.Clamp)
                {
                    return(false);
                }
            }
            switch (AssetCooker.Platform)
            {
            case TargetPlatform.Android:
            case TargetPlatform.iOS:
                return(item1.CookingRules.PVRFormat == item2.CookingRules.PVRFormat && item1.BitmapInfo.HasAlpha == item2.BitmapInfo.HasAlpha);

            case TargetPlatform.Win:
            case TargetPlatform.Mac:
                return(item1.CookingRules.DDSFormat == item2.CookingRules.DDSFormat);

            default:
                throw new ArgumentException();
            }
        }
Пример #2
0
        private void PackItemsToAtlas(List <TextureTools.AtlasItem> items, Size atlasSize, out double packRate)
        {
            items.ForEach(i => i.Allocated = false);
            // Reserve space for default one-pixel padding.
            atlasSize.Width  += 2;
            atlasSize.Height += 2;
            var rectAllocator = new RectAllocator(atlasSize);

            TextureTools.AtlasItem firstAllocatedItem = null;
            foreach (var item in items)
            {
                var padding        = item.CookingRules.AtlasItemPadding;
                var paddedItemSize = new Size(item.BitmapInfo.Width + padding * 2, item.BitmapInfo.Height + padding * 2);
                if (firstAllocatedItem == null || AreAtlasItemsCompatible(items, firstAllocatedItem, item))
                {
                    if (rectAllocator.Allocate(paddedItemSize, out item.AtlasRect))
                    {
                        item.Allocated     = true;
                        firstAllocatedItem = firstAllocatedItem ?? item;
                    }
                }
            }
            packRate = rectAllocator.GetPackRate();
            // Adjust item rects according to theirs paddings.
            foreach (var item in items)
            {
                if (!item.Allocated)
                {
                    continue;
                }
                var atlasRect = item.AtlasRect;
                atlasRect.A += new IntVector2(item.CookingRules.AtlasItemPadding);
                atlasRect.B -= new IntVector2(item.CookingRules.AtlasItemPadding);
                // Don't leave space between item rectangle and texture boundaries for items with 1 pixel padding.
                if (item.CookingRules.AtlasItemPadding == 1)
                {
                    atlasRect.A -= new IntVector2(1);
                    atlasRect.B -= new IntVector2(1);
                }
                item.AtlasRect = atlasRect;
            }
        }
Пример #3
0
        private void BuildAtlasChain(string atlasChain)
        {
            for (var i = 0; i < AssetCooker.MaxAtlasChainLength; i++)
            {
                var atlasPath = AssetCooker.GetAtlasPath(atlasChain, i);
                if (AssetCooker.OutputBundle.FileExists(atlasPath))
                {
                    AssetCooker.DeleteFileFromBundle(atlasPath);
                }
                else
                {
                    break;
                }
            }
            var pluginItems = new Dictionary <string, List <TextureTools.AtlasItem> >();
            var items       = new Dictionary <AtlasOptimization, List <TextureTools.AtlasItem> >();

            items[AtlasOptimization.Memory]    = new List <TextureTools.AtlasItem>();
            items[AtlasOptimization.DrawCalls] = new List <TextureTools.AtlasItem>();
            foreach (var fileInfo in AssetBundle.Current.EnumerateFileInfos(null, textureExtension))
            {
                var cookingRules = AssetCooker.CookingRulesMap[fileInfo.Path];
                if (cookingRules.TextureAtlas == atlasChain)
                {
                    var item = new TextureTools.AtlasItem {
                        Path            = Path.ChangeExtension(fileInfo.Path, atlasPartExtension),
                        CookingRules    = cookingRules,
                        SourceExtension = Path.GetExtension(fileInfo.Path)
                    };
                    var bitmapInfo = TextureTools.BitmapInfo.FromFile(AssetCooker.InputBundle, fileInfo.Path);
                    if (bitmapInfo == null)
                    {
                        using (var bitmap = TextureTools.OpenAtlasItemBitmapAndRescaleIfNeeded(AssetCooker.Platform, item)) {
                            item.BitmapInfo = TextureTools.BitmapInfo.FromBitmap(bitmap);
                        }
                    }
                    else
                    {
                        var srcTexturePath = AssetPath.Combine(The.Workspace.AssetsDirectory, Path.ChangeExtension(item.Path, item.SourceExtension));
                        if (TextureTools.ShouldDownscale(AssetCooker.Platform, bitmapInfo, item.CookingRules))
                        {
                            TextureTools.DownscaleTextureInfo(AssetCooker.Platform, bitmapInfo, srcTexturePath, item.CookingRules);
                        }
                        // Ensure that no image exceeded maxAtlasSize limit
                        TextureTools.DownscaleTextureToFitAtlas(bitmapInfo, srcTexturePath);
                        item.BitmapInfo = bitmapInfo;
                    }
                    var k = cookingRules.AtlasPacker;
                    if (!string.IsNullOrEmpty(k) && k != "Default")
                    {
                        List <TextureTools.AtlasItem> l;
                        if (!pluginItems.TryGetValue(k, out l))
                        {
                            pluginItems.Add(k, l = new List <TextureTools.AtlasItem>());
                        }
                        l.Add(item);
                    }
                    else
                    {
                        items[cookingRules.AtlasOptimization].Add(item);
                    }
                }
            }
            var initialAtlasId = 0;

            foreach (var kv in items)
            {
                if (kv.Value.Any())
                {
                    if (AssetCooker.Platform == TargetPlatform.iOS)
                    {
                        Predicate <PVRFormat> isRequireSquare = (format) => {
                            return
                                (format == PVRFormat.PVRTC2 ||
                                 format == PVRFormat.PVRTC4 ||
                                 format == PVRFormat.PVRTC4_Forced);
                        };
                        var square    = kv.Value.Where(item => isRequireSquare(item.CookingRules.PVRFormat)).ToList();
                        var nonSquare = kv.Value.Where(item => !isRequireSquare(item.CookingRules.PVRFormat)).ToList();
                        initialAtlasId = PackItemsToAtlas(atlasChain, square, kv.Key, initialAtlasId, true);
                        initialAtlasId = PackItemsToAtlas(atlasChain, nonSquare, kv.Key, initialAtlasId, false);
                    }
                    else
                    {
                        initialAtlasId = PackItemsToAtlas(atlasChain, kv.Value, kv.Key, initialAtlasId, false);
                    }
                }
            }
            var packers = PluginLoader.CurrentPlugin.AtlasPackers.ToDictionary(i => i.Metadata.Id, i => i.Value);

            foreach (var kv in pluginItems)
            {
                if (!packers.ContainsKey(kv.Key))
                {
                    throw new InvalidOperationException($"Packer {kv.Key} not found");
                }
                initialAtlasId = packers[kv.Key](atlasChain, kv.Value, initialAtlasId);
            }
        }