Esempio n. 1
0
        /// <summary>Function to load the image file into memory.</summary>
        /// <param name="file">The stream for the file to load.</param>
        /// <param name="name">The name of the file.</param>
        /// <returns>The image data, the virtual file entry for the working file and the original pixel format of the file.</returns>
        public (IGorgonImage image, IGorgonVirtualFile workingFile, BufferFormat originalFormat) LoadImageFile(Stream file, string name)
        {
            IGorgonImage       result = null;
            IGorgonVirtualFile workFile;
            BufferFormat       originalFormat;

            IGorgonImageInfo imageInfo = DefaultCodec.GetMetaData(file);

            originalFormat = imageInfo.Format;
            var formatInfo = new GorgonFormatInfo(imageInfo.Format);

            // We absolutely need to have an extension, or else the texconv tool will not work.
            if ((DefaultCodec.CodecCommonExtensions.Count > 0) &&
                (!string.Equals(Path.GetExtension(name), DefaultCodec.CodecCommonExtensions[0], System.StringComparison.OrdinalIgnoreCase)))
            {
                _log.Print("Adding DDS extension to working file or else external tools may not be able to read it.", LoggingLevel.Verbose);
                name = Path.ChangeExtension(name, DefaultCodec.CodecCommonExtensions[0]);
            }

            _log.Print($"Copying content file {name} to {ScratchArea.FileSystem.MountPoints.First().PhysicalPath} as working file...", LoggingLevel.Intermediate);

            // Copy to a working file.
            using (Stream outStream = ScratchArea.OpenStream(name, FileMode.Create))
            {
                file.CopyTo(outStream);
                workFile = ScratchArea.FileSystem.GetFile(name);
            }

            _log.Print($"{workFile.FullPath} is now the working file for the image editor.", LoggingLevel.Intermediate);

            if (formatInfo.IsCompressed)
            {
                _log.Print($"Image is compressed using [{formatInfo.Format}] as its pixel format.", LoggingLevel.Intermediate);

                if (_compressor == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_COMPRESSED_FILE, formatInfo.Format));
                }

                _log.Print($"Loading image '{workFile.FullPath}'...", LoggingLevel.Simple);
                result = _compressor.Decompress(ref workFile, imageInfo);

                if (result == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_COMPRESSED_FILE, formatInfo.Format));
                }

                _log.Print($"Loaded compressed ([{formatInfo.Format}]) image data as [{result.Format}]", LoggingLevel.Intermediate);
            }
            else
            {
                _log.Print($"Loading image '{workFile.FullPath}'...", LoggingLevel.Simple);
                using (Stream workingFileStream = workFile.OpenStream())
                {
                    result = DefaultCodec.LoadFromStream(workingFileStream);
                }
            }

            return(result, workFile, originalFormat);
        }
        /// <summary>
        /// Function to retrieve the image data for a sprite texture as a 32 bit RGBA pixel data.
        /// </summary>
        /// <param name="data">The data used for sprite extraction.</param>
        /// <returns>The image data for the texture.</returns>
        public async Task <IGorgonImage> GetSpriteTextureImageDataAsync(SpriteExtractionData data)
        {
            IGorgonImage imageData = data.Texture.Texture.ToImage();

            if ((imageData.Format == BufferFormat.R8G8B8A8_UNorm) ||
                (imageData.Format == BufferFormat.R8G8B8A8_UNorm_SRgb))
            {
                return(imageData);
            }

            if ((imageData.FormatInfo.IsSRgb) &&
                (imageData.CanConvertToFormat(BufferFormat.R8G8B8A8_UNorm_SRgb)))
            {
                await Task.Run(() => imageData.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm_SRgb));

                return(imageData);
            }
            else if (imageData.CanConvertToFormat(BufferFormat.R8G8B8A8_UNorm))
            {
                await Task.Run(() => imageData.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm));

                return(imageData);
            }

            // OK, so this is going to take drastic measures.
            imageData.Dispose();
            return(RenderImageData(data.Texture));
        }
        /// <summary>
        /// Function to read the textures for the font.
        /// </summary>
        /// <param name="filePath">The path to the font file.</param>
        /// <param name="fontInfo">The information about the font.</param>
        /// <returns>A list of textures.</returns>
        private IReadOnlyList <GorgonTexture2D> ReadTextures(string filePath, BmFontInfo fontInfo)
        {
            var textures  = new GorgonTexture2D[fontInfo.FontTextures.Length];
            var directory = new DirectoryInfo(Path.GetDirectoryName(filePath).FormatDirectory(Path.DirectorySeparatorChar));

            Debug.Assert(directory.Exists, "Font directory should exist, but does not.");

            for (int i = 0; i < fontInfo.FontTextures.Length; ++i)
            {
                var fileInfo = new FileInfo(directory.FullName.FormatDirectory(Path.DirectorySeparatorChar) + fontInfo.FontTextures[i].FormatFileName());

                if (!fileInfo.Exists)
                {
                    throw new FileNotFoundException(string.Format(Resources.GORGFX_ERR_FONT_TEXTURE_FILE_NOT_FOUND, fileInfo.FullName));
                }

                IGorgonImageCodec codec = GetImageCodec(fileInfo.Extension);

                using (IGorgonImage image = codec.LoadFromFile(fileInfo.FullName))
                {
                    image.ToTexture2D(Factory.Graphics,
                                      new GorgonTexture2DLoadOptions
                    {
                        Name = $"BmFont_Texture_{Guid.NewGuid():N}"
                    });
                }
            }

            return(textures);
        }
