예제 #1
0
        public ITextureAtlas CreateUnpacked(uint maxWidth, uint bytesPerPixel)
        {
            uint width   = 0u;
            uint height  = 0u;
            uint xOffset = 0u;
            uint yOffset = 0u;
            Dictionary <uint, Position> textureOffsets = new Dictionary <uint, Position>();

            foreach (var textureEntry in textures)
            {
                var textureIndex = textureEntry.Key;
                var texture      = textureEntry.Value;

                if (xOffset + texture.Width <= maxWidth)
                {
                    if (yOffset + texture.Height > height)
                    {
                        height = yOffset + (uint)texture.Height;
                    }

                    textureOffsets.Add(textureIndex, new Position((int)xOffset, (int)yOffset));

                    xOffset += (uint)texture.Width;

                    if (xOffset > width)
                    {
                        width = xOffset;
                    }
                }
                else
                {
                    xOffset = 0;
                    yOffset = height;

                    height = yOffset + (uint)texture.Height;

                    textureOffsets.Add(textureIndex, new Position((int)xOffset, (int)yOffset));

                    xOffset += (uint)texture.Width;

                    if (xOffset > width)
                    {
                        width = xOffset;
                    }
                }
            }

            // create texture
            var atlasTexture = new MutableTexture(state, (int)width, (int)height, bytesPerPixel);

            foreach (var offset in textureOffsets)
            {
                var subTexture = textures[offset.Key];

                atlasTexture.AddSubTexture(offset.Value, subTexture.Data, subTexture.Width, subTexture.Height);
            }

            atlasTexture.Finish(0);

            return(new TextureAtlas(atlasTexture, textureOffsets));
        }
예제 #2
0
        // Note: It is not the best texture packing algorithm but it will do its job
        public ITextureAtlas Create(uint bytesPerPixel)
        {
            // sort textures by similar heights (16-pixel bands)
            // heights of items are < key * 16
            // value = list of texture indices
            Dictionary <uint, List <uint> > textureCategories         = new Dictionary <uint, List <uint> >();
            Dictionary <uint, uint>         textureCategoryMinValues  = new Dictionary <uint, uint>();
            Dictionary <uint, uint>         textureCategoryMaxValues  = new Dictionary <uint, uint>();
            Dictionary <uint, uint>         textureCategoryTotalWidth = new Dictionary <uint, uint>();

            foreach (var texture in textures)
            {
                uint category = (uint)texture.Value.Height / 16u;

                if (!textureCategories.ContainsKey(category))
                {
                    textureCategories.Add(category, new List <uint>());
                    textureCategoryMinValues.Add(category, (uint)texture.Value.Height);
                    textureCategoryMaxValues.Add(category, (uint)texture.Value.Height);
                    textureCategoryTotalWidth.Add(category, (uint)texture.Value.Width);
                }
                else
                {
                    if (texture.Value.Height < textureCategoryMinValues[category])
                    {
                        textureCategoryMinValues[category] = (uint)texture.Value.Height;
                    }
                    if (texture.Value.Height > textureCategoryMaxValues[category])
                    {
                        textureCategoryMaxValues[category] = (uint)texture.Value.Height;
                    }
                    textureCategoryTotalWidth[category] += (uint)texture.Value.Width;
                }

                textureCategories[category].Add(texture.Key);
            }

            var filteredTextureCategories = new List <KeyValuePair <uint, List <uint> > >();

            foreach (var category in textureCategories)
            {
                if (textureCategories[category.Key].Count == 0)
                {
                    continue; // was merged with lower category
                }
                // merge categories with minimal differences
                if (textureCategoryMinValues[category.Key] >= category.Key * 16 + 8 &&
                    textureCategories.ContainsKey(category.Key + 1) &&
                    textureCategoryMaxValues[category.Key + 1] <= (category.Key + 1) * 16 + 8)
                {
                    textureCategories[category.Key].AddRange(textureCategories[category.Key + 1]);
                    textureCategoryMaxValues[category.Key] = Math.Max(textureCategoryMaxValues[category.Key], textureCategoryMaxValues[category.Key + 1]);
                    textureCategories[category.Key + 1].Clear();
                }

                filteredTextureCategories.Add(new KeyValuePair <uint, List <uint> >(textureCategoryMaxValues[category.Key], textureCategories[category.Key]));
            }

            filteredTextureCategories.Sort(new TextureCategorySorter());

            // now we have a sorted category list with all texture indices

            uint maxWidth = Math.Max(512u, textureCategoryMaxValues.Max(m => m.Value));
            uint width    = 0u;
            uint height   = 0u;
            uint xOffset  = 0u;
            uint yOffset  = 0u;
            Dictionary <uint, Position> textureOffsets = new Dictionary <uint, Position>();

            // create texture offsets
            foreach (var category in filteredTextureCategories)
            {
                foreach (var textureIndex in category.Value)
                {
                    var texture = textures[textureIndex];

                    if (xOffset + texture.Width <= maxWidth)
                    {
                        if (yOffset + texture.Height > height)
                        {
                            height = yOffset + (uint)texture.Height;
                        }

                        textureOffsets.Add(textureIndex, new Position((int)xOffset, (int)yOffset));

                        xOffset += (uint)texture.Width;

                        if (xOffset > width)
                        {
                            width = xOffset;
                        }
                    }
                    else
                    {
                        xOffset = 0;
                        yOffset = height;

                        height = yOffset + (uint)texture.Height;

                        textureOffsets.Add(textureIndex, new Position((int)xOffset, (int)yOffset));

                        xOffset += (uint)texture.Width;

                        if (xOffset > width)
                        {
                            width = xOffset;
                        }
                    }
                }

                if (xOffset > maxWidth - 320) // we do not expect textures with a width greater than 320
                {
                    xOffset = 0;
                    yOffset = height;
                }
            }

            // create texture
            var atlasTexture = new MutableTexture(state, (int)width, (int)height, bytesPerPixel);

            foreach (var offset in textureOffsets)
            {
                var subTexture = textures[offset.Key];

                atlasTexture.AddSubTexture(offset.Value, subTexture.Data, subTexture.Width, subTexture.Height);
            }

            atlasTexture.Finish(0);

            return(new TextureAtlas(atlasTexture, textureOffsets));
        }