Пример #1
0
 /// <summary>Initializes a new instance of the <see cref="ExtractorService"/> class.</summary>
 /// <param name="renderer">The application 2D renderer.</param>
 /// <param name="fileManager">The file manager for the project files.</param>
 /// <param name="defaultCodec">The default sprite codec.</param>
 public ExtractorService(Gorgon2D renderer, IContentFileManager fileManager, IGorgonSpriteCodec defaultCodec)
 {
     _renderer     = renderer;
     _graphics     = renderer.Graphics;
     _fileManager  = fileManager;
     _defaultCodec = defaultCodec;
 }
 /// <summary>Initializes a new instance of the <see cref="T:Gorgon.Editor.ViewModels.ContentPreviewVmParameters"/> class.</summary>
 /// <param name="fileExplorer">The file explorer view model.</param>
 /// <param name="contentFileManager">The file manager used for content files.</param>
 /// <param name="thumbDirectory">The thumbnail directory for the previewer.</param>
 /// <param name="viewModelFactory">The view model factory for creating view models.</param>
 /// <exception cref="ArgumentNullException">Thrown when any of the parameters are <b>null</b>.</exception>
 public ContentPreviewVmParameters(IFileExplorerVm fileExplorer, IContentFileManager contentFileManager, DirectoryInfo thumbDirectory, ViewModelFactory viewModelFactory)
     : base(viewModelFactory)
 {
     FileExplorer       = fileExplorer ?? throw new ArgumentNullException(nameof(fileExplorer));
     ContentFileManager = contentFileManager ?? throw new ArgumentNullException(nameof(contentFileManager));
     ThumbDirectory     = thumbDirectory ?? throw new ArgumentNullException(nameof(thumbDirectory));
 }
Пример #3
0
        /// <summary>Function to determine if the content plugin can open the specified file.</summary>
        /// <param name="file">The content file to evaluate.</param>
        /// <param name="fileManager">The content file manager.</param>
        /// <returns>
        ///   <b>true</b> if the plugin can open the file, or <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="file" />, or the <paramref name="fileManager"/> parameter is <b>null</b>.</exception>
        public bool CanOpenContent(IContentFile file, IContentFileManager fileManager)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

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

            using (Stream stream = file.OpenRead())
            {
                if (!_ddsCodec.IsReadable(stream))
                {
                    return(false);
                }

                IGorgonImageInfo metadata = _ddsCodec.GetMetaData(stream);

                // We won't be supporting 1D images in this editor.
                if ((metadata.ImageType == ImageType.Image1D) || (metadata.ImageType == ImageType.Unknown))
                {
                    return(false);
                }

                UpdateFileMetadataAttributes(file.Metadata.Attributes);
                return(true);
            }
        }
Пример #4
0
        /// <summary>
        /// Function to find the image associated with the sprite file.
        /// </summary>
        /// <param name="spriteFile">The sprite file to evaluate.</param>
        /// <param name="fileManager">The file manager used to handle content files.</param>
        /// <returns>The file representing the image associated with the sprite.</returns>
        private IContentFile FindImage(IContentFile spriteFile, IContentFileManager fileManager)
        {
            if ((spriteFile.Metadata.DependsOn.Count == 0) ||
                (!spriteFile.Metadata.DependsOn.TryGetValue(CommonEditorContentTypes.ImageType, out string texturePath)))
            {
                return(null);
            }

            IContentFile textureFile = fileManager.GetFile(texturePath);

            if (textureFile == null)
            {
                CommonServices.Log.Print($"[ERROR] Sprite '{spriteFile.Path}' has texture '{texturePath}', but the file was not found on the file system.", LoggingLevel.Verbose);
                return(null);
            }

            string textureFileContentType = textureFile.Metadata.ContentMetadata?.ContentTypeID;

            if (string.IsNullOrWhiteSpace(textureFileContentType))
            {
                CommonServices.Log.Print($"[ERROR] Sprite texture '{texturePath}' was found but has no content type ID.", LoggingLevel.Verbose);
                return(null);
            }

            if ((!textureFile.Metadata.Attributes.TryGetValue(CommonEditorConstants.ContentTypeAttr, out string imageType)) ||
                (!string.Equals(imageType, textureFileContentType, StringComparison.OrdinalIgnoreCase)))
            {
                CommonServices.Log.Print($"[ERROR] Sprite '{spriteFile.Path}' has texture '{texturePath}', but the texture has a content type ID of '{textureFileContentType}', and the sprite requires a content type ID of '{imageType}'.", LoggingLevel.Verbose);
                return(null);
            }

            return(textureFile);
        }
