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); }
/// <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); }