Texture2D、Sprite动态图集

public AtlasRegion Pack(string path)
{
    var tex = Load<Texture2D>(path, false);
    if (tex == null)
    {
        Debug.LogWarningFormat("[Packer] {0} not found", path);
        return null;
    }

    if (tex.width > width || tex.height > height)
    {
        Debug.LogError("[Packer] A texture size is bigger than the sprite sheet size!");
        return null;
    }

    var region = PackRegion(new Vector2Int(tex.width, tex.height));
    if (region == null)
        return null;
    region.name = path;
    region.page = this;

    region.degrees = 0;
    region.rotate = false;

    region.width = region.originalWidth = tex.width;
    region.height = region.originalHeight = tex.height;
    _packedSprites.Add(path, region);
    CopyTex2RT(tex, region);
                  
    region.u = (region.x + 1) / (float)width;
    region.v = (region.y - 1 + tex.height) / (float)height;
    region.u2 = (region.x - 1 + tex.width) / (float)width;
    region.v2 = (region.y + 1) / (float)height;

    region.ReferenceCount++;
    return region;
}
private AtlasRegion PackRegion(Vector2Int v2I)
{
    var v2Ix = v2I.x;
    var v2Iy = v2I.y;

    var index = GetFreeAreaIndex(v2Ix, v2Iy);
    if (index < 0) return null;
    var freeArea = _mFreeAreas[index];
    var target = AllocateRectangle(freeArea.x, freeArea.y, v2Ix, v2Iy);

    // Generate the new free areas, these are parts of the old ones intersected or touched by the target
    GenerateNewFreeAreas(target, _mFreeAreas, _mNewFreeAreas);

    while (_mNewFreeAreas.Count > 0)
        _mFreeAreas.Add(_mNewFreeAreas.Pop());

    _mInsertedRegion.Add(target);

    if (target.Right > _mPackedWidth)
        _mPackedWidth = target.Right;

    if (target.Bottom > _mPackedHeight)
        _mPackedHeight = target.Bottom;
    return target;
}
private int GetFreeAreaIndex(int spriteWidth, int spriteHeight)
{
    var best = _mOutsideRegion;
    var index = -1;

    var paddedWidth = spriteWidth + _padding;
    var paddedHeight = spriteHeight + _padding;

    var count = _mFreeAreas.Count;
    for (var i = count - 1; i >= 0; i--)
    {
        var free = _mFreeAreas[i];
        if (free.x < _mPackedWidth || free.y < _mPackedHeight)
        {

            // Within the packed area, padding required
            if (free.x >= best.x || !(paddedWidth <= free.width) || !(paddedHeight <= free.height)) continue;
            index = i;
            if (paddedWidth == free.width && free.width <= free.height && free.Right < _mWidth || paddedHeight == free.height && free.height <= free.width)
                break;

            best = free;
        }
        else
        {
            // Outside the current packed area, no padding required
            if (free.x >= best.x || spriteWidth > free.width || spriteHeight > free.height) continue;
            index = i;
            if ((spriteWidth == free.width && free.width <= free.height && free.Right < _mWidth) || (spriteHeight == free.height && free.height <= free.width))
                break;

            best = free;
        }
    }

    return index;
}
private AtlasRegion AllocateRectangle(int x, int y, int targetWidth, int targetHeight)
{
    if (_mRegionStack.Count <= 0)
        return new AtlasRegion
        {
            x = x,
            y = y,
            width = targetWidth,
            height = targetHeight,
            Right = x + targetWidth,
            Bottom = y + targetHeight
        };
    var region = _mRegionStack.Pop();
    region.x = x;
    region.y = y;
    region.width = targetWidth;
    region.height = targetHeight;
    region.Right = x + targetWidth;
    region.Bottom = y + targetHeight;
    return region;
}
private void GenerateNewFreeAreas(AtlasRegion target, List<AtlasRegion> areas, List<AtlasRegion> results)
{
    float x = target.x;
    float y = target.y;
    float right = target.Right +  _padding;
    float bottom = target.Bottom +  _padding;

    AtlasRegion targetWithPadding = null;
    if (_padding == 0)
        targetWithPadding = target;

    for (var i = areas.Count - 1; i >= 0; i--)
    {
        var area = areas[i];
        if (x >= area.Right || right <= area.x || y >= area.Bottom || bottom <= area.y) continue;
        if (targetWithPadding == null)
            targetWithPadding = AllocateRectangle(target.x, target.y, target.width + _padding, target.height + _padding);

        GenerateDividedAreas(targetWithPadding, area, results);
        var topOfStack = areas.Pop();
        if (i < areas.Count)
        {
            // Move the one on the top to the freed position
            areas[i] = topOfStack;
        }
    }

    if (targetWithPadding != null && targetWithPadding != target)
        FreeRectangle(targetWithPadding);

    FilterSelfSubAreas(results);
}
private void GenerateDividedAreas(AtlasRegion divider, AtlasRegion area, ICollection<AtlasRegion> results)
{
    var count = 0;

    var rightDelta = area.Right - divider.Right;
    if (rightDelta > 0)
    {
        results.Add(AllocateRectangle(divider.Right, area.y, rightDelta, area.height));
        count++;
    }

    var leftDelta = divider.x - area.x;
    if (leftDelta > 0)
    {
        results.Add(AllocateRectangle(area.x, area.y, leftDelta, area.height));
        count++;
    }

    var bottomDelta = area.Bottom - divider.Bottom;
    if (bottomDelta > 0)
    {
        results.Add(AllocateRectangle(area.x, divider.Bottom, area.width, bottomDelta));
        count++;
    }

    var topDelta = divider.y - area.y;
    if (topDelta > 0)
    {
        results.Add(AllocateRectangle(area.x, area.y, area.width, topDelta));
        count++;
    }

    if (count == 0 && (divider.width < area.width || divider.height < area.height))
    {
        // Only touching the area, store the area itself
        results.Add(area);
    }
    else
        _mRegionStack.Add(region);
}
private void CopyTex2RT(Texture tex, AtlasRegion region)
{
    if (_renderTexture == null)
    {
        _renderTexture = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32)
        {
            name = "PackedSheet[" + name + "]", autoGenerateMips = false, useMipMap = false
        };
        _renderTexture.DiscardContents();
    }
    if (_copyMat == null)
    {
        var shader = Shader.Find("Hidden/Copy");
        if (shader == null)
            Debug.LogError("[Packer] shader not found");
        _copyMat = new Material(shader);
    }

    var x = 1.0f * width / (region.width);
    var y = 1.0f * height / (region.height);
    var z = 1.0f * -region.x / (region.width);
    var w = 1.0f * -region.y / (region.height);

    _copyMat.SetVector(ShaderUtil.ID_MainTex_ST2, new Vector4(x, y, z,w));
    _renderTexture.MarkRestoreExpected();
    Graphics.Blit(tex, _renderTexture, _copyMat);
    _primaryMaterial.mainTexture = _renderTexture;
    rendererObject = _primaryMaterial;
}
上一篇:hadoop集群管理系统搭建规划说明


下一篇:MonoGame 3.2 下,截屏与 Texture2D 的保存