Пример #5
0
        /// <summary>Function to retrieve the ribbon button for the tool.</summary>
        /// <param name="fileManager">The project file manager.</param>
        /// <param name="scratchArea">The scratch area for writing temporary data.</param>
        /// <returns>A new tool ribbon button instance.</returns>
        /// <remarks>
        ///   <para>
        /// Tool plug in developers must override this method to return the button which is inserted on the application ribbon, under the "Tools" tab. If the method returns <b>null</b>, then the tool is
        /// ignored.
        /// </para>
        ///   <para>
        /// The resulting data structure will contain the means to handle the click event for the tool, and as such, is the only means of communication between the main UI and the plug in.
        /// </para>
        ///   <para>
        /// The <paramref name="fileManager" /> will allow plug ins to enumerate files in the project file system, create files/directories, and delete files/directories. This allows the plug in a means
        /// to persist any data generated.
        /// </para>
        ///   <para>
        /// The <paramref name="scratchArea" /> is used to write temporary data to the project temporary area, which is useful for handling transitory states. Because this is <b>temporary</b>, any data
        /// written to this area will be deleted on application shut down. So do not rely on this data being there on the next start up.
        /// </para>
        /// </remarks>
        protected override IToolPlugInRibbonButton OnGetToolButton(IContentFileManager fileManager, IGorgonFileSystemWriter <Stream> scratchArea)
        {
            _fileManager = fileManager;

            if (_button.ClickCallback == null)
            {
                _button.ClickCallback = ShowForm;
            }

            return(_button);
        }
Пример #6
0
        /// <summary>Function to provide clean up for the plugin.</summary>
        protected override void OnShutdown()
        {
            _fileManager = null;

            // Disconnect from the button to ensure that we don't get this thing keeping us around longer than we should.
            if (_button != null)
            {
                _button.CanExecute    = null;
                _button.ClickCallback = null;
                _button.Dispose();
            }

            base.OnShutdown();
        }
