/// <summary> /// Function to initialize the application. /// </summary> private static void Initialize() { try { // Create our form. _mainForm = GorgonExample.Initialize(new DX.Size2(Settings.Default.Resolution.Width, Settings.Default.Resolution.Height), "Boinger"); // Add a keybinding to switch to full screen or windowed. _mainForm.KeyDown += _mainForm_KeyDown; // Set up the swap chain, buffers, and texture(s). InitializeGpuResources(); // Create our planes. // Here's where we create the 2 planes for our rear wall and floor. We set the texture size to texel units because that's how the video card expects // them. However, it's a little hard to eyeball 0.67798223f by looking at the texture image display, so we use the ToTexel function to determine our // texel size. DX.Size2F textureSize = _texture.ToTexel(new DX.Size2(511, 511)); // And here we set up the planes with a material, and initial positioning. _planes = new[] { new Plane(_graphics, _inputLayout, new DX.Vector2(3.5f), new DX.RectangleF(0, 0, textureSize.Width, textureSize.Height)) { Material = new Material { Diffuse = GorgonColor.White, Texture = _texture }, Position = new DX.Vector3(0, 0, 3.0f) }, new Plane(_graphics, _inputLayout, new DX.Vector2(3.5f), new DX.RectangleF(0, 0, textureSize.Width, textureSize.Height)) { Material = new Material { Diffuse = GorgonColor.White, Texture = _texture }, Position = new DX.Vector3(0, -3.5f, 3.5f), Rotation = new DX.Vector3(90.0f, 0, 0) } }; // Create our sphere. // Again, here we're using texels to align the texture coordinates to the other image packed into the texture (atlasing). DX.Vector2 textureOffset = _texture.ToTexel(new DX.Vector2(516, 0)); // This is to scale our texture coordinates because the actual image is much smaller (255x255) than the full texture (1024x512). textureSize = _texture.ToTexel(new DX.Size2(255, 255)); // Give the sphere a place to live. _sphere = new Sphere(_graphics, _inputLayout, 1.0f, textureOffset, textureSize) { Position = new DX.Vector3(2.2f, 1.5f, 2.5f), Material = new Material { Diffuse = GorgonColor.White, Texture = _texture } }; // Initialize the states used to draw the objects. InitializeStates(); // Initialize 2D rendering. _2D = new Gorgon2D(_graphics); // I know, there's a lot in here. Thing is, if this were Direct 3D 11 code, it'd probably MUCH // more code and that's even before creating our planes and sphere. } finally { GorgonExample.EndInit(); } }
/// <summary> /// Function used to initialize the application. /// </summary> private static void Initialize() { GorgonExample.ResourceBaseDirectory = new DirectoryInfo(Settings.Default.ResourceLocation); // Build the form so we can actually show something. _mainForm = GorgonExample.Initialize(new DX.Size2(1280, 800), "Geometry Shaders"); try { // Now we create and enumerate the list of video devices installed in the computer. // We must do this in order to tell Gorgon which video device we intend to use. Note that this method may be quite slow (particularly when running DEBUG versions of // Direct 3D). To counter this, this object and its Enumerate method are thread safe so this can be run in the background while keeping the main UI responsive. // // If no suitable device was found (no Direct 3D 11.4 support) in the computer, this method will return an empty list. However, if it succeeds, then the devices list // will be populated with an IGorgonVideoDeviceInfo for each suitable video device in the system. // // Using this method, we could also enumerate the WARP software rasterizer, and/of the D3D Reference device (only if the DEBUG functionality provided by the Windows // SDK is installed). These devices are typically used to determine if there's a driver error, and can be terribly slow to render (reference moreso than WARP). It is // recommended that these only be used in diagnostic scenarios only. IReadOnlyList <IGorgonVideoAdapterInfo> devices = GorgonGraphics.EnumerateAdapters(log: GorgonApplication.Log); if (devices.Count == 0) { GorgonDialogs.ErrorBox(_mainForm, "This example requires a video adapter that supports Direct3D 11.4 or better."); GorgonApplication.Quit(); return; } // Now we create the main graphics interface with the first applicable video device. _graphics = new GorgonGraphics(devices[0], log: GorgonApplication.Log); // Check to ensure that we can support the format required for our swap chain. // If a video device can't support this format, then the odds are good it won't render anything. Since we're asking for a very common display format, this will // succeed nearly 100% of the time. Regardless, it's good form to the check for a working display format prior to setting up the swap chain. // // This is also used to determine if a format can be used for other objects (e.g. a texture, render target, etc...) And like the swap chain format, it is also best // practice to check if the object you're creating supports the desired format. if (!_graphics.FormatSupport[BufferFormat.R8G8B8A8_UNorm].IsDisplayFormat) { // We should never see this unless you've got some very esoteric hardware. GorgonDialogs.ErrorBox(_mainForm, "We should not see this error."); return; } // Finally, create a swap chain to display our output. // In this case we're setting up our swap chain to bind with our main window, and we use its client size to determine the width/height of the swap chain back buffers. // This width/height does not need to be the same size as the window, but, except for some scenarios, that would produce undesirable image quality. _swap = new GorgonSwapChain(_graphics, _mainForm, new GorgonSwapChainInfo("Main Swap Chain") { Format = BufferFormat.R8G8B8A8_UNorm, Width = _mainForm.ClientSize.Width, Height = _mainForm.ClientSize.Height }); // Assign events so we can update our projection with our window size. _swap.BeforeSwapChainResized += Swap_BeforeSwapChainResized; _swap.AfterSwapChainResized += Swap_AfterSwapChainResized; // We'll need a depth buffer for this example, or else our pyramid will look weird when rotating as back faces will appear through front faces. // So, first we should check for support of a proper depth/stencil format. That said, if we don't have this format, then we're likely not running hardware from the last decade or more. if (!_graphics.FormatSupport[BufferFormat.D24_UNorm_S8_UInt].IsDepthBufferFormat) { GorgonDialogs.ErrorBox(_mainForm, "A 24 bit depth buffer is required for this example."); return; } _depthStencil = GorgonDepthStencil2DView.CreateDepthStencil(_graphics, new GorgonTexture2DInfo { Format = BufferFormat.D24_UNorm_S8_UInt, Binding = TextureBinding.DepthStencil, Usage = ResourceUsage.Default, Width = _swap.Width, Height = _swap.Height }); // Load the shaders from a file on disc. LoadShaders(); // Load the texture. _texture = GorgonTexture2DView.FromFile(_graphics, Path.Combine(GorgonExample.GetResourcePath(@"Textures\GeometryShader\").FullName, "GSTexture.png"), new GorgonCodecPng()); // Create our builders so we can compose a draw call and pipeline state. _drawCallBuilder = new GorgonDrawCallBuilder(); _pipeStateBuilder = new GorgonPipelineStateBuilder(_graphics); // Create a constant buffer so we can adjust the positioning of the data. DX.Matrix.PerspectiveFovLH((65.0f).ToRadians(), (float)_swap.Width / _swap.Height, 0.125f, 1000.0f, out _projection); _vsConstants = GorgonConstantBufferView.CreateConstantBuffer(_graphics, new GorgonConstantBufferInfo("WorldProjection CBuffer") { SizeInBytes = (DX.Matrix.SizeInBytes * 2) + DX.Vector4.SizeInBytes }); _vsConstants.Buffer.SetData(ref _projection, copyMode: CopyMode.Discard); _vsConstants.Buffer.SetData(ref _worldMatrix, 64, CopyMode.NoOverwrite); // Create a draw call so we actually have something we can draw. _drawCall = _drawCallBuilder.VertexRange(0, 3) .PipelineState(_pipeStateBuilder.PixelShader(_pixelShader) .VertexShader(_bufferless) .GeometryShader(_geometryShader) .DepthStencilState(GorgonDepthStencilState.DepthEnabled)) .ShaderResource(ShaderType.Pixel, _texture) .ConstantBuffer(ShaderType.Vertex, _vsConstants) .ConstantBuffer(ShaderType.Geometry, _vsConstants) .Build(); // Finally set our swap chain as the active rendering target and the depth/stencil buffer. _graphics.SetRenderTarget(_swap.RenderTargetView, _depthStencil); GorgonExample.LoadResources(_graphics); } finally { GorgonExample.EndInit(); } }
/// <summary> /// Function to initialize the application. /// </summary> /// <returns>The application window.</returns> private static FormMain Initialize() { GorgonExample.ResourceBaseDirectory = new DirectoryInfo(Settings.Default.ResourceLocation); // Create our form and center on the primary monitor. FormMain window = GorgonExample.Initialize(new DX.Size2(1280, 800), "Gorgon MiniTri - Now with 100% more textures."); try { // First we create and enumerate the list of video devices installed in the computer. // We must do this in order to tell Gorgon which video device we intend to use. Note that this method may be quite slow (particularly when running DEBUG versions of // Direct 3D). To counter this, this object and its Enumerate method are thread safe so this can be run in the background while keeping the main UI responsive. // Find out which devices we have installed in the system. // If no suitable device was found (no Direct 3D 12.0 support) in the computer, this method will throw an exception. However, if it succeeds, then the devices object // will be populated with the IGorgonVideoDeviceInfo for each video device in the system. // // Using this method, we could also enumerate the software rasterizer. These devices are typically used to determine if there's a driver error, and can be terribly slow to render // It is recommended that these only be used in diagnostic scenarios only. IReadOnlyList <IGorgonVideoAdapterInfo> deviceList = GorgonGraphics.EnumerateAdapters(); if (deviceList.Count == 0) { throw new NotSupportedException("There are no suitable video adapters available in the system. This example is unable to continue and will now exit."); } // Now we create the main graphics interface with the first applicable video device. _graphics = new GorgonGraphics(deviceList[0]); // Check to ensure that we can support the format required for our swap chain. // If a video device can't support this format, then the odds are good it won't render anything. Since we're asking for a very common display format, this will // succeed nearly 100% of the time (unless you've somehow gotten an ancient video device to work with Direct 3D 11.1). Regardless, it's good form to the check for a // working display format prior to setting up the swap chain. // // This method is also used to determine if a format can be used for other objects (e.g. a texture, render target, etc...) Like the swap chain format, this is also a // best practice to check if the object you're creating supports the desired format. if ((_graphics.FormatSupport[BufferFormat.R8G8B8A8_UNorm].FormatSupport & BufferFormatSupport.Display) != BufferFormatSupport.Display) { // We should never see this unless you've performed some form of black magic. GorgonDialogs.ErrorBox(window, "We should not see this error."); return(window); } // Finally, create a swap chain to display our output. // In this case we're setting up our swap chain to bind with our main window, and we use its client size to determine the width/height of the swap chain back buffers. // This width/height does not need to be the same size as the window, but, except for some scenarios, that would produce undesirable image quality. _swap = new GorgonSwapChain(_graphics, window, new GorgonSwapChainInfo("Main Swap Chain") { Format = BufferFormat.R8G8B8A8_UNorm, Width = window.ClientSize.Width, Height = window.ClientSize.Height }) { DoNotAutoResizeBackBuffer = true }; // Create the shaders used to render the triangle. // These shaders provide transformation and coloring for the output pixel data. CreateShaders(); // Set up our input layout. // // We'll be using this to describe to Direct 3D how the elements of a vertex is laid out in memory. // In order to provide synchronization between the layout on the CPU side and the GPU side, we have to pass the vertex shader because it will contain the vertex // layout to match with our C# input layout. _inputLayout = GorgonInputLayout.CreateUsingType <MiniTriVertex>(_graphics, _vertexShader); // Load our texture so that we can apply it to our triangle. // // We load this first so we can use some functionality present on the texture to calculate the texture space coordinates required to render with the texture. _texture = GorgonTexture2DView.FromFile(_graphics, Path.Combine(GorgonExample.GetResourcePath(@"Textures\MiniTri\").FullName, "Gorgon.MiniTri.png"), new GorgonCodecPng()); // Set up the triangle vertices. CreateVertexBuffer(); // Set up the constant buffer. // // This is used (but could be used for more) to transform the vertex data from 3D space into 2D space. CreateConstantBuffer(window); // This defines where to send the pixel data when rendering. For now, this goes to our swap chain. _graphics.SetRenderTarget(_swap.RenderTargetView); // Create our draw call. // // This will pass all the necessary information to the GPU to render the triangle // // Since draw calls are immutable objects, we use builders to create them (and any pipeline state). Once a draw // call is built, it cannot be changed (except for the vertex, and if applicable, index, and instance ranges). // // Builders work on a fluent interface. Much like LINQ and can be used to create multiple draw calls from the same // builder. var drawCallBuilder = new GorgonDrawCallBuilder(); var pipelineStateBuilder = new GorgonPipelineStateBuilder(_graphics); _drawCall = drawCallBuilder.VertexBuffer(_inputLayout, _vertexBuffer) .VertexRange(0, 3) .ConstantBuffer(ShaderType.Vertex, _constantBuffer) .ShaderResource(ShaderType.Pixel, _texture) .PipelineState(pipelineStateBuilder .PixelShader(_pixelShader) .VertexShader(_vertexShader) .RasterState(GorgonRasterState.NoCulling)) .Build(); GorgonExample.LoadResources(_graphics); return(window); } finally { GorgonExample.EndInit(); } }