Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        /// <summary>Function to retrieve a single file name.</summary>
        /// <returns>The selected file path, or <b>null</b> if cancelled.</returns>
        public override string GetFilename()
        {
            ConfigureDialog();
            string filePath = base.GetFilename();

            if (string.IsNullOrWhiteSpace(filePath))
            {
                return(null);
            }

            var extension = new GorgonFileExtension(Path.GetExtension(filePath));

            SelectedCodec = null;

            // Check for an extension match on the codec list.
            foreach (IGorgonImageCodec codec in _codecs.Codecs.Where(item => (item.CodecCommonExtensions.Count > 0) && (item.CanDecode)))
            {
                if (codec.CodecCommonExtensions.Any(item => extension == new GorgonFileExtension(item)))
                {
                    SelectedCodec = codec;
                    break;
                }
            }

            return(filePath);
        }
Ejemplo n.º 3
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
            });
        }
        /// <summary>
        /// Function to create a new image codec object.
        /// </summary>
        /// <param name="codec">The name of the codec to look up within the plug in.</param>
        /// <returns>A new instance of a <see cref="IGorgonImageCodec"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="codec"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="codec"/> parameter is empty.</exception>
        /// <exception cref="KeyNotFoundException">Thrown when the <paramref name="codec"/> was not found in this plug in.</exception>
        /// <remarks>
        /// <para>
        /// If the <paramref name="codec"/> is not found within the plug in, then an exception will be thrown. To determine whether the plug in has the desired <paramref name="codec"/>, check the
        /// <see cref="Codecs"/> property on the plug in to locate the plug in name.
        /// </para>
        /// </remarks>
        public IGorgonImageCodec CreateCodec(string codec)
        {
            if (codec == null)
            {
                throw new ArgumentNullException(nameof(codec));
            }

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

            if (!Codecs.Any(item => string.Equals(codec, item.Name, StringComparison.OrdinalIgnoreCase)))
            {
                throw new KeyNotFoundException(string.Format(Resources.GORIMG_ERR_CODEC_NOT_IN_PLUGIN, codec));
            }

            IGorgonImageCodec result = OnCreateCodec(codec);

            if (result == null)
            {
                throw new KeyNotFoundException(string.Format(Resources.GORIMG_ERR_CODEC_NOT_IN_PLUGIN, codec));
            }

            return(result);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Function to load the images for use with the example.
        /// </summary>
        /// <param name="codec">The codec for the images.</param>
        /// <returns><b>true</b> if files were loaded successfully, <b>false</b> if not.</returns>
        private static bool LoadImageFiles(IGorgonImageCodec codec)
        {
            DirectoryInfo dirInfo = GorgonExample.GetResourcePath(@"\Textures\PostProcess");

            FileInfo[] files = dirInfo.GetFiles("*.dds", SearchOption.TopDirectoryOnly);

            if (files.Length == 0)
            {
                GorgonDialogs.ErrorBox(null, $"No DDS images found in {dirInfo.FullName}.");
                GorgonApplication.Quit();
                return(false);
            }

            _images = new GorgonTexture2DView[files.Length];

            // Load all the DDS files from the resource area.
            for (int i = 0; i < files.Length; ++i)
            {
                _images[i] = GorgonTexture2DView.FromFile(_graphics,
                                                          files[i].FullName,
                                                          codec,
                                                          new GorgonTexture2DLoadOptions
                {
                    Binding = TextureBinding.ShaderResource,
                    Usage   = ResourceUsage.Immutable,
                    Name    = Path.GetFileNameWithoutExtension(files[i].Name)
                });
            }

            return(true);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Function to load our useless image codec plug in.
        /// </summary>
        /// <returns><b>true</b> if successful, <b>false</b> if not.</returns>
        private bool LoadCodec()
        {
            const string pluginName = "Gorgon.Graphics.Example.TvImageCodecPlugIn";

            _pluginCache = new GorgonMefPlugInCache(GorgonApplication.Log);

            // Load our plug in.
            _pluginCache.LoadPlugInAssemblies(GorgonApplication.StartupPath.FullName, "TVImageCodec.dll");

            // Activate the plugin service.
            IGorgonPlugInService pluginService = new GorgonMefPlugInService(_pluginCache);

            // Find the plugin.
            GorgonImageCodecPlugIn plugIn = pluginService.GetPlugIn <GorgonImageCodecPlugIn>(pluginName);

            if ((plugIn == null) || (plugIn.Codecs.Count == 0))
            {
                return(false);
            }

            // Normally you would enumerate the plug ins, but in this case we know there's only one.
            _customCodec = plugIn.CreateCodec(plugIn.Codecs[0].Name);

            return(_customCodec != null);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Function to retrieve the codec used by the image.
        /// </summary>
        /// <param name="file">The file containing the image content.</param>
        /// <returns>The codec used to read the file.</returns>
        private IGorgonImageCodec GetCodec(FileInfo file)
        {
            IGorgonImageCodec result = null;
            Stream            stream = null;

            try
            {
                // Locate the file extension.
                if (!string.IsNullOrWhiteSpace(file.Extension))
                {
                    var extension = new GorgonFileExtension(file.Extension);

                    result = _codecs.CodecFileTypes.FirstOrDefault(item => item.extension == extension).codec;

                    if (result != null)
                    {
                        return(result);
                    }
                }
            }
            finally
            {
                stream?.Dispose();
            }

            return(null);
        }
Ejemplo n.º 8
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()
        {
            _defaultImageCodec = new GorgonCodecDds();

            _button = new ToolPlugInRibbonButton(Resources.GOREST_TEXT_BUTTON, Resources.extract_grid_48x48, Resources.extract_grid_16x16, Resources.GOREST_GROUP_BUTTON)
            {
                Description = Resources.GOREST_DESC_BUTTON
            };
            _button.ValidateButton();
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Function to locate the associated texture codec and file for a sprite.
        /// </summary>
        /// <param name="fileSystem">The file system to evaluate.</param>
        /// <param name="localDir">The local directory for the sprite file.</param>
        /// <param name="renderer">The renderer used for resource look up.</param>
        /// <param name="textureName">The name of the texture.</param>
        /// <param name="codecs">The list of available image codecs to use when determining texture type.</param>
        /// <returns>A tuple containing the codec, the texture file, and a flag to indicate that the texture was previously loaded into memory.</returns>
        private static (IGorgonImageCodec codec, IGorgonVirtualFile file, bool alreadyLoaded) LocateTextureCodecAndFile(
            IGorgonFileSystem fileSystem,
            IGorgonVirtualDirectory localDir,
            Gorgon2D renderer,
            string textureName,
            IEnumerable <IGorgonImageCodec> codecs)
        {
            // First, attempt to locate the resource by its name.  If it's already loaded, we should not load it again.
            GorgonTexture2D texture = renderer.Graphics
                                      .LocateResourcesByName <GorgonTexture2D>(textureName)
                                      .FirstOrDefault();

            if (texture != null)
            {
                return(null, null, true);
            }

            IGorgonImageCodec codec;

            // We couldn't find the texture in our loaded resources, so try to locate it on the file system.

            // First, check the local directory.
            IEnumerable <IGorgonVirtualFile> files = fileSystem.FindFiles(localDir.FullPath, $"{textureName}.*", false);

            foreach (IGorgonVirtualFile file in files)
            {
                codec = FindTextureCodec(file, codecs);

                if (codec != null)
                {
                    return(codec, file, false);
                }
            }

            // Check to see if the name has path information for the texture in the name.
            // The GorgonEditor from v2 does this.
            if (!textureName.Contains("/"))
            {
                // It is not.  We cannot load the texture.
                return(null, null, false);
            }

            IGorgonVirtualFile textureFile = fileSystem.GetFile(textureName);

            if (textureFile == null)
            {
                return(null, null, false);
            }

            // Try to find a codec for the image file.
            codec = FindTextureCodec(textureFile, codecs);

            return(codec == null ? (null, null, false) : (codec, textureFile, false));
        }
Ejemplo n.º 10
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()
        {
            _defaultImageCodec  = new GorgonCodecDds();
            _defaultSpriteCodec = new GorgonV3SpriteBinaryCodec(GraphicsContext.Renderer2D);

            _button = new ToolPlugInRibbonButton(Resources.GORTAG_TEXT_BUTTON, Resources.texture_atlas_48x48, Resources.texture_atlas_16x16, Resources.GORTAG_GROUP_BUTTON)
            {
                Description = Resources.GORTAG_DESC_BUTTON
            };
            _button.ValidateButton();
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Function to remove a codec item from the list.
        /// </summary>
        /// <param name="codec">The codec to remove.</param>
        private void RemoveCodecItem(IGorgonImageCodec codec)
        {
            ToolStripMenuItem menuItem = MenuCodecs.Items.OfType <ToolStripMenuItem>().FirstOrDefault(item => item.Tag == codec);

            if (menuItem == null)
            {
                return;
            }

            menuItem.Click -= CodecItem_Click;
            MenuCodecs.Items.Remove(menuItem);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Function to add an image codec to the list.
        /// </summary>
        /// <param name="codec">The codec to add.</param>
        private void AddCodecItem(IGorgonImageCodec codec)
        {
            var item = new ToolStripMenuItem($"{codec.CodecDescription} ({codec.Codec})")
            {
                Name         = codec.Name,
                CheckOnClick = false,
                Tag          = codec
            };

            item.Click += CodecItem_Click;

            MenuCodecs.Items.Add(item);
        }
Ejemplo n.º 13
0
 /// <summary>Initializes a new instance of the <see cref="T:Gorgon.Editor.ImageEditor.ImageIO"/> class.</summary>
 /// <param name="defaultCodec">The default codec used by the plug in.</param>
 /// <param name="installedCodecs">The list of installed codecs.</param>
 /// <param name="importDialog">The dialog service used to export an image.</param>
 /// <param name="busyService">The busy state service.</param>
 /// <param name="scratchArea">The file system writer used to write to the temporary area.</param>
 /// <param name="bcCompressor">The block compressor used to block (de)compress image data.</param>
 /// <param name="log">The logging interface to use.</param>
 public ImageIOService(IGorgonImageCodec defaultCodec,
                       ICodecRegistry installedCodecs,
                       IExportImageDialogService exportDialog,
                       IImportImageDialogService importDialog,
                       IBusyStateService busyService,
                       IGorgonFileSystemWriter <Stream> scratchArea,
                       TexConvCompressor bcCompressor,
                       IGorgonLog log)
 {
     _exportDialog   = exportDialog;
     _importDialog   = importDialog;
     DefaultCodec    = defaultCodec;
     InstalledCodecs = installedCodecs;
     ScratchArea     = scratchArea;
     _compressor     = bcCompressor;
     _busyState      = busyService;
     _log            = log ?? GorgonLog.NullLog;
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Function to load a texture from a <see cref="Stream"/>.
        /// </summary>
        /// <param name="graphics">The graphics interface that will own the texture.</param>
        /// <param name="stream">The stream containing the texture image data.</param>
        /// <param name="codec">The codec that is used to decode the the data in the stream.</param>
        /// <param name="size">[Optional] The size of the image in the stream, in bytes.</param>
        /// <param name="options">[Optional] Options used to further define the texture.</param>
        /// <returns>A new <see cref="GorgonTexture3DReadWriteView"/></returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, <paramref name="stream"/>, or the <paramref name="codec"/> parameter is <b>null</b>.</exception>
        /// <exception cref="IOException">Thrown if the <paramref name="stream"/> is write only.</exception>
        /// <exception cref="EndOfStreamException">Thrown if reading the image would move beyond the end of the <paramref name="stream"/>.</exception>
        /// <remarks>
        /// <para>
        /// This will load an <see cref="IGorgonImage"/> from a <paramref name="stream"/> and put it into a <see cref="GorgonTexture3D"/> object and return a <see cref="GorgonTexture3DReadWriteView"/>.
        /// </para>
        /// <para>
        /// If the <paramref name="size"/> option is specified, then the method will read from the stream up to that number of bytes, so it is up to the user to provide an accurate size. If it is omitted
        /// then the <c>stream length - stream position</c> is used as the total size.
        /// </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="GorgonTexture3DReadWriteView"/> returned, disposal of either one will dispose of the other on your behalf. If
        /// the user created a <see cref="GorgonTexture3DReadWriteView"/> 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 GorgonTexture3DReadWriteView FromStream(GorgonGraphics graphics,
                                                              Stream stream,
                                                              IGorgonImageCodec codec,
                                                              long?size = null,
                                                              GorgonTextureLoadOptions options = null)
        {
            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics));
            }

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

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

            if (!stream.CanRead)
            {
                throw new IOException(Resources.GORGFX_ERR_STREAM_WRITE_ONLY);
            }

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

            if ((stream.Length - stream.Position) < size)
            {
                throw new EndOfStreamException();
            }

            using (IGorgonImage image = codec.LoadFromStream(stream, size))
            {
                GorgonTexture3D texture           = image.ToTexture3D(graphics, options);
                GorgonTexture3DReadWriteView view = texture.GetReadWriteView();
                view.OwnsResource = true;
                return(view);
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Function to perform an export of an image.
        /// </summary>
        /// <param name="file">The file to export.</param>
        /// <param name="image">The image data to export.</param>
        /// <param name="codec">The codec to use when encoding the image.</param>
        /// <returns>The path to the exported file.</returns>
        public FileInfo ExportImage(IContentFile file, IGorgonImage image, IGorgonImageCodec codec)
        {
            _exportDialog.ContentFile   = file;
            _exportDialog.SelectedCodec = codec;
            string exportFilePath = _exportDialog.GetFilename();

            if (string.IsNullOrWhiteSpace(exportFilePath))
            {
                return(null);
            }

            _busyState.SetBusy();

            var result = new FileInfo(exportFilePath);

            _log.Print($"Exporting '{file.Name}' to '{exportFilePath}' as {codec.CodecDescription}", LoggingLevel.Verbose);

            codec.SaveToFile(image, result.FullName);

            _busyState.SetIdle();

            return(result);
        }
Ejemplo n.º 16
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);
            }
        }
Ejemplo n.º 17
0
 /// <summary>Initializes a new instance of the <see cref="FileIOService"/> class.</summary>
 /// <param name="fileSystem">The file system.</param>
 /// <param name="imageCodec">The default image codec to use.</param>
 /// <param name="spriteCodec">The default sprite codec to use.</param>
 public FileIOService(IContentFileManager fileSystem, IGorgonImageCodec imageCodec, IGorgonSpriteCodec spriteCodec)
 {
     _fileSystem         = fileSystem;
     _defaultImageCodec  = imageCodec;
     _defaultSpriteCodec = spriteCodec;
 }
Ejemplo n.º 18
0
        /// <summary>
        /// Function to load a <see cref="IGorgonAnimation"/> from a <see cref="GorgonFileSystem"/>.
        /// </summary>
        /// <param name="fileSystem">The file system to load the animation from.</param>
        /// <param name="renderer">The renderer for the animation.</param>
        /// <param name="path">The path to the animation file in the file system.</param>
        /// <param name="textureOptions">[Optional] Options for the texture loaded associated the sprite.</param>
        /// <param name="animationCodecs">The list of animation codecs to try and load the animation with.</param>
        /// <param name="imageCodecs">The list of image codecs to try and load the animation texture(s) with.</param>
        /// <returns>The animation data in the file as a <see cref="IGorgonAnimation"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fileSystem"/>, <paramref name="renderer"/>, or <paramref name="path"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="path"/> parameter is empty.</exception>
        /// <exception cref="FileNotFoundException">Thrown if the file in the <paramref name="path"/> was not found.</exception>
        /// <exception cref="GorgonException">Thrown if the animation data in the file system could not be loaded because a suitable codec was not found.</exception>
        /// <remarks>
        /// <para>
        /// This method extends a <see cref="GorgonFileSystem"/> so that animations can be loaded by calling a method on the file system object itself. This negates the need for users to create complex code
        /// for loading an animation.
        /// </para>
        /// <para>
        /// When loading an animation, the method will attempt to locate any <see cref="GorgonTexture2DView"/> objects associated with the animation (if they exist). When loading, it will check:
        /// <list type="number">
        ///     <item>
        ///         <description>For a texture resource with the same name that is already loaded into memory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Use the local <see cref="IGorgonVirtualDirectory"/> for the sprite file and search for the texture in that directory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Check the entire <paramref name="fileSystem"/> for a file if the texture name contains path information (this is done by the GorgonEditor from v2).</description>
        ///     </item>
        /// </list>
        /// If the file is found, and can be loaded by one of the <paramref name="imageCodecs"/>, then it is loaded and assigned to the sprite.
        /// </para>
        /// <para>
        /// The <paramref name="animationCodecs"/> is a list of codecs for loading sprite data. If the user specifies this parameter, the only the codecs provided will be used for determining if an
        /// animation can be read. If it is not supplied, then all built-in (i.e. not plug in based) sprite codecs will be used.
        /// </para>
        /// <para>
        /// The <paramref name="imageCodecs"/> is a list of codecs for loading image data. If the user specifies this parameter, the only the codecs provided will be used for determining if an image can be
        /// read. If it is not supplied, then all built-in (i.e. not plug in based) image codecs will be used.
        /// </para>
        /// </remarks>
        /// <seealso cref="GorgonFileSystem"/>
        /// <seealso cref="GorgonTexture2DView"/>
        /// <seealso cref="IGorgonAnimation"/>
        public static IGorgonAnimation LoadAnimationFromFileSystem(this GorgonFileSystem fileSystem,
                                                                   Gorgon2D renderer,
                                                                   string path,
                                                                   GorgonTexture2DLoadOptions textureOptions           = null,
                                                                   IEnumerable <IGorgonAnimationCodec> animationCodecs = null,
                                                                   IEnumerable <IGorgonImageCodec> imageCodecs         = null)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }

            IGorgonVirtualFile file = fileSystem.GetFile(path);

            if (file == null)
            {
                throw new FileNotFoundException(string.Format(Resources.GOR2DIO_ERR_FILE_NOT_FOUND, path));
            }

            if ((imageCodecs == null) || (!imageCodecs.Any()))
            {
                // If we don't specify any codecs, then use the built in ones.
                imageCodecs = new IGorgonImageCodec[]
                {
                    new GorgonCodecPng(),
                    new GorgonCodecBmp(),
                    new GorgonCodecDds(),
                    new GorgonCodecGif(),
                    new GorgonCodecJpeg(),
                    new GorgonCodecTga(),
                };
            }
            else
            {
                // Only use codecs that can decode image data.
                imageCodecs = imageCodecs.Where(item => item.CanDecode);
            }

            if ((animationCodecs == null) || (!animationCodecs.Any()))
            {
                // Use all built-in codecs if we haven't asked for any.
                animationCodecs = new IGorgonAnimationCodec[]
                {
                    new GorgonV3AnimationBinaryCodec(renderer),
                    new GorgonV3AnimationJsonCodec(renderer),
                    new GorgonV1AnimationCodec(renderer)
                };
            }
            else
            {
                // Only use codecs that can decode sprite data.
                animationCodecs = animationCodecs.Where(item => item.CanDecode);
            }

            Stream animStream = file.OpenStream();

            try
            {
                if (!animStream.CanSeek)
                {
                    Stream newStream = new DataStream((int)animStream.Length, true, true);
                    animStream.CopyTo(newStream);
                    newStream.Position = 0;

                    animStream.Dispose();
                    animStream = newStream;
                }

                IGorgonAnimationCodec animationCodec = GetAnimationCodec(animStream, animationCodecs);

                if (animationCodec == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOR2DIO_ERR_NO_SUITABLE_ANIM_CODEC_FOUND, path));
                }

                // Load the animation.
                IGorgonAnimation animation = animationCodec.FromStream(animStream, (int)file.Size);

                // We have no textures to update, leave.
                if (animation.Texture2DTrack.KeyFrames.Count == 0)
                {
                    return(animation);
                }

                // Try to locate the textures.

                // V1 sprite animations need texture coordinate correction.
                bool needsCoordinateFix = animationCodec is GorgonV1AnimationCodec;

                foreach (GorgonKeyTexture2D textureKey in animation.Texture2DTrack.KeyFrames)
                {
                    // Let's try and load the texture into memory.
                    // This does this by:
                    // 1. Checking to see if a texture resource with the name specified is already available in memory.
                    // 2. Checking the local directory of the file to see if the texture is there.
                    // 3. A file system wide search.

                    // ReSharper disable once InvertIf
                    (IGorgonImageCodec codec, IGorgonVirtualFile textureFile, bool loaded) =
                        LocateTextureCodecAndFile(fileSystem, file.Directory, renderer, textureKey.TextureName, imageCodecs);

                    // We have not loaded the texture yet.  Do so now.
                    // ReSharper disable once InvertIf
                    if ((!loaded) && (textureFile != null) && (codec != null))
                    {
                        using (Stream textureStream = textureFile.OpenStream())
                        {
                            textureKey.Value = GorgonTexture2DView.FromStream(renderer.Graphics,
                                                                              textureStream,
                                                                              codec,
                                                                              textureFile.Size, GetTextureOptions(textureFile.FullPath, textureOptions));
                        }
                    }

                    if ((needsCoordinateFix) && (textureKey.Value != null))
                    {
                        textureKey.TextureCoordinates = new RectangleF(textureKey.TextureCoordinates.X / textureKey.Value.Width,
                                                                       textureKey.TextureCoordinates.Y / textureKey.Value.Height,
                                                                       textureKey.TextureCoordinates.Width / textureKey.Value.Width,
                                                                       textureKey.TextureCoordinates.Height / textureKey.Value.Height);
                    }
                }

                return(animation);
            }
            finally
            {
                animStream?.Dispose();
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Function to load a <see cref="GorgonPolySprite"/> from a <see cref="GorgonFileSystem"/>.
        /// </summary>
        /// <param name="fileSystem">The file system to load the sprite from.</param>
        /// <param name="renderer">The renderer for the sprite.</param>
        /// <param name="path">The path to the sprite file in the file system.</param>
        /// <param name="textureOptions">[Optional] Options for the texture loaded associated the sprite.</param>
        /// <param name="spriteCodecs">The list of polygonal sprite codecs to try and load the sprite with.</param>
        /// <param name="imageCodecs">The list of image codecs to try and load the sprite texture with.</param>
        /// <returns>The sprite data in the file as a <see cref="GorgonSprite"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fileSystem"/>, <paramref name="renderer"/>, or <paramref name="path"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="path"/> parameter is empty.</exception>
        /// <exception cref="FileNotFoundException">Thrown if the file in the <paramref name="path"/> was not found.</exception>
        /// <exception cref="GorgonException">Thrown if the sprite data in the file system could not be loaded because a suitable codec was not found.</exception>
        /// <remarks>
        /// <para>
        /// This method extends a <see cref="GorgonFileSystem"/> so that sprites can be loaded by calling a method on the file system object itself. This negates the need for users to create complex code
        /// for loading a sprite.
        /// </para>
        /// <para>
        /// When loading a sprite, the method will attempt to locate the <see cref="GorgonTexture2DView"/> associated with the sprite (if it exists). When loading, it will check:
        /// <list type="number">
        ///     <item>
        ///         <description>For a texture resource with the same name that is already loaded into memory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Use the local <see cref="IGorgonVirtualDirectory"/> for the sprite file and search for the texture in that directory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Check the entire <paramref name="fileSystem"/> for a file if the texture name contains path information (this is done by the GorgonEditor from v2).</description>
        ///     </item>
        /// </list>
        /// If the file is found, and can be loaded by one of the <paramref name="imageCodecs"/>, then it is loaded and assigned to the sprite.
        /// </para>
        /// <para>
        /// The <paramref name="spriteCodecs"/> is a list of codecs for loading polygonal sprite data. If the user specifies this parameter, the only the codecs provided will be used for determining if a
        /// sprite can be read. If it is not supplied, then all built-in (i.e. not plug in based) sprite codecs will be used.
        /// </para>
        /// <para>
        /// The <paramref name="imageCodecs"/> is a list of codecs for loading image data. If the user specifies this parameter, the only the codecs provided will be used for determining if an image can be
        /// read. If it is not supplied, then all built-in (i.e. not plug in based) image codecs will be used.
        /// </para>
        /// </remarks>
        /// <seealso cref="GorgonFileSystem"/>
        /// <seealso cref="GorgonTexture2DView"/>
        /// <seealso cref="GorgonPolySprite"/>
        public static GorgonPolySprite LoadPolySpriteFromFileSystem(this GorgonFileSystem fileSystem,
                                                                    Gorgon2D renderer,
                                                                    string path,
                                                                    GorgonTexture2DLoadOptions textureOptions         = null,
                                                                    IEnumerable <IGorgonPolySpriteCodec> spriteCodecs = null,
                                                                    IEnumerable <IGorgonImageCodec> imageCodecs       = null)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }

            IGorgonVirtualFile file = fileSystem.GetFile(path);

            if (file == null)
            {
                throw new FileNotFoundException(string.Format(Resources.GOR2DIO_ERR_FILE_NOT_FOUND, path));
            }

            if ((imageCodecs == null) || (!imageCodecs.Any()))
            {
                // If we don't specify any codecs, then use the built in ones.
                imageCodecs = new IGorgonImageCodec[]
                {
                    new GorgonCodecPng(),
                    new GorgonCodecBmp(),
                    new GorgonCodecDds(),
                    new GorgonCodecGif(),
                    new GorgonCodecJpeg(),
                    new GorgonCodecTga(),
                };
            }
            else
            {
                // Only use codecs that can decode image data.
                imageCodecs = imageCodecs.Where(item => item.CanDecode);
            }

            if ((spriteCodecs == null) || (!spriteCodecs.Any()))
            {
                // Use all built-in codecs if we haven't asked for any.
                spriteCodecs = new IGorgonPolySpriteCodec[]
                {
                    new GorgonV3PolySpriteBinaryCodec(renderer),
                    new GorgonV3PolySpriteJsonCodec(renderer)
                };
            }
            else
            {
                // Only use codecs that can decode sprite data.
                spriteCodecs = spriteCodecs.Where(item => item.CanDecode);
            }

            Stream spriteStream = file.OpenStream();

            try
            {
                if (!spriteStream.CanSeek)
                {
                    Stream newStream = new DataStream((int)spriteStream.Length, true, true);
                    spriteStream.CopyTo(newStream);
                    newStream.Position = 0;
                    spriteStream.Dispose();
                    spriteStream = newStream;
                }

                IGorgonPolySpriteCodec spriteCodec = GetPolySpriteCodec(spriteStream, spriteCodecs);

                if (spriteCodec == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOR2DIO_ERR_NO_SUITABLE_SPRITE_CODEC_FOUND, path));
                }

                // Try to locate the texture.
                string textureName = spriteCodec.GetAssociatedTextureName(spriteStream);

                GorgonTexture2DView textureForSprite = null;

                // Let's try and load the texture into memory.
                // This does this by:
                // 1. Checking to see if a texture resource with the name specified is already available in memory.
                // 2. Checking the local directory of the file to see if the texture is there.
                // 3. A file system wide search.

                // ReSharper disable once InvertIf
                if (!string.IsNullOrWhiteSpace(textureName))
                {
                    (IGorgonImageCodec codec, IGorgonVirtualFile textureFile, bool loaded) =
                        LocateTextureCodecAndFile(fileSystem, file.Directory, renderer, textureName, imageCodecs);

                    // We have not loaded the texture yet.  Do so now.
                    // ReSharper disable once InvertIf
                    if ((!loaded) && (textureFile != null) && (codec != null))
                    {
                        using (Stream textureStream = textureFile.OpenStream())
                        {
                            textureForSprite = GorgonTexture2DView.FromStream(renderer.Graphics,
                                                                              textureStream,
                                                                              codec,
                                                                              textureFile.Size,
                                                                              GetTextureOptions(textureFile.FullPath, textureOptions));
                        }
                    }
                }

                return(spriteCodec.FromStream(spriteStream, textureForSprite, (int)file.Size));
            }
            finally
            {
                spriteStream?.Dispose();
            }
        }