Esempio n. 4
0
        /// <summary>
        /// Function to resize the image to a new width, height and/or depth.
        /// </summary>
        /// <param name="baseImage">The image to resize.</param>
        /// <param name="newWidth">The new width for the image.</param>
        /// <param name="newHeight">The new height for the image (for <see cref="ImageType.Image2D"/> and <see cref="ImageType.ImageCube"/> images).</param>
        /// <param name="newDepth">The new depth for the image (for <see cref="ImageType.Image3D"/> images).</param>
        /// <param name="filter">[Optional] The type of filtering to apply to the scaled image to help smooth larger and smaller images.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the resized image.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="newWidth"/>, <paramref name="newHeight"/>, or <paramref name="newDepth"/> parameters are less than 1.</exception>
        /// <exception cref="GorgonException">Thrown if there was an error during resizing regarding image pixel format conversion due to the type of <paramref name="filter"/> applied.</exception>
        /// <remarks>
        /// <para>
        /// This method will change the size of an existing image and return a larger or smaller version of itself as a new <see cref="IGorgonImage"/>.
        /// </para>
        /// </remarks>
        public static IGorgonImage Resize(this IGorgonImage baseImage, int newWidth, int newHeight, int newDepth, ImageFilter filter = ImageFilter.Point)
        {
            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            if (newWidth < 1)
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_WIDTH_TOO_SMALL, nameof(newWidth));
            }

            if ((newHeight < 1) && ((baseImage.ImageType == ImageType.Image2D) || (baseImage.ImageType == ImageType.ImageCube)))
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_HEIGHT_TOO_SMALL, nameof(newHeight));
            }

            if ((newDepth < 1) && (baseImage.ImageType == ImageType.Image3D))
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_DEPTH_TOO_SMALL, nameof(newDepth));
            }

            // Only use the appropriate dimensions.
            switch (baseImage.ImageType)
            {
            case ImageType.Image1D:
                newHeight = baseImage.Height;
                break;

            case ImageType.Image2D:
            case ImageType.ImageCube:
                newDepth = baseImage.Depth;
                break;
            }

            // If we haven't actually changed the size, then skip out.
            if ((newWidth == baseImage.Width) && (newHeight == baseImage.Height) && (newDepth == baseImage.Depth))
            {
                return(baseImage);
            }

            var wic = new WicUtilities();

            IGorgonImage newImage = null;

            try
            {
                int calcMipLevels = GorgonImage.CalculateMaxMipCount(newWidth, newHeight, newDepth).Min(baseImage.MipCount);
                newImage = wic.Resize(baseImage, 0, 0, newWidth, newHeight, newDepth, calcMipLevels, filter, ResizeMode.Scale);

                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
                wic.Dispose();
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Function to render the thumbnail into the image passed in.
        /// </summary>
        /// <param name="image">The image to render the thumbnail into.</param>
        /// <param name="scale">The scale of the image.</param>
        private void RenderThumbnail(ref IGorgonImage image, float scale)
        {
            lock (_syncLock)
            {
                using (GorgonTexture2D texture = image.ToTexture2D(GraphicsContext.Graphics, new GorgonTexture2DLoadOptions
                {
                    Usage = ResourceUsage.Immutable,
                    IsTextureCube = false
                }))
                    using (var rtv = GorgonRenderTarget2DView.CreateRenderTarget(GraphicsContext.Graphics, new GorgonTexture2DInfo
                    {
                        ArrayCount = 1,
                        Binding = TextureBinding.ShaderResource,
                        Format = BufferFormat.R8G8B8A8_UNorm,
                        MipLevels = 1,
                        Height = (int)(image.Height * scale),
                        Width = (int)(image.Width * scale),
                        Usage = ResourceUsage.Default
                    }))
                    {
                        GorgonTexture2DView view = texture.GetShaderResourceView(mipCount: 1, arrayCount: 1);
                        rtv.Clear(GorgonColor.BlackTransparent);
                        GraphicsContext.Graphics.SetRenderTarget(rtv);
                        GraphicsContext.Graphics.DrawTexture(view, new DX.Rectangle(0, 0, rtv.Width, rtv.Height), blendState: GorgonBlendState.Default, samplerState: GorgonSamplerState.Default);
                        GraphicsContext.Graphics.SetRenderTarget(null);

                        image?.Dispose();
                        image = rtv.Texture.ToImage();
                    }
            }
        }
Esempio n. 6
0
        /// <summary>Handles the RenderToBitmap event of the PanelDisplay control.</summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
        private void PanelDisplay_RenderToBitmap(object sender, PaintEventArgs e)
        {
            if ((IsDesignTime) || (_swapChain == null))
            {
                return;
            }

            // This method is used to capture the D3D rendering when rendering to a GDI+ bitmap (as used by the overlay).
            // Without it, no image is rendered and only a dark grey background is visible.

            IGorgonImage swapBufferImage = null;
            Bitmap       gdiBitmap       = null;

            try
            {
                RenderImage();

                swapBufferImage = _swapChain.CopyBackBufferToImage();
                gdiBitmap       = swapBufferImage.Buffers[0].ToBitmap();
                swapBufferImage.Dispose();

                e.Graphics.DrawImage(gdiBitmap, new Point(0, 0));
            }
            catch
            {
                // Empty on purpose.  Don't need to worry about exceptions here, if things fail, they fail and state should not be corrupted.
            }
            finally
            {
                gdiBitmap?.Dispose();
                swapBufferImage?.Dispose();
            }
        }
        /// <summary>
        /// Function to create a <see cref="GorgonTexture2D"/> from a GDI+ bitmap.
        /// </summary>
        /// <param name="gdiBitmap">The GDI+ bitmap used to create the texture.</param>
        /// <param name="graphics">The graphics interface used to create the texture.</param>
        /// <param name="options">[Optional] Options used to further define the texture.</param>
        /// <returns>A new <see cref="GorgonTexture2D"/> containing the data from the <paramref name="gdiBitmap"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="gdiBitmap"/>, or the <paramref name="graphics"/> parameter is <b>null</b>.</exception>
        /// <remarks>
        /// <para>
        /// A GDI+ bitmap is useful to holding image data in memory, but it cannot be sent to the GPU for use as a texture. This method allows an application to convert the GDI+ bitmap into a
        /// <see cref="GorgonTexture2D"/>.
        /// </para>
        /// <para>
        /// The resulting <see cref="GorgonTexture2D"/> will only contain a single mip level, and single array level. The only image type available will be 2D (i.e. image with a width and height). The GDI+
        /// bitmap should have a 32bpp rgba format, or a 24bpp rgb format or else an exception will be thrown.
        /// </para>
        /// <para>
        /// The optional <paramref name="options"/>parameter will define how Gorgon and shaders should handle the texture.  The <see cref="GorgonTextureLoadOptions"/> type contains the following:
        /// <list type="bullet">
        ///		<item>
        ///			<term>Binding</term>
        ///			<description>When defined, will indicate the <see cref="TextureBinding"/> that defines how the texture will be bound to the graphics pipeline. If it is omitted, then the binding will be
        ///         <see cref="TextureBinding.ShaderResource"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Usage</term>
        ///			<description>When defined, will indicate the preferred usage for the texture. If it is omitted, then the usage will be set to <see cref="ResourceUsage.Default"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Multisample info</term>
        ///			<description>When defined (i.e. not <b>null</b>), defines the multisampling to apply to the texture. If omitted, then the default is <see cref="GorgonMultisampleInfo.NoMultiSampling"/>.</description>
        ///		</item>
        ///		<item>
        ///		    <term>ConvertToPremultipliedAlpha</term>
        ///		    <description>Converts the image to premultiplied alpha before uploading the image data to the texture.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// </remarks>
        public static GorgonTexture2D ToTexture2D(this Bitmap gdiBitmap,
                                                  GorgonGraphics graphics,
                                                  GorgonTexture2DLoadOptions options = null)
        {
            if (gdiBitmap == null)
            {
                throw new ArgumentNullException(nameof(gdiBitmap));
            }

            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics));
            }

            if (options == null)
            {
                options = _defaultLoadOptions;
            }

            if (string.IsNullOrEmpty(options.Name))
            {
                options.Name = GorgonGraphicsResource.GenerateName(GorgonTexture2D.NamePrefix);
            }

            using (IGorgonImage image = gdiBitmap.ToGorgonImage())
            {
                if (options.ConvertToPremultipliedAlpha)
                {
                    image.ConvertToPremultipliedAlpha();
                }

                return(new GorgonTexture2D(graphics, image, options));
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Function to retrieve an image based on the current depth slice.
        /// </summary>
        /// <param name="sourceImage">The image to extract the depth slice from.</param>
        /// <param name="currentDepthSlice">The depth slice to extract.</param>
        /// <returns>A new image with the specified depth slice.</returns>
        public IGorgonImage GetDepthSliceAsImage(IGorgonImage sourceImage, int currentDepthSlice)
        {
            if (sourceImage.MipCount == 1)
            {
                return(sourceImage);
            }

            IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage, ImageType.Image2D)
            {
                Depth = 1
            });

            for (int mip = 0; mip < result.MipCount; ++mip)
            {
                int depthCount = sourceImage.GetDepthCount(mip);

                if (currentDepthSlice >= depthCount)
                {
                    return(result);
                }

                IGorgonImageBuffer srcBuffer  = sourceImage.Buffers[mip, currentDepthSlice];
                IGorgonImageBuffer destBuffer = result.Buffers[mip];

                srcBuffer.CopyTo(destBuffer);
            }

            return(result);
        }
