/// <summary> /// Function to render the thumbnail into the image passed in. /// </summary> /// <param name="image">The image to render the thumbnail into.</param> /// <param name="scale">The scale of the image.</param> private void RenderThumbnail(ref IGorgonImage image, float scale) { lock (_syncLock) { using (GorgonTexture2D texture = image.ToTexture2D(GraphicsContext.Graphics, new GorgonTexture2DLoadOptions { Usage = ResourceUsage.Immutable, IsTextureCube = false })) using (var rtv = GorgonRenderTarget2DView.CreateRenderTarget(GraphicsContext.Graphics, new GorgonTexture2DInfo { ArrayCount = 1, Binding = TextureBinding.ShaderResource, Format = BufferFormat.R8G8B8A8_UNorm, MipLevels = 1, Height = (int)(image.Height * scale), Width = (int)(image.Width * scale), Usage = ResourceUsage.Default })) { GorgonTexture2DView view = texture.GetShaderResourceView(mipCount: 1, arrayCount: 1); rtv.Clear(GorgonColor.BlackTransparent); GraphicsContext.Graphics.SetRenderTarget(rtv); GraphicsContext.Graphics.DrawTexture(view, new DX.Rectangle(0, 0, rtv.Width, rtv.Height), blendState: GorgonBlendState.Default, samplerState: GorgonSamplerState.Default); GraphicsContext.Graphics.SetRenderTarget(null); image?.Dispose(); image = rtv.Texture.ToImage(); } } }
/// <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); }
/// <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="GorgonTexture2DReadWriteView"/></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="GorgonTexture2DReadWriteView"/>. /// </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="GorgonTexture2DReadWriteView"/> returned, disposal of either one will dispose of the other on your behalf. If /// the user created a <see cref="GorgonTexture2DReadWriteView"/> 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 GorgonTexture2DReadWriteView 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)) { GorgonTexture2D texture = image.ToTexture2D(graphics, options); GorgonTexture2DReadWriteView view = texture.GetReadWriteView(); view.OwnsResource = true; return(view); } }
/// <summary>Function to create the texture for the view.</summary> /// <param name="graphics">The graphics interface used to create the texture.</param> /// <param name="imageData">The image data to create the texture from.</param> /// <param name="name">The name of the texture.</param> protected override void OnCreateTexture(GorgonGraphics graphics, IGorgonImage imageData, string name) { _texture = imageData.ToTexture2D(graphics, new GorgonTexture2DLoadOptions { Name = name, Binding = TextureBinding.ShaderResource, Usage = ResourceUsage.Immutable, IsTextureCube = false }); _textureView = _texture.GetShaderResourceView(); }
/// <summary> /// Function to create a new texture that is bindable to the GPU. /// </summary> /// <param name="graphics">The graphics interface to use when creating the target.</param> /// <param name="info">The information about the texture.</param> /// <param name="initialData">[Optional] Initial data used to populate the texture.</param> /// <returns>A new <see cref="GorgonTexture2DView"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, or <paramref name="info"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// This is a convenience method that will create a <see cref="GorgonTexture2D"/> and a <see cref="GorgonTexture2DView"/> as a single object that users can use to apply a texture as a shader /// resource. This helps simplify creation of a texture by executing some prerequisite steps on behalf of the user. /// </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> /// <para> /// If an <paramref name="initialData"/> image is provided, and the width/height/depth is not the same as the values in the <paramref name="info"/> parameter, then the image data will be cropped to /// match the values in the <paramref name="info"/> parameter. Things like array count, and mip levels will still be taken from the <paramref name="initialData"/> image parameter. /// </para> /// </remarks> /// <seealso cref="GorgonTexture2D"/> public static GorgonTexture2DView CreateTexture(GorgonGraphics graphics, IGorgonTexture2DInfo info, IGorgonImage initialData = null) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } if (info == null) { throw new ArgumentNullException(nameof(info)); } if (initialData != null) { if ((initialData.Width < info.Width) || (initialData.Height < info.Height)) { initialData.Expand(info.Width, info.Height, 1); } if ((initialData.Width > info.Width) || (initialData.Height > info.Height)) { initialData.Crop(new DX.Rectangle(0, 0, info.Width, info.Height), 1); } } var newInfo = new GorgonTexture2DInfo(info) { Usage = info.Usage == ResourceUsage.Staging ? ResourceUsage.Default : info.Usage, Binding = (info.Binding & TextureBinding.ShaderResource) != TextureBinding.ShaderResource ? (info.Binding | TextureBinding.ShaderResource) : info.Binding }; GorgonTexture2D texture = initialData == null ? new GorgonTexture2D(graphics, newInfo) : initialData.ToTexture2D(graphics, new GorgonTexture2DLoadOptions { Usage = newInfo.Usage, Binding = newInfo.Binding, MultisampleInfo = newInfo.MultisampleInfo, Name = newInfo.Name, IsTextureCube = newInfo.IsCubeMap }); GorgonTexture2DView result = texture.GetShaderResourceView(); result.OwnsResource = true; return(result); }
/// <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); } }
/// <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="GorgonTexture2DView"/></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="GorgonTexture2D"/> object and return a <see cref="GorgonTexture2DView"/>. /// </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> /// <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 FromStream(GorgonGraphics graphics, Stream stream, IGorgonImageCodec codec, long?size = null, GorgonTexture2DLoadOptions 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)) { GorgonTexture2D texture = image.ToTexture2D(graphics, options); GorgonTexture2DView view = texture.GetShaderResourceView(); view.OwnsResource = true; return(view); } }
/// <summary> /// Function to convert the image to use our custom codec. /// </summary> private void ConvertImage() { // The path to our image file for our custom codec. string tempPath = Path.ChangeExtension(Path.GetTempPath().FormatDirectory(Path.DirectorySeparatorChar) + Path.GetRandomFileName(), "tvImage"); try { // Save the current texture using our useless new custom codec. _customCodec.SaveToFile(_image.ConvertToFormat(BufferFormat.R8G8B8A8_UNorm), tempPath); _image.Dispose(); _texture?.Dispose(); _image = _customCodec.LoadFromFile(tempPath); _texture = _image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Converted Texture" }).GetShaderResourceView(); } catch { // Clean up the new texture should we have an exception (this shouldn't happen, better safe than sorry). _image?.Dispose(); throw; } finally { try { File.Delete(tempPath); } // ReSharper disable once EmptyGeneralCatchClause catch { // Intentionally left blank. // If we can't clean up the temp file, then it's no big deal right now. } } }
/// <summary> /// Function to initialize the GPU resource objects. /// </summary> private static void InitializeGpuResources() { _graphics = CreateGraphicsInterface(); // If we couldn't create the graphics interface, then leave. if (_graphics == null) { return; } // Create a 1280x800 window with a depth buffer. // We can modify the resolution in the config file for the application, but like other Gorgon examples, the default is 1280x800. _swap = new GorgonSwapChain(_graphics, _mainForm, new GorgonSwapChainInfo("Main") { // Set up for 32 bit RGBA normalized display. Format = BufferFormat.R8G8B8A8_UNorm, Width = Settings.Default.Resolution.Width, Height = Settings.Default.Resolution.Height }); // Build the depth buffer for our swap chain. BuildDepthBuffer(_swap.Width, _swap.Height); if (!Settings.Default.IsWindowed) { // Get the output for the main window. var currentScreen = Screen.FromControl(_mainForm); IGorgonVideoOutputInfo output = _graphics.VideoAdapter.Outputs[currentScreen.DeviceName]; // If we've asked for full screen mode, then locate the correct video mode and set us up. _selectedVideoMode = new GorgonVideoMode(Settings.Default.Resolution.Width, Settings.Default.Resolution.Height, BufferFormat.R8G8B8A8_UNorm); _swap.EnterFullScreen(in _selectedVideoMode, output); } // Handle resizing because the projection matrix and depth buffer needs to be updated to reflect the new view size. _swap.BeforeSwapChainResized += Swap_BeforeResized; _swap.AfterSwapChainResized += Swap_AfterResized; // Set the current render target output so we can see something. _graphics.SetRenderTarget(_swap.RenderTargetView, _depthBuffer); // Create our shaders. // Our vertex shader. This is a simple shader, it just processes a vertex by multiplying it against // the world/view/projection matrix and spits it back out. _vertexShader = GorgonShaderFactory.Compile <GorgonVertexShader>(_graphics, Resources.Shader, "BoingerVS"); // Our main pixel shader. This is a very simple shader, it just reads a texture and spits it back out. Has no // diffuse capability. _pixelShader = GorgonShaderFactory.Compile <GorgonPixelShader>(_graphics, Resources.Shader, "BoingerPS"); // Create the vertex input layout. // We need to create a layout for our vertex type because the shader won't know how to interpret the data we're sending it otherwise. // This is why we need a vertex shader before we even create the layout. _inputLayout = GorgonInputLayout.CreateUsingType <BoingerVertex>(_graphics, _vertexShader); // Resources are stored as System.Drawing.Bitmap files, so we need to convert into an IGorgonImage so we can upload it to a texture. // We also will generate mip-map levels for this image so that scaling the texture will look better. using (IGorgonImage image = Resources.Texture.ToGorgonImage()) { _texture = image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Usage = ResourceUsage.Immutable, Name = "Texture" }) .GetShaderResourceView(); } // Create our constant buffer. // Our constant buffers are how we send data to our shaders. This one in particular will be responsible for sending our world/view/projection matrix // to the vertex shader. _wvpBuffer = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("WVPBuffer") { Usage = ResourceUsage.Dynamic, SizeInBytes = DX.Matrix.SizeInBytes }); // This one will hold our material information. _materialBuffer = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("MaterialBuffer") { Usage = ResourceUsage.Dynamic, SizeInBytes = Unsafe.SizeOf <GorgonColor>() }); GorgonColor defaultMaterialColor = GorgonColor.White; _materialBuffer.Buffer.SetData(ref defaultMaterialColor); GorgonExample.LoadResources(_graphics); }
/// <summary> /// Function to load textures from application resources. /// </summary> private static void LoadTextures() { // Load standard images from the resource section. _renderer.TextureCache["UV"] = Resources.UV.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "UV" }).GetShaderResourceView(); _renderer.TextureCache["Earth"] = Resources.earthmap1k.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Earth" }).GetShaderResourceView(); _renderer.TextureCache["Earth_Specular"] = Resources.earthspec1k.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Earth_Specular" }).GetShaderResourceView(); _renderer.TextureCache["Clouds"] = Resources.earthcloudmap.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Clouds" }).GetShaderResourceView(); _renderer.TextureCache["GorgonNormalMap"] = Resources.normalmap.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "GorgonNormalMap" }).GetShaderResourceView(); // The following images are DDS encoded and require an encoder to read them from the resources. var dds = new GorgonCodecDds(); using (var stream = new MemoryStream(Resources.Rain_Height_NRM)) using (IGorgonImage image = dds.LoadFromStream(stream)) { _renderer.TextureCache["Water_Normal"] = image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Water_Normal" }).GetShaderResourceView(); } using (var stream = new MemoryStream(Resources.Rain_Height_SPEC)) using (IGorgonImage image = dds.LoadFromStream(stream)) { _renderer.TextureCache["Water_Specular"] = image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Water_Specular" }).GetShaderResourceView(); } using (var stream = new MemoryStream(Resources.earthbump1k_NRM)) using (IGorgonImage image = dds.LoadFromStream(stream)) { _renderer.TextureCache["Earth_Normal"] = image.ToTexture2D(_graphics, new GorgonTexture2DLoadOptions { Name = "Earth_Normal" }).GetShaderResourceView(); } }