Пример #7
0
        /// <summary>
        /// Function to retrieve the ribbon button for the tool.
        /// </summary>
        /// <param name="project">The project data.</param>
        /// <param name="fileManager">The project file manager.</param>
        /// <returns>A new tool ribbon button instance.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="project"/>, or the <paramref name="fileManager"/> parameter is <b>null</b>.</exception>
        /// <remarks>
        /// <para>
        /// This will return data to describe a new button for the tool in the plug in. If the return value is <b>null</b>, then the tool will not be available on the ribbon.
        /// </para>
        /// </remarks>
        public IToolPlugInRibbonButton GetToolButton(IProject project, IContentFileManager fileManager)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

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

            IGorgonFileSystemWriter <Stream> scratchWriter = GetScratchArea(project.TempDirectory);

            return(OnGetToolButton(fileManager, scratchWriter));
        }
 /// <summary>Initializes a new instance of the <see cref="T:Gorgon.Editor.SpriteEditor.SpriteContentParameters"/> class.</summary>
 /// <param name="factory">The factory for building sprite content data.</param>
 /// <param name="spriteFile">The sprite file.</param>
 /// <param name="spriteTextureFile">The sprite texture file.</param>
 /// <param name="fileManager">The file manager used to access external content.</param>
 /// <param name="textureService">The texture service to use when reading sprite texture data.</param>
 /// <param name="sprite">The sprite being edited.</param>
 /// <param name="codec">The codec to use when reading/writing sprite data.</param>
 /// <param name="manualRectEdit">The manual rectangle editor view model.</param>
 /// <param name="manualVertexEdit">The manual vertex editor view model.</param>
 /// <param name="spritePickMaskEditor">The sprite picker mask color editor.</param>
 /// <param name="colorEditor">The color editor for the sprite.</param>
 /// <param name="anchorEditor">The anchor editor for the sprite.</param>
 /// <param name="wrapEditor">The texture wrapping state editor for the sprite.</param>
 /// <param name="settings">The plug in settings view model.</param>
 /// <param name="undoService">The undo service.</param>
 /// <param name="scratchArea">The file system used to write out temporary working data.</param>
 /// <param name="commonServices">Common application services.</param>
 public SpriteContentParameters(
     ISpriteContentFactory factory,
     IContentFile spriteFile,
     IContentFile spriteTextureFile,
     IContentFileManager fileManager,
     ISpriteTextureService textureService,
     GorgonSprite sprite,
     IGorgonSpriteCodec codec,
     IManualRectangleEditor manualRectEdit,
     IManualVertexEditor manualVertexEdit,
     ISpritePickMaskEditor spritePickMaskEditor,
     ISpriteColorEdit colorEditor,
     ISpriteAnchorEdit anchorEditor,
     ISpriteWrappingEditor wrapEditor,
     ISamplerBuildService samplerBuilder,
     IEditorPlugInSettings settings,
     IUndoService undoService,
     IGorgonFileSystemWriter <Stream> scratchArea,
     IViewModelInjection commonServices)
     : base(spriteFile, commonServices)
 {
     Factory               = factory ?? throw new ArgumentNullException(nameof(factory));
     Sprite                = sprite ?? throw new ArgumentNullException(nameof(sprite));
     UndoService           = undoService ?? throw new ArgumentNullException(nameof(undoService));
     ContentFileManager    = fileManager ?? throw new ArgumentNullException(nameof(fileManager));
     ScratchArea           = scratchArea ?? throw new ArgumentNullException(nameof(scratchArea));
     TextureService        = textureService ?? throw new ArgumentNullException(nameof(textureService));
     SpriteCodec           = codec ?? throw new ArgumentNullException(nameof(codec));
     ManualRectangleEditor = manualRectEdit ?? throw new ArgumentNullException(nameof(manualRectEdit));
     ManualVertexEditor    = manualVertexEdit ?? throw new ArgumentNullException(nameof(manualVertexEdit));
     SpritePickMaskEditor  = spritePickMaskEditor ?? throw new ArgumentNullException(nameof(spritePickMaskEditor));
     Settings              = settings ?? throw new ArgumentNullException(nameof(settings));
     ColorEditor           = colorEditor ?? throw new ArgumentNullException(nameof(colorEditor));
     AnchorEditor          = anchorEditor ?? throw new ArgumentNullException(nameof(anchorEditor));
     SpriteWrappingEditor  = wrapEditor ?? throw new ArgumentNullException(nameof(wrapEditor));
     SamplerBuilder        = samplerBuilder ?? throw new ArgumentNullException(nameof(samplerBuilder));
     SpriteTextureFile     = spriteTextureFile;
 }
Пример #9
0
        /// <summary>Function to determine if the content plugin can open the specified file.</summary>
        /// <param name="file">The content file to evaluate.</param>
        /// <param name="fileManager">The content file manager.</param>
        /// <returns>
        ///   <b>true</b> if the plugin can open the file, or <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="file" />, or the <paramref name="fileManager" /> parameter is <b>null</b>.</exception>
        public bool CanOpenContent(IContentFile file, IContentFileManager fileManager)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

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

            using (Stream stream = file.OpenRead())
            {
                if (_defaultCodec.IsReadable(stream))
                {
                    UpdateFileMetadataAttributes(file.Metadata.Attributes);
                    UpdateDependencies(stream, file.Metadata.DependsOn, fileManager);
                    return(true);
                }

                return(false);
            }
        }