Esempio n. 9
0
        /// <summary>Function to provide initialization for the plugin.</summary>
        /// <remarks>This method is only called when the plugin is loaded at startup.</remarks>
        protected override void OnInitialize()
        {
            ViewFactory.Register <ISpriteContent>(() => new SpriteEditorView());

            // Get built-in codec list.
            _defaultCodec = new GorgonV3SpriteBinaryCodec(GraphicsContext.Renderer2D);

            SpriteEditorSettings settings = ContentPlugInService.ReadContentSettings <SpriteEditorSettings>(typeof(SpriteEditorPlugIn).FullName, new JsonSharpDxRectConverter());

            if (settings != null)
            {
                _settings = settings;
            }

            _ddsCodec = new GorgonCodecDds();

            using (var noImageStream = new MemoryStream(Resources.NoImage_256x256))
            {
                _noImage = _ddsCodec.LoadFromStream(noImageStream);
            }

            _bgPattern = GorgonTexture2DView.CreateTexture(GraphicsContext.Graphics, new GorgonTexture2DInfo($"Sprite_Editor_Bg_Preview_{Guid.NewGuid():N}")
            {
                Width  = EditorCommonResources.CheckerBoardPatternImage.Width,
                Height = EditorCommonResources.CheckerBoardPatternImage.Height
            }, EditorCommonResources.CheckerBoardPatternImage);

            _rtv = GorgonRenderTarget2DView.CreateRenderTarget(GraphicsContext.Graphics, new GorgonTexture2DInfo($"SpriteEditor_Rtv_Preview_{Guid.NewGuid():N}")
            {
                Width   = 256,
                Height  = 256,
                Format  = BufferFormat.R8G8B8A8_UNorm,
                Binding = TextureBinding.ShaderResource
            });
        }
Esempio n. 10
0
        /// <summary>
        /// Function to retrieve an image based on the current mip level.
        /// </summary>
        /// <param name="sourceImage">The image to extract the mip level from.</param>
        /// <param name="currentMipLevel">The mip level to extract.</param>
        /// <returns>A new image with the specified mip level.</returns>
        public IGorgonImage GetMipLevelAsImage(IGorgonImage sourceImage, int currentMipLevel)
        {
            if (sourceImage.MipCount == 1)
            {
                return(sourceImage);
            }

            int depthCount = 1;

            if (sourceImage.ImageType == ImageType.Image3D)
            {
                depthCount = sourceImage.GetDepthCount(currentMipLevel);
            }

            IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage)
            {
                Width    = sourceImage.Buffers[currentMipLevel].Width,
                Height   = sourceImage.Buffers[currentMipLevel].Height,
                Depth    = depthCount,
                MipCount = 1
            });

            for (int array = 0; array < sourceImage.ArrayCount; ++array)
            {
                for (int depth = 0; depth < result.Depth; ++depth)
                {
                    IGorgonImageBuffer srcBuffer  = sourceImage.Buffers[currentMipLevel, sourceImage.ImageType == ImageType.Image3D ? depth : array];
                    IGorgonImageBuffer destBuffer = result.Buffers[0, sourceImage.ImageType == ImageType.Image3D ? depth : array];

                    srcBuffer.CopyTo(destBuffer);
                }
            }

            return(result);
        }
Esempio n. 11
0
        /// <summary>
        /// Function to load a texture from a file.
        /// </summary>
        /// <param name="graphics">The graphics interface that will own the texture.</param>
        /// <param name="filePath">The path to the file.</param>
        /// <param name="codec">The codec that is used to decode the the data in the stream.</param>
        /// <param name="options">[Optional] Options used to further define the texture.</param>
        /// <returns>A new <see cref="GorgonTexture3DView"/></returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, <paramref name="filePath"/>, or the <paramref name="codec"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="filePath"/> parameter is empty.</exception>
        /// <remarks>
        /// <para>
        /// This will load an <see cref="IGorgonImage"/> from a file on disk and put it into a <see cref="GorgonTexture3D"/> object and return a <see cref="GorgonTexture3DView"/>.
        /// </para>
        /// <para>
        /// If specified, the <paramref name="options"/>parameter will define how Gorgon and shaders should handle the texture.  The <see cref="GorgonTextureLoadOptions"/> type contains the following:
        /// <list type="bullet">
        ///		<item>
        ///			<term>Binding</term>
        ///			<description>When defined, will indicate the <see cref="TextureBinding"/> that defines how the texture will be bound to the graphics pipeline. If it is omitted, then the binding will be
        ///         <see cref="TextureBinding.ShaderResource"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Usage</term>
        ///			<description>When defined, will indicate the preferred usage for the texture. If it is omitted, then the usage will be set to <see cref="ResourceUsage.Default"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Multisample info</term>
        ///			<description>When defined (i.e. not <b>null</b>), defines the multisampling to apply to the texture. If omitted, then the default is <see cref="GorgonMultisampleInfo.NoMultiSampling"/>.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// <para>
        /// Since the <see cref="GorgonTexture3D"/> created by this method is linked to the <see cref="GorgonTexture3DView"/> returned, disposal of either one will dispose of the other on your behalf. If
        /// the user created a <see cref="GorgonTexture3DView"/> from the <see cref="GorgonTexture3D.GetShaderResourceView"/> method on the <see cref="GorgonTexture3D"/>, then it's assumed the user knows
        /// what they are doing and will handle the disposal of the texture and view on their own.
        /// </para>
        /// </remarks>
        public static GorgonTexture3DView FromFile(GorgonGraphics graphics, string filePath, IGorgonImageCodec codec, GorgonTextureLoadOptions options = null)
        {
            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics));
            }

            if (filePath == null)
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentEmptyException(nameof(filePath));
            }

            if (codec == null)
            {
                throw new ArgumentNullException(nameof(codec));
            }

            using (IGorgonImage image = codec.LoadFromFile(filePath))
            {
                GorgonTexture3D     texture = image.ToTexture3D(graphics, options);
                GorgonTexture3DView view    = texture.GetShaderResourceView();
                view.OwnsResource = true;
                return(view);
            }
        }
