/// <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));
        }
Exemple #2
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;
            }
        }
Exemple #3
0
        /// <summary>
        /// Function to convert the image to use our custom codec.
        /// </summary>
        private void ConvertImage()
        {
            // The path to our image file for our custom codec.
            string tempPath = Path.ChangeExtension(Path.GetTempPath().FormatDirectory(Path.DirectorySeparatorChar) + Path.GetRandomFileName(), "tvImage");

            try
            {
                // Save the current texture using our useless new custom codec.
                _customCodec.SaveToFile(_image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm), tempPath);
                _image.Dispose();
                _texture?.Dispose();

                _image = _customCodec.LoadFromFile(tempPath);

                _texture = _image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions
                {
                    Name = "Converted Texture"
                }).GetShaderResourceView();
            }
            catch
            {
                // Clean up the new texture should we have an exception (this shouldn't happen, better safe than sorry).
                _image?.Dispose();
                throw;
            }
            finally
            {
                try
                {
                    File.Delete(tempPath);
                }
                // ReSharper disable once EmptyGeneralCatchClause
                catch
                {
                    // Intentionally left blank.
                    // If we can't clean up the temp file, then it's no big deal right now.
                }
            }
        }
        /// <summary>
        /// Function to save the specified image file.
        /// </summary>
        /// <param name="name">The name of the file to write into.</param>
        /// <param name="image">The image to save.</param>
        /// <param name="pixelFormat">The pixel format for the image.</param>
        /// <param name="codec">[Optional] The codec to use when saving the image.</param>
        /// <returns>The updated working file.</returns>
        public IGorgonVirtualFile SaveImageFile(string name, IGorgonImage image, BufferFormat pixelFormat, IGorgonImageCodec codec = null)
        {
            if (codec == null)
            {
                codec = DefaultCodec;
            }

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

            IGorgonVirtualFile workFile = ScratchArea.FileSystem.GetFile(name);
            var formatInfo = new GorgonFormatInfo(pixelFormat);

            // The file doesn't exist, so we need to create a dummy file.
            if (workFile == null)
            {
                using (Stream tempStream = ScratchArea.OpenStream(name, FileMode.Create))
                {
                    tempStream.WriteString("TEMP_WORKING_FILE");
                }

                workFile = ScratchArea.FileSystem.GetFile(name);
            }

            _log.Print($"Working image file: '{workFile.FullPath}'.", LoggingLevel.Verbose);


            IGorgonVirtualFile result;

            // For compressed images, we need to rely on an external tool to do the job.
            if (formatInfo.IsCompressed)
            {
                _log.Print($"Pixel format [{pixelFormat}] is a block compression format, compressing using external tool...", LoggingLevel.Intermediate);
                if ((_compressor == null) || (!codec.SupportsBlockCompression))
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_COMPRESSED_FILE, formatInfo.Format));
                }

                // Send the image data as uncompressed to our working file, so we can have something to compress.
                using (Stream outStream = ScratchArea.OpenStream(workFile.FullPath, FileMode.Create))
                {
                    codec.SaveToStream(image, outStream);
                }

                _log.Print($"Saving to working file '{workFile.FullPath}'...", LoggingLevel.Simple);
                result = _compressor.Compress(workFile, pixelFormat, image.MipCount);

                // Convert to an uncompressed format if we aren't already in that format.
                switch (pixelFormat)
                {
                case BufferFormat.BC5_SNorm when image.Format != BufferFormat.R8G8_SNorm:
                    image.ConvertToFormat(BufferFormat.R8G8_SNorm);
                    break;

                case BufferFormat.BC5_Typeless when image.Format != BufferFormat.R8G8_UNorm:
                case BufferFormat.BC5_UNorm when image.Format != BufferFormat.R8G8_UNorm:
                    image.ConvertToFormat(BufferFormat.R8G8_UNorm);
                    break;

                case BufferFormat.BC6H_Sf16 when image.Format != BufferFormat.R16G16B16A16_Float:
                case BufferFormat.BC6H_Typeless when image.Format != BufferFormat.R16G16B16A16_Float:
                case BufferFormat.BC6H_Uf16 when image.Format != BufferFormat.R16G16B16A16_Float:
                    image.ConvertToFormat(BufferFormat.R16G16B16A16_Float);
                    break;

                case BufferFormat.BC4_SNorm when image.Format != BufferFormat.R8G8_SNorm:
                    image.ConvertToFormat(BufferFormat.R8_SNorm);
                    break;

                case BufferFormat.BC4_Typeless when image.Format != BufferFormat.R8G8_UNorm:
                case BufferFormat.BC4_UNorm when image.Format != BufferFormat.R8G8_UNorm:
                    image.ConvertToFormat(BufferFormat.R8_UNorm);
                    break;

                case BufferFormat.BC1_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC1_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC2_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC2_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC3_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC3_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC7_Typeless when image.Format != BufferFormat.R8G8B8A8_UNorm:
                case BufferFormat.BC7_UNorm when image.Format != BufferFormat.R8G8B8A8_UNorm:
                    image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm);
                    break;

                case BufferFormat.BC1_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                case BufferFormat.BC2_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                case BufferFormat.BC3_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                case BufferFormat.BC7_UNorm_SRgb when image.Format != BufferFormat.R8G8B8A8_UNorm_SRgb:
                    image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm_SRgb);
                    break;
                }

                if (result == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_COMPRESSED_FILE, formatInfo.Format));
                }
            }
            else
            {
                // We've changed the pixel format, so convert prior to saving.
                if (pixelFormat != image.Format)
                {
                    _log.Print($"Image pixel format [{image.Format}] is different than requested format of [{pixelFormat}], converting...", LoggingLevel.Intermediate);
                    image.ConvertToFormat(pixelFormat);
                    _log.Print($"Converted image '{workFile.Name}' to pixel format: [{pixelFormat}].", LoggingLevel.Simple);
                }

                _log.Print($"Saving to working file '{workFile.FullPath}'...", LoggingLevel.Simple);
                using (Stream outStream = ScratchArea.OpenStream(workFile.FullPath, FileMode.Create))
                {
                    codec.SaveToStream(image, outStream);
                }

                ScratchArea.FileSystem.Refresh();
                result = ScratchArea.FileSystem.GetFile(workFile.FullPath);
            }

            return(result);
        }
