Example #1
0
        /// <summary>
        /// scales all images to the given dimensions
        /// </summary>
        public void ScaleImages(Size3 size, ScalingModel scaling)
        {
            if (NumImages == 0)
            {
                return;
            }
            if (Size == size)
            {
                return;
            }
            if (ImageType != typeof(TextureArray2D))
            {
                throw new Exception("scaling is only supported for 2D images");
            }

            var prevMipmaps = NumMipmaps;

            foreach (var imageData in Images)
            {
                imageData.Scale(size, scaleShader, scaling);
            }

            InitDimensions(images[0].Image);

            OnPropertyChanged(nameof(Size));
            if (prevMipmaps != NumMipmaps)
            {
                OnPropertyChanged(nameof(NumMipmaps));
            }
        }
Example #2
0
            public void Scale(Size3 size, MitchellNetravaliScaleShader shader, ScalingModel scaling)
            {
                var tmp = shader.Run((TextureArray2D)Image, size, scaling);

                Image.Dispose();
                Image = tmp;
            }
Example #3
0
            internal void GenerateMipmaps(int levels, ScalingModel scaling)
            {
                var tmp = Image.CloneWithMipmaps(levels);

                scaling.WriteMipmaps(tmp);
                Image.Dispose();
                Image = tmp;
            }
        public TextureArray2D Run(TextureArray2D src, Size3 dstSize, ScalingModel scaling)
        {
            Debug.Assert(src.Size != dstSize);
            var genMipmaps = src.NumMipmaps > 1;
            var numMipmaps = 1;

            if (genMipmaps)
            {
                numMipmaps = dstSize.MaxMipLevels;
            }

            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(new LayerMipmapCount(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(new LayerMipmapCount(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)
            {
                scaling.WriteMipmaps(src);
            }

            return(src);
        }
Example #5
0
        /// <summary>
        /// generates mipmaps for all images
        /// </summary>
        public void GenerateMipmaps(ScalingModel scaling)
        {
            Debug.Assert(NumMipmaps == 1);

            // compute new mipmap levels
            var levels = Size.MaxMipLevels;

            if (levels == NumMipmaps)
            {
                return;
            }

            foreach (var image in Images)
            {
                image.GenerateMipmaps(levels, scaling);
            }

            // recalc dimensions array
            InitDimensions(Images[0].Image);

            OnPropertyChanged(nameof(NumMipmaps));
        }
        /// <summary>
        /// creates a thumbnail for one image layer/mipmap
        /// </summary>
        /// <param name="size">maximum width/height of the thumbnail</param>
        /// <param name="texture">source texture</param>
        /// <param name="dstFormat">destination texture format</param>
        /// <param name="layer">source layer</param>
        /// <returns>texture with width, height smaller or equal to size. One layer and one mipmap</returns>
        public TextureArray2D CreateThumbnail(int size, ITexture texture,
                                              SharpDX.DXGI.Format dstFormat, int layer, ScalingModel scaling)
        {
            Debug.Assert(ImageFormat.IsSupported(dstFormat));
            Debug.Assert(ImageFormat.IsSupported(texture.Format));

            // determine dimensions of output texture
            var width  = 0;
            var height = 0;

            if (texture.Size.Width > texture.Size.Height)
            {
                width  = size;
                height = (texture.Size.Height * size) / texture.Size.Width;
            }
            else
            {
                height = size;
                width  = (texture.Size.Width * size) / texture.Size.Height;
            }
            Debug.Assert(width <= size);
            Debug.Assert(height <= size);

            var res = new TextureArray2D(LayerMipmapCount.One, new Size3(width, height), dstFormat, false);

            // compute which mipmap has the closest fit
            var mipmap   = 0;
            var curWidth = texture.Size.Width;

            while (curWidth >= width)
            {
                ++mipmap;
                curWidth /= 2;
            }
            // mipmap just jumped over the optimal size
            mipmap = Math.Max(0, mipmap - 1);

            var      dev    = Device.Get();
            ITexture tmpTex = null;

            if (texture.NumMipmaps < mipmap + 1)
            {
                // generate new texture with mipmaps
                tmpTex = texture.CloneWithMipmaps(mipmap + 1);

                scaling.WriteMipmaps(tmpTex);
                dev.Pixel.SetShaderResource(0, tmpTex.GetSrView(new LayerMipmapSlice(layer, mipmap)));
            }
            else
            {
                dev.Pixel.SetShaderResource(0, texture.GetSrView(new LayerMipmapSlice(layer, mipmap)));
            }

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

            dev.Pixel.SetSampler(0, sampler);

            dev.OutputMerger.SetRenderTargets(res.GetRtView(LayerMipmapSlice.Mip0));
            dev.SetViewScissors(width, height);
            dev.DrawFullscreenTriangle(1);

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

            tmpTex?.Dispose();

            return(res);
        }
Example #7
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="scaling">required for regenerating mipmaps after cropping</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>
 public ITexture Convert(ITexture texture, SharpDX.DXGI.Format dstFormat, ScalingModel scaling, int mipmap = -1, int layer = -1, float multiplier = 1.0f)
 {
     return(Convert(texture, dstFormat, new LayerMipmapRange(layer, mipmap), multiplier, false, Size3.Zero, Size3.Zero, Size3.Zero, scaling, null));
 }
Example #8
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="srcLm">layer/mipmap to export</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>
        /// <param name="scaling">required for regenerating mipmaps after cropping.</param>
        /// <param name="overlay">overlay</param>
        /// <param name="scale">scales the destination image by this factor</param>
        /// <returns></returns>
        public ITexture Convert(ITexture texture, SharpDX.DXGI.Format dstFormat, LayerMipmapRange srcLm, float multiplier, bool crop,
                                Size3 offset, Size3 size, Size3 align, ScalingModel scaling, ITexture overlay = null, int scale = 1)
        {
            Debug.Assert(ImageFormat.IsSupported(dstFormat));
            Debug.Assert(ImageFormat.IsSupported(texture.Format));
            Debug.Assert(overlay == null || texture.HasSameDimensions(overlay));
            Debug.Assert(scale >= 1);

            // set width, height mipmap
            int nMipmaps = srcLm.IsSingleMipmap ? 1: texture.NumMipmaps;
            int nLayer   = srcLm.IsSingleLayer ? 1 : texture.NumLayers;

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

            if (scale != 1)
            {
                size.X *= scale;
                size.Y *= scale;
                if (texture.Is3D)
                {
                    size.Z *= scale;
                }
                offset.X *= scale;
                offset.Y *= scale;
                if (texture.Is3D)
                {
                    offset.Z *= scale;
                }
            }

            // 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 || scale != 1);

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

            var res = texture.Create(new LayerMipmapCount(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);
            if (overlay != null)
            {
                dev.Pixel.SetShaderResource(1, overlay.View);
            }
            else
            {
                dev.Pixel.SetShaderResource(1, null);
            }

            foreach (var dstLm in res.LayerMipmap.Range)
            {
                cbuffer.SetData(new LayerLevelOffsetData
                {
                    Layer      = dstLm.Layer + srcLm.FirstLayer + offset.Z,
                    Level      = dstLm.Mipmap + srcLm.FirstMipmap,
                    Xoffset    = offset.X,
                    Yoffset    = offset.Y,
                    Multiplier = multiplier,
                    UseOverlay = overlay != null ? 1 : 0,
                    Scale      = scale
                });

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

                if (recomputeMips && dstLm.Mipmap > 0)
                {
                    break;                                    // only write most detailed mipmap
                }
            }

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

            if (recomputeMips)
            {
                scaling.WriteMipmaps(res);
            }

            return(res);
        }
Example #9
0
        /// <summary>
        /// adds pixels to the image edges
        /// </summary>
        /// <param name="src">source image</param>
        /// <param name="leftPad">padding on the left/top/front side</param>
        /// <param name="rightPad">padding on the right/bot/back side</param>
        /// <param name="fill">padding fill mode</param>
        /// <param name="scaling">used for regenerating mipmaps (may be null if no mipmaps need to be generated)</param>
        /// <param name="shared"></param>
        /// <param name="keepMipmaps">if set to false, no mipmaps will be generated</param>
        /// <returns>same as source with added padding (amount of mipmaps might change, format remains)</returns>
        public ITexture Run(ITexture src, Size3 leftPad, Size3 rightPad, FillMode fill, ScalingModel scaling, SharedModel shared, bool keepMipmaps = true)
        {
            Size3 dstSize  = leftPad + rightPad + src.Size;
            int   nMipmaps = src.NumMipmaps > 1 ? dstSize.MaxMipLevels : 1;

            if (!keepMipmaps)
            {
                nMipmaps = 1;
            }

            var dst = src.Create(new LayerMipmapCount(src.NumLayers, nMipmaps), dstSize, src.Format, src.HasUaViews,
                                 true);

            var dev = DirectX.Device.Get();

            shared.Upload.SetData(new BufferData
            {
                Depth  = dstSize.Depth,
                Offset = new Float3(leftPad) / new Float3(dstSize),
                Scale  = new Float3(dstSize) / new Float3(src.Size),
            });

            shared.QuadShader.Bind(src.Is3D);
            if (src.Is3D)
            {
                dev.Pixel.Set(shader3D.Pixel);
            }
            else
            {
                dev.Pixel.Set(shader.Pixel);
            }
            dev.Pixel.SetSampler(0, sampler[(int)fill]);
            dev.Pixel.SetConstantBuffer(0, shared.Upload.Handle);

            foreach (var lm in src.LayerMipmap.RangeOf(LayerMipmapRange.MostDetailed))
            {
                dev.OutputMerger.SetRenderTargets(dst.GetRtView(lm));
                dev.SetViewScissors(dstSize.Width, dstSize.Height);
                dev.Pixel.SetShaderResource(0, src.GetSrView(lm));

                dev.DrawFullscreenTriangle(dstSize.Depth);
            }

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

            if (dst.NumMipmaps > 1)
            {
                Debug.Assert(scaling != null);
                scaling.WriteMipmaps(dst);
            }

            return(dst);
        }