Esempio n. 12
0
        /// <summary>Function to convert the specified image into a volume image.</summary>
        /// <param name="image">The image to convert.</param>
        /// <returns>The converted image.</returns>
        public IGorgonImage ConvertToVolume(IGorgonImage image)
        {
            IGorgonImage result = null;

            try
            {
                result = new GorgonImage(new GorgonImageInfo(image, ImageType.Image3D)
                {
                    ArrayCount = 1,
                    Depth      = 1
                });

                // Copy the mip levels.
                for (int i = 0; i < result.MipCount; ++i)
                {
                    image.Buffers[i].CopyTo(result.Buffers[i]);
                }
            }
            catch
            {
                result?.Dispose();
                throw;
            }

            return(result);
        }
Esempio n. 13
0
        /// <summary>
        /// Function to persist a <see cref="IGorgonImage"/> to a stream.
        /// </summary>
        /// <param name="imageData">A <see cref="IGorgonImage"/> to persist to the stream.</param>
        /// <param name="stream">The stream that will receive the image data.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/>, or the <paramref name="imageData"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="stream"/> is read only.</exception>
        /// <exception cref="NotSupportedException">Thrown when the image data in the stream has a pixel format that is unsupported by the codec.</exception>
        /// <remarks>
        /// <para>
        /// When persisting image data via a codec, the image must have a format that the codec can recognize. This list of supported formats is provided by the <see cref="SupportedPixelFormats"/>
        /// property. Applications may convert their image data a supported format before saving the data using a codec.
        /// </para>
        /// </remarks>
        public override void SaveToStream(IGorgonImage imageData, Stream stream)
        {
            if (imageData == null)
            {
                throw new ArgumentNullException(nameof(imageData));
            }

            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanWrite)
            {
                throw new IOException(string.Format(Resources.GORIMG_ERR_STREAM_IS_READONLY));
            }

            var wic = new WicUtilities();

            try
            {
                if (SupportedPixelFormats.All(item => item != imageData.Format))
                {
                    throw new NotSupportedException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, imageData.Format));
                }

                IReadOnlyDictionary <string, object> metaData = GetCustomEncodingMetadata(0, imageData);
                wic.EncodeImageData(imageData, stream, SupportedFileFormat, EncodingOptions, metaData);
            }
            finally
            {
                wic.Dispose();
            }
        }
        /// <summary>
        /// Function to create a <see cref="GorgonTexture1D"/> from a <see cref="GorgonImage"/>.
        /// </summary>
        /// <param name="image">The image used to create the texture.</param>
        /// <param name="graphics">The graphics interface used to create the texture.</param>
        /// <param name="options">[Optional] Options used to further define the texture.</param>
        /// <returns>A new <see cref="GorgonTexture1D"/> containing the data from the <paramref name="image"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="image"/>, or the <paramref name="graphics"/> parameter is <b>null</b>.</exception>
        /// <remarks>
        /// <para>
        /// A <see cref="GorgonImage"/> is useful to holding image data in memory, but it cannot be sent to the GPU for use as a texture. This method allows an application to convert the
        /// <see cref="GorgonImage"/> into a <see cref="GorgonTexture1D"/>.
        /// </para>
        /// <para>
        /// If specified, the <paramref name="options"/>parameter will define how Gorgon and shaders should handle the texture.  The <see cref="GorgonTextureLoadOptions"/> type contains the following:
        /// <list type="bullet">
        ///		<item>
        ///			<term>Binding</term>
        ///			<description>When defined, will indicate the <see cref="TextureBinding"/> that defines how the texture will be bound to the graphics pipeline. If it is omitted, then the binding will be
        ///         <see cref="TextureBinding.ShaderResource"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Usage</term>
        ///			<description>When defined, will indicate the preferred usage for the texture. If it is omitted, then the usage will be set to <see cref="ResourceUsage.Default"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Multisample info</term>
        ///			<description>This is not available on 1D textures, and is ignored.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// </remarks>
        public static GorgonTexture1D ToTexture1D(this IGorgonImage image,
                                                  GorgonGraphics graphics,
                                                  GorgonTextureLoadOptions options = null)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }

            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics));
            }

            if (options == null)
            {
                options = _defaultLoadOptions;
            }

            if (string.IsNullOrEmpty(options.Name))
            {
                options.Name = GorgonGraphicsResource.GenerateName(GorgonTexture1D.NamePrefix);
            }

            return(new GorgonTexture1D(graphics, image, options));
        }