Exemple #5
0
        /// <summary>
        /// Function to create a compatible image to use when drawing with this effect.
        /// </summary>
        /// <param name="diffuse">The diffuse map.</param>
        /// <param name="normalMap">The normal map.</param>
        /// <param name="specularMap">[Optional] The specular map.</param>
        /// <returns>A new image with the maps combined as an image array to use with the effect.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="diffuse"/>, or the <paramref name="normalMap"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentException">Thrown if any of the images passed in are not a <see cref="ImageType.Image2D"/> type.</exception>
        /// <remarks>
        /// <para>
        /// Since the lighting effect requires that textures be drawn using an array of 3 images, developers can use this helper method to create a new image based on separate images that will be suitable
        /// for rendering with this effect.
        /// </para>
        /// <para>
        /// The resulting image from this method is guaranteed to contain the correct image data, in the correct order, for use with this effect. The image can then be used in any of the
        /// texture types for rendering.
        /// </para>
        /// <para>
        /// The images passed to this method must be a 2D image type, otherwise an exception will thrown.
        /// </para>
        /// <para>
        /// All images passed to this method should be the same width, height and pixel format. Otherwise undesired artifacts may appear on the generated maps.
        /// </para>
        /// </remarks>
        /// <seealso cref="IGorgonImage"/>
        /// <seealso cref="GorgonTexture2D"/>
        /// <seealso cref="GorgonTexture2DView"/>
        public IGorgonImage CreateLightingImage(IGorgonImage diffuse, IGorgonImage normalMap, IGorgonImage specularMap = null)
        {
            if (diffuse == null)
            {
                throw new ArgumentNullException(nameof(diffuse));
            }

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

            if (diffuse.ImageType != ImageType.Image2D)
            {
                throw new ArgumentException(string.Format(Resources.GOR2D_ERR_2D_IMAGE_ONLY, nameof(diffuse)));
            }

            if (normalMap.ImageType != ImageType.Image2D)
            {
                throw new ArgumentException(string.Format(Resources.GOR2D_ERR_2D_IMAGE_ONLY, nameof(normalMap)));
            }

            if ((specularMap != null) && (specularMap.ImageType != ImageType.Image2D))
            {
                throw new ArgumentException(string.Format(Resources.GOR2D_ERR_2D_IMAGE_ONLY, nameof(specularMap)));
            }

            IGorgonImage result       = null;
            IGorgonImage workSpecular = specularMap?.Clone();
            IGorgonImage workDiffuse  = diffuse.Clone();
            IGorgonImage workNormal   = normalMap.Clone();

            if (workSpecular == null)
            {
                workSpecular = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, diffuse.Format)
                {
                    Width  = diffuse.Width,
                    Height = diffuse.Height
                });
                workSpecular.Buffers[0].Fill(0x00);
            }

            try
            {
                // Ensure formats are the same across all array entries.
                if (workNormal.Format != workDiffuse.Format)
                {
                    workNormal.ConvertToFormat(workDiffuse.Format);
                }

                if (workSpecular.Format != workDiffuse.Format)
                {
                    workSpecular.ConvertToFormat(workDiffuse.Format);
                }

                // Ensure width and height matches.
                if ((workNormal.Width != workDiffuse.Width) || (workDiffuse.Height != workNormal.Height))
                {
                    workNormal.Resize(workDiffuse.Width, workDiffuse.Height, 1);
                }

                if ((workSpecular.Width != workDiffuse.Width) || (workSpecular.Height != workNormal.Height))
                {
                    workSpecular.Resize(workDiffuse.Width, workDiffuse.Height, 1);
                }

                var info = new GorgonImageInfo(ImageType.Image2D, diffuse.Format)
                {
                    Width      = diffuse.Width,
                    Height     = diffuse.Height,
                    ArrayCount = 3
                };

                result = new GorgonImage(info);
                workDiffuse.Buffers[0].CopyTo(result.Buffers[0, 0]);
                workSpecular.Buffers[0].CopyTo(result.Buffers[0, 1]);
                workNormal.Buffers[0].CopyTo(result.Buffers[0, 2]);

                return(result);
            }
            catch
            {
                result?.Dispose();
                throw;
            }
            finally
            {
                workDiffuse?.Dispose();
                workNormal?.Dispose();
                workSpecular.Dispose();
            }
        }