Пример #10
0
        /// <summary>Function to open a content object from this plugin.</summary>
        /// <param name="file">The file that contains the content.</param>
        /// <param name = "fileManager" > The file manager used to access other content files.</param>
        /// <param name="scratchArea">The file system for the scratch area used to write transitory information.</param>
        /// <param name="undoService">The undo service for the plug in.</param>
        /// <returns>A new IEditorContent object.</returns>
        /// <remarks>
        /// The <paramref name="scratchArea" /> parameter is the file system where temporary files to store transitory information for the plug in is stored. This file system is destroyed when the
        /// application or plug in is shut down, and is not stored with the project.
        /// </remarks>
        protected async override Task <IEditorContent> OnOpenContentAsync(IContentFile file, IContentFileManager fileManager, IGorgonFileSystemWriter <Stream> scratchArea, IUndoService undoService)
        {
            var content = new SpriteContent();
            GorgonTexture2DView   spriteImage = null;
            IContentFile          imageFile;
            GorgonSprite          sprite;
            ISpriteTextureService textureService;
            Stream stream = null;

            try
            {
                textureService = new SpriteTextureService(GraphicsContext, fileManager, _ddsCodec);

                // Load the sprite image.
                (spriteImage, imageFile) = await textureService.LoadFromSpriteContentAsync(file);

                // Load the sprite now.
                stream = file.OpenRead();
                sprite = _defaultCodec.FromStream(stream, spriteImage);

                var settings = new EditorPlugInSettings();
                ISpritePickMaskEditor spritePickMaskEditor = settings;
                settings.Initialize(new SettingsParameters(_settings, CommonServices));

                var manualRectEdit = new ManualRectangleEditor();
                manualRectEdit.Initialize(new ManualInputParameters(settings, CommonServices));

                var manualVertexEdit = new ManualVertexEditor();
                manualVertexEdit.Initialize(new ManualInputParameters(settings, CommonServices));

                var colorEditor = new SpriteColorEdit();
                colorEditor.Initialize(CommonServices);

                var anchorEditor = new SpriteAnchorEdit();
                anchorEditor.Initialize(CommonServices);

                var samplerBuilder = new SamplerBuildService(new GorgonSamplerStateBuilder(GraphicsContext.Graphics));

                var wrapEditor = new SpriteWrappingEditor();
                wrapEditor.Initialize(new SpriteWrappingEditorParameters(samplerBuilder, CommonServices));

                content.Initialize(new SpriteContentParameters(this,
                                                               file,
                                                               imageFile,
                                                               fileManager,
                                                               textureService,
                                                               sprite,
                                                               _defaultCodec,
                                                               manualRectEdit,
                                                               manualVertexEdit,
                                                               spritePickMaskEditor,
                                                               colorEditor,
                                                               anchorEditor,
                                                               wrapEditor,
                                                               samplerBuilder,
                                                               settings,
                                                               undoService,
                                                               scratchArea,
                                                               CommonServices));

                // If we have a texture, then read its data into RAM.
                if (sprite.Texture != null)
                {
                    await content.ExtractImageDataAsync();
                }

                return(content);
            }
            catch
            {
                spriteImage?.Dispose();
                throw;
            }
            finally
            {
                stream?.Dispose();
            }
        }
Пример #11
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();
            }
        }
Пример #12
0
        /// <summary>
        /// Function to update the dependencies for the sprite.
        /// </summary>
        /// <param name="fileStream">The stream for the file.</param>
        /// <param name="dependencyList">The list of dependency file paths.</param>
        /// <param name="fileManager">The content file management system.</param>
        private void UpdateDependencies(Stream fileStream, Dictionary <string, string> dependencyList, IContentFileManager fileManager)
        {
            string textureName = _defaultCodec.GetAssociatedTextureName(fileStream);

            if (string.IsNullOrWhiteSpace(textureName))
            {
                return;
            }
            IContentFile textureFile = fileManager.GetFile(textureName);

            // If we lack the texture (e.g. it's been deleted or something), then reset the value from the metadata.
            if (textureFile == null)
            {
                dependencyList.Remove(textureName);
                return;
            }

            dependencyList[CommonEditorContentTypes.ImageType] = textureName;
        }
Пример #13
0
        /// <summary>
        /// Function to perform the scan used to determine whether a content file has an associated plugin or not.
        /// </summary>
        /// <param name="node">The node to scan.</param>
        /// <param name="contentFileManager">The file manager used to manage content file data.</param>
        /// <param name="scanProgress">The callback method used to report progress of the scan.</param>
        /// <param name="deepScan"><b>true</b> to perform a more time consuming scan, or <b>false</b> to just scan by file name extension.</param>
        /// <param name="forceScan">[Optional] <b>true</b> to force the scan, even if content metadata is already available, or <b>false</b> to skip files with content metadata already.</param>
        /// <returns><b>true</b> if the content plugin metadata was updated, <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="node"/>, <paramref name="contentFileManager"/> or the <paramref name="scanProgress"/> parameter is <b>null</b>.</exception>
        public bool Scan(IFileExplorerNodeVm node, IContentFileManager contentFileManager, Action <string, int, int> scanProgress, bool deepScan, bool forceScan = false)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

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

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

            IEnumerable <IFileExplorerNodeVm> contentFiles;
            int fileCount;

            if (node.Children.Count > 0)
            {
                contentFiles = node.Children.Traverse(n => n.Children)
                               .Where(n => ((n.Metadata != null) && (n.IsContent) && ((forceScan) || (n.Metadata.ContentMetadata == null))));
                fileCount = contentFiles.Count();
            }
            else
            {
                contentFiles = new IFileExplorerNodeVm[] { node };
                fileCount    = 1;
            }

            if (fileCount == 0)
            {
                return(false);
            }

            bool result   = false;
            int  count    = 0;
            var  prevDeps = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            foreach (IContentFile contentFile in contentFiles.OfType <IContentFile>())
            {
                string pluginName = contentFile.Metadata.PlugInName;

                if (forceScan)
                {
                    contentFile.Metadata.ContentMetadata = null;
                    contentFile.Metadata.DependsOn.Clear();
                }

                prevDeps.Clear();
                foreach (KeyValuePair <string, string> dep in contentFile.Metadata.DependsOn)
                {
                    prevDeps[dep.Key] = dep.Value;
                }

                if (_contentPlugIns.AssignContentPlugIn(contentFile, contentFileManager, !deepScan))
                {
                    if ((!string.Equals(pluginName, contentFile.Metadata.PlugInName, StringComparison.OrdinalIgnoreCase)) ||
                        (!CompareDependencyLists(contentFile.Metadata.DependsOn, prevDeps)))
                    {
                        result = true;
                    }
                }

                scanProgress.Invoke(contentFile.Path, ++count, fileCount);
            }

            return(result);
        }