Esempio n. 15
0
        /// <summary>
        /// Function to convert the image to B4G4R4A4.
        /// </summary>
        /// <param name="baseImage">The base image to convert.</param>
        /// <param name="dithering">Dithering to apply to the converstion to B8G8R8A8.</param>
        /// <returns>The updated image.</returns>
        private static IGorgonImage ConvertToB4G4R4A4(IGorgonImage baseImage, ImageDithering dithering)
        {
            // This temporary image will be used to convert to B8G8R8A8.
            IGorgonImage newImage = baseImage;

            IGorgonImageInfo destInfo = new GorgonImageInfo(baseImage.ImageType, BufferFormat.B4G4R4A4_UNorm)
            {
                Depth      = baseImage.Depth,
                Height     = baseImage.Height,
                Width      = baseImage.Width,
                ArrayCount = baseImage.ArrayCount,
                MipCount   = baseImage.MipCount
            };

            // This is our working buffer for B4G4R4A4.
            IGorgonImage destImage = new GorgonImage(destInfo);

            try
            {
                // If necessary, convert to B8G8R8A8. Otherwise, we'll just downsample directly.
                if ((newImage.Format != BufferFormat.B8G8R8A8_UNorm) &&
                    (newImage.Format != BufferFormat.R8G8B8A8_UNorm))
                {
                    newImage = baseImage.Clone();
                    ConvertToFormat(newImage, BufferFormat.B8G8R8A8_UNorm, dithering);
                }

                // The next step is to manually downsample to R4G4B4A4.
                // Because we're doing this manually, dithering won't be an option unless unless we've downsampled from a much higher bit format when converting to B8G8R8A8.
                for (int array = 0; array < newImage.ArrayCount; ++array)
                {
                    for (int mip = 0; mip < newImage.MipCount; ++mip)
                    {
                        int depthCount = newImage.GetDepthCount(mip);

                        for (int depth = 0; depth < depthCount; depth++)
                        {
                            IGorgonImageBuffer destBuffer = destImage.Buffers[mip, destInfo.ImageType == ImageType.Image3D ? depth : array];
                            IGorgonImageBuffer srcBuffer  = newImage.Buffers[mip, newImage.ImageType == ImageType.Image3D ? depth : array];

                            ConvertPixelsToB4G4R4A4(destBuffer, srcBuffer);
                        }
                    }
                }

                destImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                destImage.Dispose();

                if (newImage != baseImage)
                {
                    newImage.Dispose();
                }
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Handles the Click event of the ButtonImagePath control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void ButtonImagePath_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;

            IGorgonImage image = null;
            var          png   = new GorgonCodecPng();

            try
            {
                if (DialogOpenPng.ShowDialog(this) != DialogResult.OK)
                {
                    return;
                }

                TextImagePath.Text = DialogOpenPng.FileName;
                _sourceTexture?.Texture?.Dispose();
                _outputTexture?.Dispose();
                _sourceTexture = null;
                _outputTexture = null;

                image          = png.LoadFromFile(DialogOpenPng.FileName);
                _sourceTexture = image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm)
                                 .ToTexture2D(_graphics,
                                              new GorgonTexture2DLoadOptions
                {
                    Name =
                        Path.GetFileNameWithoutExtension(DialogOpenPng.FileName)
                }).GetShaderResourceView();

                _outputTexture = new GorgonTexture2D(_graphics,
                                                     new GorgonTexture2DInfo(_sourceTexture, "Output")
                {
                    Format  = BufferFormat.R8G8B8A8_Typeless,
                    Binding = TextureBinding.ShaderResource | TextureBinding.ReadWriteView
                });

                // Get an SRV for the output texture so we can render it later.
                _outputView = _outputTexture.GetShaderResourceView(BufferFormat.R8G8B8A8_UNorm);

                // Get a UAV for the output.
                _outputUav = _outputTexture.GetReadWriteView(BufferFormat.R32_UInt);

                // Process the newly loaded texture.
                _sobel.Process(_sourceTexture, _outputUav, TrackThickness.Value, TrackThreshold.Value / 100.0f);

                TrackThreshold.Enabled = TrackThickness.Enabled = true;
            }
            catch (Exception ex)
            {
                GorgonDialogs.ErrorBox(this, ex);
                TrackThreshold.Enabled = TrackThickness.Enabled = false;
            }
            finally
            {
                image?.Dispose();
                Cursor.Current = Cursors.Default;
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Function to load an image from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the image data to read.</param>
        /// <param name="size">[Optional] The size of the image within the stream, in bytes.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the image data from the stream.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="stream"/> is write only.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown when the <paramref name="size"/> parameter is less than 1.</exception>
        /// <exception cref="EndOfStreamException">Thrown when the amount of data requested exceeds the size of the stream minus its current position.</exception>
        /// <exception cref="GorgonException">Thrown when the image data in the stream has a pixel format that is unsupported.</exception>
        /// <remarks>
        /// <para>
        /// When the <paramref name="size"/> parameter is specified, the image data will be read from the stream up to the amount specified. If it is omitted, then image data will be read up to the end of
        /// the stream.
        /// </para>
        /// </remarks>
        public IGorgonImage LoadFromStream(Stream stream, long?size = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException(Resources.GORIMG_ERR_STREAM_IS_WRITEONLY, nameof(stream));
            }

            if (size + stream.Position > stream.Length)
            {
                throw new EndOfStreamException();
            }

            if (size < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(size), Resources.GORIMG_ERR_IMAGE_BYTE_LENGTH_TOO_SHORT);
            }

            long basePosition = stream.Position;

            if (size == null)
            {
                size = stream.Length;
            }

            Stream externalStream = stream;

            try
            {
                if (!stream.CanSeek)
                {
                    externalStream = new DX.DataStream((int)(size ?? stream.Length), true, true);
                    stream.CopyTo(externalStream, (int)(size ?? stream.Length));
                    externalStream.Position = 0;
                }

                IGorgonImage result = OnDecodeFromStream(externalStream, size.Value);

                // Move the base stream to the number of bytes written (this is already done if we've copied the stream into memory above).
                if (stream.Position < basePosition + size)
                {
                    stream.Position = basePosition + size.Value;
                }

                return(result);
            }
            finally
            {
                if (externalStream != stream)
                {
                    externalStream?.Dispose();
                }
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Function to set the alpha value for an image.
        /// </summary>
        /// <param name="sourceImage">The source image.</param>
        /// <param name="currentMipLevel">The current mip map level.</param>
        /// <param name="currentArrayOrDepth">The current array index or depth slice.</param>
        /// <param name="value">The value to assign.</param>
        /// <param name="inclusionRange">The range of alpha values to update.</param>
        /// <returns>A new image with the updated alpha.</returns>
        public IGorgonImage SetAlphaValue(IGorgonImage sourceImage, int currentMipLevel, int currentArrayOrDepth, int value, GorgonRange inclusionRange)
        {
            IGorgonImage result = sourceImage.Clone();

            result.Buffers[currentMipLevel, currentArrayOrDepth]
            .SetAlpha(value / 255.0f, new GorgonRangeF(inclusionRange.Minimum / 255.0f, inclusionRange.Maximum / 255.0f));

            return(result);
        }
Esempio n. 19
0
        /// <summary>
        /// Function to convert the image data into a premultiplied format.
        /// </summary>
        /// <param name="baseImage">The image to convert.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the image data with the premultiplied alpha pixel data.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> is <b>null</b>.</exception>
        /// <exception cref="ArgumentException">Thrown when the original format could not be converted to <see cref="BufferFormat.R8G8B8A8_UNorm"/>.</exception>
        /// <remarks>
        /// <para>
        /// Use this to convert an image to a premultiplied format. This takes each Red, Green and Blue element and multiplies them by the Alpha element.
        /// </para>
        /// <para>
        /// Because this method will only operate on <see cref="BufferFormat.R8G8B8A8_UNorm"/> formattted image data, the image will be converted to that format and converted back to its original format
        /// after the alpha is premultiplied. This may cause color fidelity issues. If the image cannot be converted, then an exception will be thrown.
        /// </para>
        /// </remarks>
        public static IGorgonImage ConvertToPremultipliedAlpha(this IGorgonImage baseImage)
        {
            IGorgonImage newImage = null;

            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            try
            {
                // Worker image.
                var cloneImageInfo = new GorgonImageInfo(baseImage)
                {
                    HasPreMultipliedAlpha = true
                };
                newImage = new GorgonImage(cloneImageInfo);
                baseImage.CopyTo(newImage);

                if (newImage.Format != BufferFormat.R8G8B8A8_UNorm)
                {
                    if (!newImage.CanConvertToFormat(BufferFormat.R8G8B8A8_UNorm))
                    {
                        throw new ArgumentException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, BufferFormat.R8G8B8A8_UNorm), nameof(baseImage));
                    }

                    // Clone the image so we can convert it to the correct format.
                    newImage.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm);
                }

                unsafe
                {
                    int *imagePtr = (int *)(newImage.ImageData);

                    for (int i = 0; i < newImage.SizeInBytes; i += newImage.FormatInfo.SizeInBytes)
                    {
                        var color = GorgonColor.FromABGR(*imagePtr);
                        color         = new GorgonColor(color.Red * color.Alpha, color.Green * color.Alpha, color.Blue * color.Alpha, color.Alpha);
                        *(imagePtr++) = color.ToABGR();
                    }
                }

                if (newImage.Format != baseImage.Format)
                {
                    newImage.ConvertToFormat(baseImage.Format);
                }

                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
            }
        }
