/// <summary> /// Handles the Click event of the ButtonImagePath control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void ButtonImagePath_Click(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; IGorgonImage image = null; var png = new GorgonCodecPng(); try { if (DialogOpenPng.ShowDialog(this) != DialogResult.OK) { return; } TextImagePath.Text = DialogOpenPng.FileName; _sourceTexture?.Texture?.Dispose(); _outputTexture?.Dispose(); _sourceTexture = null; _outputTexture = null; image = png.LoadFromFile(DialogOpenPng.FileName); _sourceTexture = image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm) .ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = Path.GetFileNameWithoutExtension(DialogOpenPng.FileName) }).GetShaderResourceView(); _outputTexture = new GorgonTexture2D(_graphics, new GorgonTexture2DInfo(_sourceTexture, "Output") { Format = BufferFormat.R8G8B8A8_Typeless, Binding = TextureBinding.ShaderResource | TextureBinding.ReadWriteView }); // Get an SRV for the output texture so we can render it later. _outputView = _outputTexture.GetShaderResourceView(BufferFormat.R8G8B8A8_UNorm); // Get a UAV for the output. _outputUav = _outputTexture.GetReadWriteView(BufferFormat.R32_UInt); // Process the newly loaded texture. _sobel.Process(_sourceTexture, _outputUav, TrackThickness.Value, TrackThreshold.Value / 100.0f); TrackThreshold.Enabled = TrackThickness.Enabled = true; } catch (Exception ex) { GorgonDialogs.ErrorBox(this, ex); TrackThreshold.Enabled = TrackThickness.Enabled = false; } finally { image?.Dispose(); Cursor.Current = Cursors.Default; } }
/// <summary> /// Handles the ValueChanged event of the TrackThreshold control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void TrackThreshold_ValueChanged(object sender, EventArgs e) { if (_sourceTexture == null) { return; } Cursor.Current = Cursors.WaitCursor; try { // Unfortunately, because the two interfaces are disconnected, we need to ensure that we're not using a resource on the graphics side // when we want access to it on the compute side. This needs to be fixed as it can be a bit on the slow side to constantly do this // every frame. _sobel.Process(_sourceTexture, _outputUav, TrackThickness.Value, TrackThreshold.Value / 100.0f); var png = new GorgonCodecPng(); using (var tempTexture = new GorgonTexture2D(_graphics, new GorgonTexture2DInfo(_outputTexture) { Format = BufferFormat.R8G8B8A8_UNorm })) { _outputTexture.CopyTo(tempTexture); using (IGorgonImage image = tempTexture.ToImage()) { png.SaveToFile(image, @"D:\unpak\uav.png"); } } } catch (Exception ex) { GorgonDialogs.ErrorBox(this, ex); } finally { Cursor.Current = Cursors.Default; } }
/// <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; } }
/// <summary> /// Function to generate the Gorgon bitmap fonts. /// </summary> /// <param name="fontFamilies">The list of TrueType font families to use.</param> /// <param name="window">The window that contains the loading message.</param> private static void GenerateGorgonFonts(IReadOnlyList <Drawing.FontFamily> fontFamilies, FormMain window) { // Pick a font to use with outlines. int fontWithOutlineIndex = GorgonRandom.RandomInt32(1, 5); _glowIndex = GorgonRandom.RandomInt32(fontWithOutlineIndex + 1, fontWithOutlineIndex + 5); int fontWithGradient = GorgonRandom.RandomInt32(_glowIndex + 1, _glowIndex + 5); int fontWithTexture = GorgonRandom.RandomInt32(fontWithGradient + 1, fontWithGradient + 5).Min(_fontFamilies.Count - 1); var pngCodec = new GorgonCodecPng(); using (IGorgonImage texture = pngCodec.LoadFromFile(Path.Combine(GorgonExample.GetResourcePath(@"Textures\Fonts\").FullName, "Gradient.png"))) { for (int i = 0; i < _fontFamilies.Count; ++i) { string fontFamily = _fontFamilies[i]; // Use this to determine if the font is avaiable. if (fontFamilies.All(item => !string.Equals(item.Name, fontFamily, StringComparison.InvariantCultureIgnoreCase))) { // Can't locate this one, move on... continue; } bool isExternal = Drawing.FontFamily.Families.All(item => !string.Equals(item.Name, fontFamily, StringComparison.InvariantCultureIgnoreCase)); string fontName; int outlineSize = 0; GorgonColor outlineColor1 = GorgonColor.BlackTransparent; GorgonColor outlineColor2 = GorgonColor.BlackTransparent; GorgonGlyphBrush brush = null; if (i == fontWithOutlineIndex) { fontName = $"{fontFamily} 32px Outlined{(isExternal ? " External TTF" : string.Empty)}"; outlineColor1 = GorgonColor.Black; outlineColor2 = GorgonColor.Black; outlineSize = 3; } else if (i == _glowIndex) { fontName = $"{fontFamily} 32px Outline as Glow{(isExternal ? " External TTF" : string.Empty)}"; outlineColor1 = new GorgonColor(GorgonColor.YellowPure, 1.0f); outlineColor2 = new GorgonColor(GorgonColor.DarkRed, 0.0f); outlineSize = 16; } else if (i == fontWithGradient) { fontName = $"{fontFamily} 32px Gradient{(isExternal ? " External TTF" : string.Empty)}"; brush = new GorgonGlyphLinearGradientBrush { StartColor = GorgonColor.White, EndColor = GorgonColor.Black, Angle = 45.0f }; } else if (i == fontWithTexture) { fontName = $"{fontFamily} 32px Textured{(isExternal ? " External TTF" : string.Empty)}"; brush = new GorgonGlyphTextureBrush(texture); } else { fontName = $"{fontFamily} 32px{(isExternal ? " External TTF" : string.Empty)}"; } window.UpdateStatus($"Generating Font: {fontFamily}".Ellipses(50)); var fontInfo = new GorgonFontInfo(fontFamily, 30.25f, name: fontName) { AntiAliasingMode = FontAntiAliasMode.AntiAlias, OutlineSize = outlineSize, OutlineColor1 = outlineColor1, OutlineColor2 = outlineColor2, UsePremultipliedTextures = false, Brush = brush }; _font.Add(_fontFactory.GetFont(fontInfo)); // Texture brushes have to be disposed when we're done with them. var disposableBrush = brush as IDisposable; disposableBrush?.Dispose(); } } }
/// <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; } }
/// <summary> /// Raises the <see cref="E:System.Windows.Forms.Form.Load" /> event. /// </summary> /// <param name="e">An <see cref="T:System.EventArgs" /> that contains the event data.</param> protected override void OnLoad(EventArgs e) { base.OnLoad(e); Cursor.Current = Cursors.WaitCursor; try { GorgonExample.ResourceBaseDirectory = new DirectoryInfo(Settings.Default.ResourceLocation); // Load the custom codec. if (!LoadCodec()) { GorgonDialogs.ErrorBox(this, "Unable to load the image codec plug in."); GorgonApplication.Quit(); return; } // Set up the graphics interface. // Find out which devices we have installed in the system. IReadOnlyList <IGorgonVideoAdapterInfo> deviceList = GorgonGraphics.EnumerateAdapters(); if (deviceList.Count == 0) { GorgonDialogs.ErrorBox(this, "There are no suitable video adapters available in the system. This example is unable to continue and will now exit."); GorgonApplication.Quit(); return; } _graphics = new GorgonGraphics(deviceList[0]); _swap = new GorgonSwapChain(_graphics, this, new GorgonSwapChainInfo("Codec PlugIn SwapChain") { Width = ClientSize.Width, Height = ClientSize.Height, Format = BufferFormat.R8G8B8A8_UNorm }); _graphics.SetRenderTarget(_swap.RenderTargetView); // Load the image to use as a texture. IGorgonImageCodec png = new GorgonCodecPng(); _image = png.LoadFromFile(Path.Combine(GorgonExample.GetResourcePath(@"Textures\CodecPlugIn\").FullName, "SourceTexture.png")); GorgonExample.LoadResources(_graphics); ConvertImage(); GorgonApplication.IdleMethod = Idle; } catch (Exception ex) { GorgonExample.HandleException(ex); GorgonApplication.Quit(); } finally { Cursor.Current = Cursors.Default; } }