Пример #14
0
        /// <summary>Function to retrieve a thumbnail for the content.</summary>
        /// <param name="contentFile">The content file used to retrieve the data to build the thumbnail with.</param>
        /// <param name="fileManager">The content file manager.</param>
        /// <param name="outputFile">The output file for the thumbnail data.</param>
        /// <param name="cancelToken">The token used to cancel the thumbnail generation.</param>
        /// <returns>A <see cref="T:Gorgon.Graphics.Imaging.IGorgonImage"/> containing the thumbnail image data.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="contentFile" />, <paramref name="fileManager" />, or the <paramref name="outputFile" /> parameter is <b>null</b>.</exception>
        public async Task <IGorgonImage> GetThumbnailAsync(IContentFile contentFile, IContentFileManager fileManager, FileInfo outputFile, CancellationToken cancelToken)
        {
            if (contentFile == null)
            {
                throw new ArgumentNullException(nameof(contentFile));
            }

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

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

            // If the content is not a DDS image, then leave it.
            if ((!contentFile.Metadata.Attributes.TryGetValue(ImageContent.CodecAttr, out string codecName)) ||
                (string.IsNullOrWhiteSpace(codecName)) ||
                (!string.Equals(codecName, _ddsCodec.GetType().FullName, StringComparison.OrdinalIgnoreCase)))
            {
                return(null);
            }

            if (!outputFile.Directory.Exists)
            {
                outputFile.Directory.Create();
                outputFile.Directory.Refresh();
            }

            IGorgonImageCodec pngCodec = new GorgonCodecPng();

            (IGorgonImage thumbImage, bool needsConversion) = await Task.Run(() => LoadThumbNailImage(pngCodec, outputFile, contentFile, cancelToken));

            if ((thumbImage == null) || (cancelToken.IsCancellationRequested))
            {
                return(null);
            }

            if (!needsConversion)
            {
                return(thumbImage);
            }

            // We need to switch back to the main thread here to render the image, otherwise things will break.
            Cursor.Current = Cursors.WaitCursor;

            try
            {
                const float maxSize = 256;
                float       scale   = (maxSize / thumbImage.Width).Min(maxSize / thumbImage.Height);
                RenderThumbnail(ref thumbImage, scale);

                if (cancelToken.IsCancellationRequested)
                {
                    return(null);
                }

                // We're done on the main thread, we can switch to another thread to write the image.
                Cursor.Current = Cursors.Default;

                await Task.Run(() => pngCodec.SaveToFile(thumbImage, outputFile.FullName), cancelToken);

                if (cancelToken.IsCancellationRequested)
                {
                    return(null);
                }

                contentFile.Metadata.Attributes[CommonEditorConstants.ThumbnailAttr] = outputFile.Name;
                return(thumbImage);
            }
            catch (Exception ex)
            {
                CommonServices.Log.Print($"[ERROR] Cannot create thumbnail for '{contentFile.Path}'", LoggingLevel.Intermediate);
                CommonServices.Log.LogException(ex);
                return(null);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }
Пример #15
0
 /// <summary>
 /// Function to retrieve the ribbon button for the tool.
 /// </summary>
 /// <param name="fileManager">The project file manager.</param>
 /// <param name="scratchArea">The scratch area for writing temporary data.</param>
 /// <returns>A new tool ribbon button instance.</returns>
 /// <remarks>
 /// <para>
 /// Tool plug in developers must override this method to return the button which is inserted on the application ribbon, under the "Tools" tab. If the method returns <b>null</b>, then the tool is
 /// ignored.
 /// </para>
 /// <para>
 /// The resulting data structure will contain the means to handle the click event for the tool, and as such, is the only means of communication between the main UI and the plug in.
 /// </para>
 /// <para>
 /// The <paramref name="fileManager"/> will allow plug ins to enumerate files in the project file system, create files/directories, and delete files/directories. This allows the plug in a means
 /// to persist any data generated.
 /// </para>
 /// <para>
 /// The <paramref name="scratchArea"/> is used to write temporary data to the project temporary area, which is useful for handling transitory states. Because this is <b>temporary</b>, any data
 /// written to this area will be deleted on application shut down. So do not rely on this data being there on the next start up.
 /// </para>
 /// </remarks>
 protected abstract IToolPlugInRibbonButton OnGetToolButton(IContentFileManager fileManager, IGorgonFileSystemWriter <Stream> scratchArea);
Пример #16
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;
 }