Esempio n. 20
0
        /// <summary>Function to resize the image to fit within the width and height specified.</summary>
        /// <param name="resizeImage">The image tor resize.</param>
        /// <param name="newSize">The new size for the image.</param>
        /// <param name="filter">The filter to apply when resizing.</param>
        /// <param name="preserveAspect"><b>true</b> to preserve the aspect ratio of the image, <b>false</b> to ignore it.</param>
        public void Resize(IGorgonImage resizeImage, DX.Size2 newSize, ImageFilter filter, bool preserveAspect)
        {
            if (preserveAspect)
            {
                float imageScale = ((float)newSize.Width / resizeImage.Width).Min((float)newSize.Height / resizeImage.Height);
                newSize = new DX.Size2((int)(resizeImage.Width * imageScale), (int)(resizeImage.Height * imageScale));
            }

            resizeImage.Resize(newSize.Width, newSize.Height, resizeImage.Depth, filter);
        }
Esempio n. 21
0
        /// <summary>
        /// Function to decompress a block compressed file into a standard pixel format.
        /// </summary>
        /// <param name="imageFile">The file to decompress</param>
        /// <param name="metadata">The metadata for the file.</param>
        /// <returns>The decompressed image.</returns>
        public IGorgonImage Decompress(ref IGorgonVirtualFile imageFile, IGorgonImageInfo metadata)
        {
            string             directory      = Path.GetDirectoryName(imageFile.PhysicalFile.FullPath);
            IGorgonImage       result         = null;
            Process            texConvProcess = null;
            Stream             inStream       = null;
            IGorgonVirtualFile decodedFile    = null;

            var info = new ProcessStartInfo
            {
                Arguments        = $"-f {_d3dFormats[metadata.Format]} -y -m {metadata.MipCount} -fl 12.0 -ft DDS -o \"{directory}\" -nologo -px decoded {imageFile.PhysicalFile.FullPath}\"",
                ErrorDialog      = true,
                FileName         = _texConv.FullName,
                WorkingDirectory = directory,
                UseShellExecute  = false,
#if DEBUG
                CreateNoWindow = false,
#else
                CreateNoWindow = true,
#endif
                RedirectStandardError  = true,
                RedirectStandardOutput = true
            };

            try
            {
                texConvProcess = Process.Start(info);

                if (texConvProcess == null)
                {
                    return(null);
                }

                texConvProcess.WaitForExit();

                _writer.FileSystem.Refresh();
                imageFile = _writer.FileSystem.GetFile(imageFile.FullPath);

                decodedFile = _writer.FileSystem.GetFile(imageFile.Directory.FullPath + "decoded" + imageFile.Name);
                inStream    = decodedFile.OpenStream();
                result      = _codec.LoadFromStream(inStream);

                return(result);
            }
            finally
            {
                texConvProcess?.Dispose();
                inStream?.Dispose();

                if (decodedFile != null)
                {
                    _writer.DeleteFile(decodedFile.FullPath);
                }
            }
        }
Esempio n. 22
0
        /// <summary>
        /// Function to convert the image from B4G4R4A4.
        /// </summary>
        /// <param name="baseImage">The base image to convert.</param>
        /// <param name="destFormat">The destination format.</param>
        /// <returns>The updated image.</returns>
        private static IGorgonImage ConvertFromB4G4R4A4(IGorgonImage baseImage, BufferFormat destFormat)
        {
            // If we're converting to R8G8B8A8 or B8G8R8A8, then use those formats, otherwise, default to B8G8R8A8 as an intermediate buffer.
            BufferFormat tempFormat = ((destFormat != BufferFormat.B8G8R8A8_UNorm) && (destFormat != BufferFormat.R8G8B8A8_UNorm)) ? BufferFormat.B8G8R8A8_UNorm : destFormat;

            // Create an worker image in B8G8R8A8 format.
            IGorgonImageInfo destInfo = new GorgonImageInfo(baseImage.ImageType, tempFormat)
            {
                Depth      = baseImage.Depth,
                Height     = baseImage.Height,
                Width      = baseImage.Width,
                ArrayCount = baseImage.ArrayCount,
                MipCount   = baseImage.MipCount
            };

            // Our destination image for B8G8R8A8 or R8G8B8A8.
            var destImage = new GorgonImage(destInfo);

            try
            {
                // We have to manually upsample from R4G4B4A4 to B8R8G8A8.
                // Because we're doing this manually, dithering won't be an option unless
                for (int array = 0; array < baseImage.ArrayCount; ++array)
                {
                    for (int mip = 0; mip < baseImage.MipCount; ++mip)
                    {
                        int depthCount = baseImage.GetDepthCount(mip);

                        for (int depth = 0; depth < depthCount; depth++)
                        {
                            IGorgonImageBuffer destBuffer = destImage.Buffers[mip, baseImage.ImageType == ImageType.Image3D ? depth : array];
                            IGorgonImageBuffer srcBuffer  = baseImage.Buffers[mip, baseImage.ImageType == ImageType.Image3D ? depth : array];

                            ConvertPixelsFromB4G4R4A4(destBuffer, srcBuffer);
                        }
                    }
                }

                // If the destination format is not R8G8B8A8 or B8G8R8A8, then we need to do more conversion.
                if (destFormat != destImage.Format)
                {
                    ConvertToFormat(destImage, destFormat);
                }

                // Update the base image with our worker image.
                destImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                destImage.Dispose();
            }
        }