Ejemplo n.º 20
0
 /// <summary>Initializes a new instance of the TexConvCompressor class.</summary>
 /// <param name="texConvFile">The tex conv file.</param>
 /// <param name="scratchWriter">The scratch writer.</param>
 /// <param name="codec">The codec used to read/write the file.</param>
 public TexConvCompressor(FileInfo texConvFile, IGorgonFileSystemWriter <Stream> scratchWriter, IGorgonImageCodec codec)
 {
     _codec   = codec;
     _writer  = scratchWriter;
     _texConv = texConvFile;
 }
Ejemplo n.º 21
0
        /// <summary>
        /// Function to load the image to be used a thumbnail.
        /// </summary>
        /// <param name="thumbnailCodec">The codec for the thumbnail images.</param>
        /// <param name="thumbnailFile">The path to the thumbnail file.</param>
        /// <param name="content">The content being thumbnailed.</param>
        /// <param name="fileManager">The file manager used to handle content files.</param>
        /// <param name="cancelToken">The token used to cancel the operation.</param>
        /// <returns>The image, image content file and sprite, or just the thumbnail image if it was cached (sprite will be null).</returns>
        private (IGorgonImage image, IContentFile imageFile, GorgonSprite sprite) LoadThumbnailImage(IGorgonImageCodec thumbnailCodec, FileInfo thumbnailFile, IContentFile content, IContentFileManager fileManager, CancellationToken cancelToken)
        {
            IGorgonImage spriteImage;
            Stream       inStream  = null;
            Stream       imgStream = null;

            try
            {
                // If we've already got the file, then leave.
                if (thumbnailFile.Exists)
                {
                    inStream    = thumbnailFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
                    spriteImage = thumbnailCodec.LoadFromStream(inStream);

#pragma warning disable IDE0046 // Convert to conditional expression
                    if (cancelToken.IsCancellationRequested)
                    {
                        return(null, null, null);
                    }
#pragma warning restore IDE0046 // Convert to conditional expression

                    return(spriteImage, null, null);
                }

                IContentFile imageFile = FindImage(content, fileManager);
                if (imageFile == null)
                {
                    return(_noImage.Clone(), null, null);
                }

                imgStream = imageFile.OpenRead();
                inStream  = content.OpenRead();

                if ((!_ddsCodec.IsReadable(imgStream)) ||
                    (!_defaultCodec.IsReadable(inStream)))
                {
                    return(_noImage.Clone(), null, null);
                }

                spriteImage = _ddsCodec.LoadFromStream(imgStream);
                GorgonSprite sprite = _defaultCodec.FromStream(inStream);

                return(spriteImage, imageFile, sprite);
            }
            catch (Exception ex)
            {
                CommonServices.Log.Print($"[ERROR] Cannot create thumbnail for '{content.Path}'", LoggingLevel.Intermediate);
                CommonServices.Log.LogException(ex);
                return(null, null, null);
            }
            finally
            {
                imgStream?.Dispose();
                inStream?.Dispose();
            }
        }
