public TextureArray2D Run(TextureArray2D src, Size3 dstSize)
        {
            Debug.Assert(src.Size != dstSize);
            var genMipmaps = src.HasMipmaps;
            var numMipmaps = 1;

            if (genMipmaps)
            {
                numMipmaps = ImagesModel.ComputeMaxMipLevels(dstSize);
            }

            bool changeWidth  = dstSize.Width != src.Size.Width;
            bool changeHeight = dstSize.Height != src.Size.Height;

            if (changeWidth)
            {
                var curMips = numMipmaps;

                if (changeHeight) // only temporary texture with a single mipmap
                {
                    curMips = 1;
                }

                var tmp = new TextureArray2D(src.NumLayers, curMips, new Size3(dstSize.Width, src.Size.Height), src.Format, false);
                Apply(src, tmp, 1, 0);
                src = tmp;
            }

            if (changeHeight)
            {
                var tmp = new TextureArray2D(src.NumLayers, numMipmaps, dstSize, src.Format, false);

                Apply(src, tmp, 0, 1);
                if (changeWidth) // delete temporary texture created by width invocation
                {
                    src.Dispose();
                }
                src = tmp;
            }

            if (genMipmaps)
            {
                src.RegenerateMipmapLevels();
            }

            return(src);
        }
Пример #2
0
        /// <summary>
        /// converts the texture into another format and performs cropping if requested
        /// </summary>
        /// <param name="texture">source texture</param>
        /// <param name="dstFormat">destination format</param>
        /// <param name="mipmap">mipmap to export, -1 for all mipmaps</param>
        /// <param name="layer">layer to export, -1 for all layers</param>
        /// <param name="multiplier">rgb channels will be multiplied by this value</param>
        /// <param name="crop">indicates if the image should be cropped, only works with 1 mipmap to export</param>
        /// <param name="offset">if crop: offset in source image</param>
        /// <param name="size">if crop: size of the destination image</param>
        /// <param name="align">if nonzero: texture width will be aligned to this (rounded down)</param>
        /// <returns></returns>
        public ITexture Convert(ITexture texture, SharpDX.DXGI.Format dstFormat, int mipmap, int layer, float multiplier, bool crop,
                                Size3 offset, Size3 size, Size3 align)
        {
            Debug.Assert(ImageFormat.IsSupported(dstFormat));
            Debug.Assert(ImageFormat.IsSupported(texture.Format));

            // set width, height mipmap
            int firstMipmap = Math.Max(mipmap, 0);
            int firstLayer  = Math.Max(layer, 0);
            int nMipmaps    = mipmap == -1 ? texture.NumMipmaps : 1;
            int nLayer      = layer == -1 ? texture.NumLayers : 1;

            // set correct width, height, offsets
            if (!crop)
            {
                size   = texture.Size.GetMip(firstMipmap);
                offset = Size3.Zero;
            }

            // adjust alignments
            for (int i = 0; i < 3; ++i)
            {
                if (align[i] != 0)
                {
                    if (size[i] % align[i] != 0)
                    {
                        if (size[i] < align[i])
                        {
                            throw new Exception($"image needs to be aligned to {align[i]} but one axis is only {size[i]}. Axis should be at least {align[i]}");
                        }

                        crop = true;
                        var remainder = size[i] % align[i];
                        offset[i] = offset[i] + remainder / 2;
                        size[i]   = size[i] - remainder;
                    }
                }
            }

            bool recomputeMips = nMipmaps > 1 && crop;

            if (recomputeMips)
            {
                // number of mipmaps might have changed
                nMipmaps      = ImagesModel.ComputeMaxMipLevels(size);
                recomputeMips = nMipmaps > 1;
            }

            var res = texture.Create(nLayer, nMipmaps, size, dstFormat, false);

            var dev = DirectX.Device.Get();

            quad.Bind(texture.Is3D);
            if (texture.Is3D)
            {
                dev.Pixel.Set(convert3D.Pixel);
            }
            else
            {
                dev.Pixel.Set(convert2D.Pixel);
            }

            dev.Pixel.SetShaderResource(0, texture.View);

            for (int curLayer = 0; curLayer < nLayer; ++curLayer)
            {
                for (int curMipmap = 0; curMipmap < nMipmaps; ++curMipmap)
                {
                    cbuffer.SetData(new LayerLevelOffsetData
                    {
                        Layer      = curLayer + firstLayer + offset.Z,
                        Level      = curMipmap + firstMipmap,
                        Xoffset    = offset.X,
                        Yoffset    = offset.Y,
                        Multiplier = multiplier
                    });

                    var dim = res.Size.GetMip(curMipmap);
                    dev.Pixel.SetConstantBuffer(0, cbuffer.Handle);
                    dev.OutputMerger.SetRenderTargets(res.GetRtView(curLayer, curMipmap));
                    dev.SetViewScissors(dim.Width, dim.Height);
                    dev.DrawFullscreenTriangle(dim.Depth);

                    if (recomputeMips)
                    {
                        break;               // only write most detailed mipmap
                    }
                }
            }

            // remove bindings
            dev.Pixel.SetShaderResource(0, null);
            dev.OutputMerger.SetRenderTargets((RenderTargetView)null);
            quad.Unbind();

            if (recomputeMips)
            {
                res.RegenerateMipmapLevels();
            }

            return(res);
        }