Esempio n. 23
0
        /// <summary>
        /// Function to crop the image to the rectangle passed to the parameters.
        /// </summary>
        /// <param name="baseImage">The image to resize.</param>
        /// <param name="cropRect">The rectangle that will be used to crop the image.</param>
        /// <param name="newDepth">The new depth for the image (for <see cref="ImageType.Image3D"/> images).</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the resized image.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="newDepth"/> parameter is less than 1.</exception>
        /// <remarks>
        /// <para>
        /// This method will crop the existing image a smaller version of itself as a new <see cref="IGorgonImage"/>. If the sizes are the same, or the <paramref name="cropRect"/> is larger than the size
        /// of the <paramref name="baseImage"/>, then no changes will be made.
        /// </para>
        /// </remarks>
        public static IGorgonImage Crop(this IGorgonImage baseImage, DX.Rectangle cropRect, int newDepth)
        {
            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            if ((newDepth < 1) && (baseImage.ImageType == ImageType.Image3D))
            {
                throw new ArgumentOutOfRangeException(Resources.GORIMG_ERR_IMAGE_DEPTH_TOO_SMALL, nameof(newDepth));
            }

            // Only use the appropriate dimensions.
            switch (baseImage.ImageType)
            {
            case ImageType.Image1D:
                cropRect.Height = baseImage.Height;
                break;

            case ImageType.Image2D:
            case ImageType.ImageCube:
                newDepth = baseImage.Depth;
                break;
            }

            // If the intersection of the crop rectangle and the source buffer are the same (and the depth is the same), then we don't need to crop.
            var bufferRect = new DX.Rectangle(0, 0, baseImage.Width, baseImage.Height);
            var clipRect   = DX.Rectangle.Intersect(cropRect, bufferRect);

            if ((bufferRect.Equals(ref clipRect)) && (newDepth == baseImage.Depth))
            {
                return(baseImage);
            }

            var wic = new WicUtilities();

            IGorgonImage newImage = null;

            try
            {
                int calcMipLevels = GorgonImage.CalculateMaxMipCount(cropRect.Width, cropRect.Height, newDepth).Min(baseImage.MipCount);
                newImage = wic.Resize(baseImage, cropRect.X, cropRect.Y, cropRect.Width, cropRect.Height, newDepth, calcMipLevels, ImageFilter.Point, ResizeMode.Crop);

                // Send the data over to the new image.
                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
                wic.Dispose();
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Function to render the image data into an 32 bit RGBA pixel format render target and then return it as the properly formatted image data.
        /// </summary>
        /// <param name="texture">The texture to render.</param>
        /// <returns>The converted image data for the texture.</returns>
        private IGorgonImage RenderImageData(GorgonTexture2DView texture)
        {
            GorgonRenderTargetView   oldRtv        = _graphics.RenderTargets[0];
            GorgonRenderTarget2DView convertTarget = null;
            GorgonTexture2DView      rtvTexture    = null;
            IGorgonImage             tempImage     = null;
            BufferFormat             targetFormat  = texture.FormatInformation.IsSRgb ? BufferFormat.R8G8B8A8_UNorm_SRgb : BufferFormat.R8G8B8A8_UNorm;

            try
            {
                IGorgonImage resultImage = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, targetFormat)
                {
                    Width      = texture.Width,
                    Height     = texture.Height,
                    ArrayCount = texture.ArrayCount
                });

                convertTarget = GorgonRenderTarget2DView.CreateRenderTarget(_graphics, new GorgonTexture2DInfo(texture, "Convert_rtv")
                {
                    ArrayCount = 1,
                    MipLevels  = 1,
                    Format     = targetFormat,
                    Binding    = TextureBinding.ShaderResource
                });

                rtvTexture = convertTarget.GetShaderResourceView();

                for (int i = 0; i < texture.ArrayCount; ++i)
                {
                    convertTarget.Clear(GorgonColor.BlackTransparent);
                    _graphics.SetRenderTarget(convertTarget);
                    _renderer.Begin();
                    _renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, texture.Width, texture.Height),
                                                  GorgonColor.White,
                                                  texture,
                                                  new DX.RectangleF(0, 0, 1, 1),
                                                  i);
                    _renderer.End();

                    tempImage?.Dispose();
                    tempImage = convertTarget.Texture.ToImage();
                    tempImage.Buffers[0].CopyTo(resultImage.Buffers[0, i]);
                }

                return(resultImage);
            }
            finally
            {
                tempImage?.Dispose();
                _graphics.SetRenderTarget(oldRtv);
                rtvTexture?.Dispose();
                convertTarget?.Dispose();
            }
        }
Esempio n. 25
0
        /// <summary>Function to create the texture for the view.</summary>
        /// <param name="graphics">The graphics interface used to create the texture.</param>
        /// <param name="imageData">The image data to create the texture from.</param>
        /// <param name="name">The name of the texture.</param>
        protected override void OnCreateTexture(GorgonGraphics graphics, IGorgonImage imageData, string name)
        {
            _texture = imageData.ToTexture2D(graphics, new GorgonTexture2DLoadOptions
            {
                Name          = name,
                Binding       = TextureBinding.ShaderResource,
                Usage         = ResourceUsage.Immutable,
                IsTextureCube = false
            });

            _textureView = _texture.GetShaderResourceView();
        }
Esempio n. 26
0
        /// <summary>Function to create the texture for the view.</summary>
        /// <param name="graphics">The graphics interface used to create the texture.</param>
        /// <param name="imageData">The image data to create the texture from.</param>
        /// <param name="name">The name of the texture.</param>
        protected override void OnCreateTexture(GorgonGraphics graphics, IGorgonImage imageData, string name)
        {
            _texture = imageData.ToTexture3D(graphics, new GorgonTextureLoadOptions
            {
                Name    = name,
                Binding = TextureBinding.ShaderResource,
                Usage   = ResourceUsage.Immutable
            });

            _textureView = _texture.GetShaderResourceView();
            _volRenderer.AssignTexture(_textureView);
        }