Ejemplo n.º 22
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="GorgonTexture2DView"/></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="GorgonTexture2D"/> object and return a <see cref="GorgonTexture2DView"/>.
        /// </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>
        ///		<item>
        ///		    <term>ConvertToPremultipliedAlpha</term>
        ///		    <description>Converts the image to premultiplied alpha before uploading the image data to the texture.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// <para>
        /// Since the <see cref="GorgonTexture2D"/> created by this method is linked to the <see cref="GorgonTexture2DView"/> returned, disposal of either one will dispose of the other on your behalf. If
        /// the user created a <see cref="GorgonTexture2DView"/> from the <see cref="GorgonTexture2D.GetShaderResourceView"/> method on the <see cref="GorgonTexture2D"/>, 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 GorgonTexture2DView FromFile(GorgonGraphics graphics, string filePath, IGorgonImageCodec codec, GorgonTexture2DLoadOptions 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))
            {
                if (options == null)
                {
                    options = new GorgonTexture2DLoadOptions
                    {
                        Name          = Path.GetFileNameWithoutExtension(filePath),
                        Usage         = ResourceUsage.Default,
                        Binding       = TextureBinding.ShaderResource,
                        IsTextureCube = image.ImageType == ImageType.ImageCube
                    };
                }
                GorgonTexture2D     texture = image.ToTexture2D(graphics, options);
                GorgonTexture2DView view    = texture.GetShaderResourceView();
                view.OwnsResource = true;
                return(view);
            }
        }