Пример #17
0
 /// <summary>
 /// Function to open a content object from this plugin.
 /// </summary>
 /// <param name="file">The file that contains the content.</param>
 /// <param name="fileManager">The file manager used to access other content files.</param>
 /// <param name="scratchArea">The file system for the scratch area used to write transitory information.</param>
 /// <param name="undoService">The undo service for the plug in.</param>
 /// <returns>A new <see cref="IEditorContent"/> object.</returns>
 /// <remarks>
 /// <para>
 /// The <paramref name="scratchArea"/> parameter is the file system where temporary files to store transitory information for the plug in is stored. This file system is destroyed when the
 /// application or plug in is shut down, and is not stored with the project.
 /// </para>
 /// </remarks>
 protected abstract Task <IEditorContent> OnOpenContentAsync(IContentFile file, IContentFileManager fileManager, IGorgonFileSystemWriter <Stream> scratchArea, IUndoService undoService);
Пример #18
0
        /// <summary>Function to retrieve a thumbnail for the content.</summary>
        /// <param name="contentFile">The content file used to retrieve the data to build the thumbnail with.</param>
        /// <param name="fileManager">The content file manager.</param>
        /// <param name="outputFile">The output file for the thumbnail data.</param>
        /// <param name="cancelToken">The token used to cancel the thumbnail generation.</param>
        /// <returns>A <see cref="T:Gorgon.Graphics.Imaging.IGorgonImage"/> containing the thumbnail image data.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="contentFile" />, <paramref name="fileManager" /> or the <paramref name="outputFile" /> parameter is <b>null</b>.</exception>
        public async Task <IGorgonImage> GetThumbnailAsync(IContentFile contentFile, IContentFileManager fileManager, FileInfo outputFile, CancellationToken cancelToken)
        {
            if (contentFile == null)
            {
                throw new ArgumentNullException(nameof(contentFile));
            }

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

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

            // If the content is not a v3 sprite, then leave it.
            if ((!contentFile.Metadata.Attributes.TryGetValue(SpriteContent.CodecAttr, out string codecName)) ||
                (string.IsNullOrWhiteSpace(codecName)) ||
                (!string.Equals(codecName, _defaultCodec.GetType().FullName, StringComparison.OrdinalIgnoreCase)))
            {
                return(null);
            }

            if (!outputFile.Directory.Exists)
            {
                outputFile.Directory.Create();
                outputFile.Directory.Refresh();
            }

            IGorgonImageCodec pngCodec = new GorgonCodecPng();

            (IGorgonImage image, IContentFile imageFile, GorgonSprite sprite) = await Task.Run(() => LoadThumbnailImage(pngCodec, outputFile, contentFile, fileManager, cancelToken));

            if ((image == null) || (cancelToken.IsCancellationRequested))
            {
                return(null);
            }

            // We loaded a cached thumbnail.
            if ((sprite == null) || (imageFile == null))
            {
                return(image);
            }

            // We need to switch back to the main thread here to render the image, otherwise things will break.
            Cursor.Current = Cursors.WaitCursor;

            GorgonTexture2DView spriteTexture = null;
            IGorgonImage        resultImage   = null;

            try
            {
                spriteTexture = GorgonTexture2DView.CreateTexture(GraphicsContext.Graphics, new GorgonTexture2DInfo(imageFile.Path)
                {
                    Width   = image.Width,
                    Height  = image.Height,
                    Format  = image.Format,
                    Binding = TextureBinding.ShaderResource,
                    Usage   = ResourceUsage.Default
                }, image);
                sprite.Texture = spriteTexture;

                resultImage = RenderThumbnail(sprite);

                await Task.Run(() => pngCodec.SaveToFile(resultImage, outputFile.FullName), cancelToken);

                if (cancelToken.IsCancellationRequested)
                {
                    return(null);
                }

                contentFile.Metadata.Attributes[CommonEditorConstants.ThumbnailAttr] = outputFile.Name;
                return(resultImage);
            }
            catch (Exception ex)
            {
                CommonServices.Log.Print($"[ERROR] Cannot create thumbnail for '{contentFile.Path}'", LoggingLevel.Intermediate);
                CommonServices.Log.LogException(ex);
                return(null);
            }
            finally
            {
                image?.Dispose();
                spriteTexture?.Dispose();
                Cursor.Current = Cursors.Default;
            }
        }