Esempio n. 27
0
        /// <summary>
        /// Function to copy an image onto another image, using the supplied alignment.
        /// </summary>
        /// <param name="srcImage">The image to copy.</param>
        /// <param name="destImage">The destination image.</param>
        /// <param name="startMip">The starting mip map level to copy.</param>
        /// <param name="startArrayOrDepth">The starting array index for 2D images, or depth slice for 3D images.</param>
        /// <param name="alignment">The alignment of the image, relative to the source image.</param>
        public void CopyTo(IGorgonImage srcImage, IGorgonImage destImage, int startMip, int startArrayOrDepth, Alignment alignment)
        {
            int mipCount   = destImage.MipCount - startMip;
            int arrayCount = destImage.ArrayCount - (destImage.ImageType == ImageType.Image3D ? 0 : startArrayOrDepth);

            int minMipCount   = mipCount.Min(srcImage.MipCount);
            int minArrayCount = arrayCount.Min(srcImage.ArrayCount);

            var size = new DX.Size2(srcImage.Width, srcImage.Height);

            for (int array = 0; array < minArrayCount; ++array)
            {
                for (int mip = 0; mip < minMipCount; ++mip)
                {
                    int destDepthCount = destImage.GetDepthCount(mip + startMip);
                    int minDepth       = destDepthCount.Min(srcImage.GetDepthCount(mip));

                    for (int depth = 0; depth < minDepth; ++depth)
                    {
                        int destOffset;
                        if (destImage.ImageType == ImageType.Image3D)
                        {
                            destOffset = depth + startArrayOrDepth;

                            // We're at the end of the destination buffer, skip the rest of the slices.
                            if (destOffset >= destDepthCount)
                            {
                                break;
                            }
                        }
                        else
                        {
                            destOffset = array + startArrayOrDepth;
                        }

                        IGorgonImageBuffer srcBuffer  = srcImage.Buffers[mip, srcImage.ImageType == ImageType.Image3D ? depth : array];
                        IGorgonImageBuffer destBuffer = destImage.Buffers[mip + startMip, destOffset];

                        // Clear the destination buffer before copying.
                        destBuffer.Data.Fill(0);

                        int minWidth   = destBuffer.Width.Min(srcBuffer.Width);
                        int minHeight  = destBuffer.Height.Min(srcBuffer.Height);
                        var copyRegion = new DX.Rectangle(0, 0, minWidth, minHeight);

                        DX.Point startLoc = GetAnchorStart(new DX.Size2(minWidth, minHeight), ref size, alignment);

                        srcBuffer.CopyTo(destBuffer, copyRegion, startLoc.X, startLoc.Y);
                    }
                }
            }
        }
Esempio n. 28
0
        /// <summary>
        /// Function to convert the pixel format of an image into another pixel format.
        /// </summary>
        /// <param name="baseImage">The image to convert.</param>
        /// <param name="format">The new pixel format for the image.</param>
        /// <param name="dithering">[Optional] Flag to indicate the type of dithering to perform when the bit depth for the <paramref name="format"/> is lower than the original bit depth.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the image data with the converted pixel format.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="baseImage"/> is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="format"/> is set to <see cref="BufferFormat.Unknown"/>.
        /// <para>-or-</para>
        /// <para>Thrown when the original format could not be converted into the desired <paramref name="format"/>.</para>
        /// </exception>
        /// <remarks>
        /// <para>
        /// Use this to convert an image format from one to another. The conversion functionality uses Windows Imaging Components (WIC) to perform the conversion.
        /// </para>
        /// <para>
        /// Because this method uses WIC, not all formats will be convertible. To determine if a format can be converted, use the <see cref="GorgonImage.CanConvertToFormat"/> method.
        /// </para>
        /// <para>
        /// For the <see cref="BufferFormat.B4G4R4A4_UNorm"/> format, Gorgon has to perform a manual conversion since that format is not supported by WIC. Because of this, the
        /// <paramref name="dithering"/> flag will be ignored when downsampling to that format.
        /// </para>
        /// </remarks>
        public static IGorgonImage ConvertToFormat(this IGorgonImage baseImage, BufferFormat format, ImageDithering dithering = ImageDithering.None)
        {
            if (baseImage == null)
            {
                throw new ArgumentNullException(nameof(baseImage));
            }

            if ((format == BufferFormat.Unknown) || (!baseImage.CanConvertToFormat(format)))
            {
                throw new ArgumentException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, format), nameof(format));
            }

            if (format == baseImage.Format)
            {
                return(baseImage);
            }

            // If we've asked for 4 bit per channel BGRA, then we have to convert the base image to B8R8G8A8,and then convert manually (no support in WIC).
            if (format == BufferFormat.B4G4R4A4_UNorm)
            {
                return(ConvertToB4G4R4A4(baseImage, dithering));
            }

            // If we're currently using B4G4R4A4, then manually convert (no support in WIC).
            if (baseImage.Format == BufferFormat.B4G4R4A4_UNorm)
            {
                return(ConvertFromB4G4R4A4(baseImage, format));
            }

            var          destInfo = new GorgonFormatInfo(format);
            WicUtilities wic      = null;

            IGorgonImage newImage = null;

            try
            {
                wic      = new WicUtilities();
                newImage = wic.ConvertToFormat(baseImage, format, dithering, baseImage.FormatInfo.IsSRgb, destInfo.IsSRgb);

                newImage.CopyTo(baseImage);

                return(baseImage);
            }
            finally
            {
                newImage?.Dispose();
                wic?.Dispose();
            }
        }
Esempio n. 29
0
        /// <summary>Imports the data.</summary>
        /// <param name="temporaryDirectory">The temporary directory for writing any transitory data.</param>
        /// <param name="cancelToken">The cancel token.</param>
        /// <remarks>
        /// <para>
        /// The <paramref name="temporaryDirectory"/> should be used to write any working/temporary data used by the import.  Note that all data written into this directory will be deleted when the
        /// project is unloaded from memory.
        /// </para>
        /// </remarks>
        public FileInfo ImportData(DirectoryInfo temporaryDirectory, CancellationToken cancelToken)
        {
            var ddsCodec = new GorgonCodecDds();

            _log.Print($"Importing file '{SourceFile.FullName}' (Codec: {_codec.Name})...", LoggingLevel.Verbose);
            using (IGorgonImage image = _codec.LoadFromFile(SourceFile.FullName))
            {
                var tempFile = new FileInfo(Path.Combine(temporaryDirectory.FullName, Path.GetFileNameWithoutExtension(SourceFile.Name)));

                _log.Print($"Converting '{SourceFile.FullName}' to DDS file format. Image format [{image.Format}].", LoggingLevel.Verbose);
                ddsCodec.SaveToFile(image, tempFile.FullName);

                return(tempFile);
            }
        }
Esempio n. 30
0
        /// <summary>
        /// Function to persist a <see cref="IGorgonImage"/> to a file on the physical file system.
        /// </summary>
        /// <param name="imageData">A <see cref="IGorgonImage"/> to persist to the stream.</param>
        /// <param name="filePath">The path to the file that will hold the image data.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="filePath"/>, or the <paramref name="imageData"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="filePath"/> is empty..</exception>
        /// <exception cref="NotSupportedException">Thrown when the image data in the stream has a pixel format that is unsupported by the codec.</exception>
        /// <remarks>
        /// <para>
        /// When persisting image data via a codec, the image must have a format that the codec can recognize. This list of supported formats is provided by the <see cref="SupportedPixelFormats"/>
        /// property. Applications may convert their image data a supported format before saving the data using a codec.
        /// </para>
        /// </remarks>
        public void SaveToFile(IGorgonImage imageData, string filePath)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentEmptyException(nameof(filePath));
            }

            using (Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                SaveToStream(imageData, stream);
            }
        }