Ejemplo n.º 23
0
 /// <summary>Initializes a new instance of the <see cref="T:Gorgon.Editor.ImageEditor.Services.DdsImageImporter"/> class.</summary>
 /// <param name="log">The log used for logging debug messages.</param>
 public DdsImageImporter(FileInfo sourceFile, IGorgonImageCodec codec, IGorgonLog log)
 {
     _log       = log ?? GorgonLog.NullLog;
     SourceFile = sourceFile;
     _codec     = codec;
 }
Ejemplo n.º 24
0
        /// <summary>
        /// Function to load the image to be used a thumbnail.
        /// </summary>
        /// <param name="thumbnailCodec">The codec for the thumbnail images.</param>
        /// <param name="thumbnailFile">The path to the thumbnail file.</param>
        /// <param name="content">The content being thumbnailed.</param>
        /// <param name="cancelToken">The token used to cancel the operation.</param>
        /// <returns>The thumbnail image, and a flag to indicate whether the thumbnail needs conversion.</returns>
        private (IGorgonImage thumbnailImage, bool needsConversion) LoadThumbNailImage(IGorgonImageCodec thumbnailCodec, FileInfo thumbnailFile, IContentFile content, CancellationToken cancelToken)
        {
            IGorgonImage result;
            Stream       inStream = null;

            try
            {
                // If we've already got the file, then leave.
                if (thumbnailFile.Exists)
                {
                    inStream = thumbnailFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
                    result   = thumbnailCodec.LoadFromStream(inStream);

                    return(cancelToken.IsCancellationRequested ? (null, false) : (result, false));
                }

                inStream = content.OpenRead();
                result   = _ddsCodec.LoadFromStream(inStream);

                return(result, true);
            }
            catch (Exception ex)
            {
                CommonServices.Log.Print($"[ERROR] Cannot create thumbnail for '{content.Path}'", LoggingLevel.Intermediate);
                CommonServices.Log.LogException(ex);
                return(null, false);
            }
            finally
            {
                inStream?.Dispose();
            }
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Function to import an image file from the physical file system into the current image.
        /// </summary>
        /// <param name="codec">The codec used to open the file.</param>
        /// <param name="filePath">The path to the file to import.</param>
        /// <returns>The source file information, image data, the virtual file entry for the working file and the original pixel format of the file.</returns>
        public (FileInfo file, IGorgonImage image, IGorgonVirtualFile workingFile, BufferFormat originalFormat) ImportImage(IGorgonImageCodec codec, string filePath)
        {
            var file = new FileInfo(filePath);
            IGorgonImageCodec  importCodec  = codec;
            IGorgonImageInfo   metaData     = null;
            IGorgonVirtualFile workFile     = null;
            IGorgonImage       importImage  = null;
            string             workFilePath = $"{Path.GetFileNameWithoutExtension(filePath)}_import_{Guid.NewGuid().ToString("N")}";

            // Try to determine if we can actually read the file using an installed codec, if we can't, then try to find a suitable codec.
            using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                if ((importCodec == null) || (!importCodec.IsReadable(stream)))
                {
                    importCodec = null;

                    foreach (IGorgonImageCodec newCodec in InstalledCodecs.Codecs.Where(item => (item.CodecCommonExtensions.Count > 0) && (item.CanDecode)))
                    {
                        if (newCodec.IsReadable(stream))
                        {
                            importCodec = newCodec;
                            break;
                        }
                    }
                }

                if (importCodec == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GORIMG_ERR_NO_CODEC, filePath));
                }

                metaData = importCodec.GetMetaData(stream);


                // We absolutely need to have an extension, or else the texconv tool will not work.
                var codecExtension = new GorgonFileExtension(importCodec.CodecCommonExtensions[0]);
                _log.Print($"Adding {codecExtension.Extension} extension to working file or else external tools may not be able to read it.", LoggingLevel.Verbose);
                workFilePath = $"{workFilePath}.{codecExtension.Extension}";

                using (Stream outStream = ScratchArea.OpenStream(workFilePath, FileMode.Create))
                {
                    stream.CopyTo(outStream);
                }
            }

            workFile = ScratchArea.FileSystem.GetFile(workFilePath);
            var formatInfo = new GorgonFormatInfo(metaData.Format);

            // This is always in DDS format.
            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);
                importImage = _compressor.Decompress(ref workFile, metaData);

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

                _log.Print($"Loaded compressed ([{formatInfo.Format}]) image data as [{importImage.Format}]", LoggingLevel.Intermediate);
            }
            else
            {
                using (Stream workStream = workFile.OpenStream())
                {
                    importImage = importCodec.LoadFromStream(workStream);
                }
            }

            return(file, importImage, workFile, metaData.Format);
        }
Ejemplo n.º 26
0
        /// <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);
        }