Пример #19
0
        /// <summary>Function to open a content object from this plugin.</summary>
        /// <param name="file">The file that contains the content.</param>
        /// <param name = "fileManager" > The file manager used to access other content files.</param>
        /// <param name="injector">Parameters for injecting dependency objects.</param>
        /// <param name="scratchArea">The file system for the scratch area used to write transitory information.</param>
        /// <param name="undoService">The undo service for the plug in.</param>
        /// <returns>A new IEditorContent object.</returns>
        /// <remarks>
        /// The <paramref name="scratchArea" /> parameter is the file system where temporary files to store transitory information for the plug in is stored. This file system is destroyed when the
        /// application or plug in is shut down, and is not stored with the project.
        /// </remarks>
        protected async override Task <IEditorContent> OnOpenContentAsync(IContentFile file, IContentFileManager fileManager, IGorgonFileSystemWriter <Stream> scratchArea, IUndoService undoService)
        {
            FileInfo          texConvExe = GetTexConvExe();
            TexConvCompressor compressor = null;

            if (texConvExe.Exists)
            {
                compressor = new TexConvCompressor(texConvExe, scratchArea, _ddsCodec);
            }

            var imageIO = new ImageIOService(_ddsCodec,
                                             _codecs,
                                             new ExportImageDialogService(_settings),
                                             new ImportImageDialogService(_settings, _codecs),
                                             CommonServices.BusyService,
                                             scratchArea,
                                             compressor,
                                             CommonServices.Log);

            (IGorgonImage image, IGorgonVirtualFile workingFile, BufferFormat originalFormat)imageData = await Task.Run(() =>
            {
                using (Stream inStream = file.OpenRead())
                {
                    return(imageIO.LoadImageFile(inStream, file.Name));
                }
            });

            var services = new ImageEditorServices
            {
                CommonServices        = CommonServices,
                ImageIO               = imageIO,
                UndoService           = undoService,
                ImageUpdater          = new ImageUpdaterService(),
                ExternalEditorService = new ImageExternalEditService(CommonServices.Log)
            };

            var cropResizeSettings = new CropResizeSettings();
            var dimensionSettings  = new DimensionSettings();
            var mipSettings        = new MipMapSettings();
            var alphaSettings      = new AlphaSettings
            {
                AlphaValue  = _settings.LastAlphaValue,
                UpdateRange = _settings.LastAlphaRange
            };

            cropResizeSettings.Initialize(CommonServices);
            dimensionSettings.Initialize(new DimensionSettingsParameters(GraphicsContext.Graphics.VideoAdapter, CommonServices));
            mipSettings.Initialize(CommonServices);


            var content = new ImageContent();

            content.Initialize(new ImageContentParameters(file,
                                                          _settings,
                                                          cropResizeSettings,
                                                          dimensionSettings,
                                                          mipSettings,
                                                          alphaSettings,
                                                          imageData,
                                                          GraphicsContext.Graphics.VideoAdapter,
                                                          GraphicsContext.Graphics.FormatSupport,
                                                          services));

            return(content);
        }