/// <summary> /// Function to build up the render targets. /// </summary> /// <param name="width">The width of the render targets.</param> /// <param name="height">The height of the render targets.</param> /// <param name="format">The format of the buffer.</param> private void BuildRenderTargets(int width, int height, BufferFormat format) { // For the lighting effect, we use a deferred rendering technique where we have 3 render targets for diffuse, specularity, and normal mapping. // These targets are sub resources of the same texture resource (array indices). // Diffuse. _rtvInfo.Width = width; _rtvInfo.Height = height; _rtvInfo.Format = format; _rtvInfo.ArrayCount = 2; _gbufferTargets[0] = Graphics.TemporaryTargets.Rent(_rtvInfo, "Gorgon 2D GBuffer - Diffuse/Specular", false); _gbufferTargets[0].Clear(GorgonColor.Black); // Specular. _gbufferTargets[1] = _gbufferTargets[0].Texture.GetRenderTargetView(arrayIndex: 1, arrayCount: 1); _rtvInfo.Format = BufferFormat.R8G8B8A8_UNorm; _rtvInfo.ArrayCount = 1; // Normals. // We'll clear it before the pass, the default color is insufficient. _gbufferTargets[2] = Graphics.TemporaryTargets.Rent(_rtvInfo, "Gorgon 2D Buffer - Normals", false); GorgonTexture2DView normalSrv = _gbufferTargets[2].GetShaderResourceView(); if ((_pixelLitShaderState.ShaderResources[1] != normalSrv) || (_diffuseFilter != DiffuseFiltering) || (_normalFilter != NormalFiltering) || (_specularFilter != SpecularFiltering)) { _diffuseFilter = DiffuseFiltering ?? GorgonSamplerState.Default; _normalFilter = NormalFiltering ?? GorgonSamplerState.PointFiltering; _specularFilter = SpecularFiltering ?? GorgonSamplerState.Default; _pixelDeferShaderState = PixelShaderBuilder.ResetTo(_pixelDeferShaderState) .SamplerState(_diffuseFilter, 0) .SamplerState(_normalFilter, 1) .SamplerState(_specularFilter, 2) .Build(); _pixelLitShaderState = PixelShaderBuilder .ResetTo(_pixelLitShaderState) .ShaderResource(normalSrv, 1) .SamplerState(_diffuseFilter, 0) .SamplerState(_normalFilter, 1) .SamplerState(_specularFilter, 2) .Build(); _lightingState = BatchStateBuilder .ResetTo(_lightingState) .PixelShaderState(_pixelLitShaderState) .Build(); } _gbufferTexture = _gbufferTargets[0].Texture.GetShaderResourceView(); }
/// <summary> /// Function to assign a sampler to a shader on the pipeline. /// </summary> /// <param name="sampler">The sampler to assign.</param> /// <param name="index">[Optional] The index of the sampler.</param> /// <returns>The fluent interface for this builder.</returns> /// <exception cref="ArgumentOutOfRangeException">Thrown if the <paramref name="index"/> parameter is less than 0, or greater than/equal to <see cref="GorgonSamplerStates.MaximumSamplerStateCount"/>.</exception> public Gorgon2DShaderStateBuilder <T> SamplerState(GorgonSamplerState sampler, int index = 0) { if ((index < 0) || (index >= GorgonSamplerStates.MaximumSamplerStateCount)) { throw new ArgumentOutOfRangeException(nameof(index), string.Format(Resources.GOR2D_ERR_INVALID_SAMPLER_INDEX, GorgonSamplerStates.MaximumSamplerStateCount)); } _workingShader.RwSamplers[index] = sampler; return(this); }
/// <summary>Handles the PropertyChanged event of the WrappingEditor control.</summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param> private void WrappingEditor_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { case nameof(ISpriteWrappingEditor.BorderColor): case nameof(ISpriteWrappingEditor.HorizontalWrapping): case nameof(ISpriteWrappingEditor.VerticalWrapping): _current = SpriteContent.WrappingEditor.GetSampler(SpriteContent.SamplerState.Filter); break; } }
/// <summary>Function called when the sprite has a property change.</summary> /// <param name="e">The event parameters.</param> protected override void OnSpriteChanged(PropertyChangedEventArgs e) { base.OnSpriteChanged(e); switch (e.PropertyName) { case nameof(ISpriteContent.SamplerState): _current = SpriteContent.WrappingEditor.GetSampler(SpriteContent.SamplerState.Filter); SpriteContent.WrappingEditor.HorizontalWrapping = _current.WrapU; SpriteContent.WrappingEditor.VerticalWrapping = _current.WrapV; SpriteContent.WrappingEditor.OriginalBorderColor = SpriteContent.WrappingEditor.BorderColor = _current.BorderColor; break; } }
/// <summary>Function called to perform custom loading of resources.</summary> protected override void OnLoad() { base.OnLoad(); if (_builder == null) { _builder = new GorgonSamplerStateBuilder(Graphics); } _current = SpriteContent.SamplerState; SpriteContent.WrappingEditor.HorizontalWrapping = _current.WrapU; SpriteContent.WrappingEditor.VerticalWrapping = _current.WrapV; SpriteContent.WrappingEditor.OriginalBorderColor = SpriteContent.WrappingEditor.BorderColor = _current.BorderColor; SpriteContent.WrappingEditor.PropertyChanged += WrappingEditor_PropertyChanged; BuildSpriteRtv(); }
/// <summary> /// Function to render a texture to the current render target using the current effect. /// </summary> /// <param name="texture">The texture to render.</param> /// <param name="outputSize">The size of the output render target that the blit will render into.</param> /// <param name="destinationRegion">[Optional] The region that the texture will be drawn into.</param> /// <param name="textureCoordinates">[Optional] The texture coordinates to use with the texture.</param> /// <param name="samplerStateOverride">[Optional] An override for the current texture sampler.</param> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="texture"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// This method is a convenience method that will render a texture to the current set render target in slot 0. /// </para> /// <para> /// If the <paramref name="destinationRegion"/> parameter is omitted, then the texture will be rendered to the full size of the current render target. If it is provided, then texture will be rendered to the /// location specified, and with the width and height specified. /// </para> /// <para> /// If the <paramref name="textureCoordinates"/> parameter is omitted, then the full size of the texture is rendered. /// </para> /// <para> /// If the <paramref name="samplerStateOverride"/> parameter is omitted, then the <see cref="GorgonSamplerState.Default"/> is used. When provided, this will alter how the pixel shader samples our /// texture in slot 0. /// </para> /// <para> /// <note type="important"> /// <para> /// For performance reasons, any exceptions thrown by this method will only be thrown when Gorgon is compiled as DEBUG. /// </para> /// </note> /// </para> /// </remarks> /// <seealso cref="GorgonBlendState"/> /// <seealso cref="GorgonDepthStencilState"/> /// <seealso cref="GorgonRasterState"/> /// <seealso cref="Gorgon2DOrthoCamera"/> /// <seealso cref="Gorgon2DPerspectiveCamera"/> protected void BlitTexture(GorgonTexture2DView texture, DX.Size2 outputSize, DX.RectangleF?destinationRegion = null, DX.RectangleF?textureCoordinates = null, GorgonSamplerState samplerStateOverride = null) { texture.ValidateObject(nameof(texture)); if (destinationRegion == null) { destinationRegion = new DX.RectangleF(0, 0, outputSize.Width, outputSize.Height); } if (textureCoordinates == null) { textureCoordinates = new DX.RectangleF(0, 0, 1, 1); } Renderer.DrawFilledRectangle(destinationRegion.Value, GorgonColor.White, texture, textureCoordinates, textureSampler: samplerStateOverride); }
/// <summary> /// Function to blit the specified texture into the current output target. /// </summary> /// <param name="texture">The texture to blit.</param> /// <param name="textureCoordinates">[Optional] The texture coordinates to use on the source texture.</param> /// <param name="samplerState">[Optional] The sampler state to apply.</param> protected void Blit(GorgonTexture2DView texture, DX.RectangleF?textureCoordinates = null, GorgonSamplerState samplerState = null) => Renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, OutputSize.Width, OutputSize.Height), GorgonColor.White, texture, textureCoordinates ?? new DX.RectangleF(0, 0, 1, 1), textureSampler: samplerState ?? GorgonSamplerState.Default, depth: 0.1f);
/// <summary> /// Function to blit the texture to the specified render target. /// </summary> /// <param name="texture">The texture that will be blitted to the render target.</param> /// <param name="destRect">The layout area to blit the texture into.</param> /// <param name="sourceOffset">The offset within the source texture to start blitting from.</param> /// <param name="color">The color used to tint the diffuse value of the texture.</param> /// <param name="clip"><b>true</b> to clip the contents of the texture if the destination is larger/small than the size of the texture.</param> /// <param name="blendState">The blending state to apply.</param> /// <param name="samplerState">The sampler state to apply.</param> /// <param name="pixelShader">The pixel shader used to override the default pixel shader.</param> /// <param name="pixelShaderConstants">The pixel shader constant buffers to use.</param> public void Blit(GorgonTexture2DView texture, DX.Rectangle destRect, DX.Point sourceOffset, GorgonColor color, bool clip, GorgonBlendState blendState, GorgonSamplerState samplerState, GorgonPixelShader pixelShader, GorgonConstantBuffers pixelShaderConstants) { if ((_graphics.RenderTargets[0] == null) || (color.Alpha.EqualsEpsilon(0))) { return; } if (texture == null) { texture = _defaultTexture; } GorgonRenderTargetView currentView = _graphics.RenderTargets[0]; // We need to update the projection/view if the size of the target changes. if ((_targetBounds == null) || (currentView.Width != _targetBounds.Value.Width) || (currentView.Height != _targetBounds.Value.Height)) { _needsWvpUpdate = true; } UpdateProjection(); // Set to default states if not provided. if (blendState == null) { blendState = GorgonBlendState.NoBlending; } if (pixelShader == null) { pixelShader = _pixelShader; } if (samplerState == null) { samplerState = GorgonSamplerState.Default; } if (pixelShaderConstants == null) { pixelShaderConstants = _emptyPsConstants; } GetDrawCall(texture, blendState, samplerState, pixelShader, pixelShaderConstants); // Calculate position on the texture. DX.Vector2 topLeft = texture.Texture.ToTexel(sourceOffset); DX.Vector2 bottomRight = texture.Texture.ToTexel(clip ? new DX.Vector2(destRect.Width, destRect.Height) : new DX.Point(texture.Width, texture.Height)); if (clip) { DX.Vector2.Add(ref bottomRight, ref topLeft, out bottomRight); } // Update the vertices. _vertices[0] = new BltVertex { Position = new DX.Vector4(destRect.X, destRect.Y, 0, 1.0f), Uv = topLeft, Color = color }; _vertices[1] = new BltVertex { Position = new DX.Vector4(destRect.Right, destRect.Y, 0, 1.0f), Uv = new DX.Vector2(bottomRight.X, topLeft.Y), Color = color }; _vertices[2] = new BltVertex { Position = new DX.Vector4(destRect.X, destRect.Bottom, 0, 1.0f), Uv = new DX.Vector2(topLeft.X, bottomRight.Y), Color = color }; _vertices[3] = new BltVertex { Position = new DX.Vector4(destRect.Right, destRect.Bottom, 0, 1.0f), Uv = new DX.Vector2(bottomRight.X, bottomRight.Y), Color = color }; // Copy to the vertex buffer. _vertexBufferBindings[0].VertexBuffer.SetData(_vertices); _graphics.Submit(_drawCall); }
/// <summary> /// Function to return the appropriate draw call based on the states provided. /// </summary> /// <param name="texture">The texture to display.</param> /// <param name="blendState">The blending state for the texture.</param> /// <param name="samplerState">The sampler state for the texture.</param> /// <param name="shader">The pixel shader to use.</param> /// <param name="constantBuffers">Constant buffers for the pixel shader, if required.</param> private void GetDrawCall(GorgonTexture2DView texture, GorgonBlendState blendState, GorgonSamplerState samplerState, GorgonPixelShader shader, GorgonConstantBuffers constantBuffers) { if ((_drawCall != null) && (shader == _pixelShader) && (_drawCall.PixelShader.Samplers[0] == samplerState) && (_pipelineState.BlendStates[0] == blendState) && (_drawCall.PixelShader.ShaderResources[0] == texture) && (_drawCall.PixelShader.ConstantBuffers.DirtyEquals(constantBuffers))) { // This draw call hasn't changed, so return the previous one. return; } if (_pipelineState.BlendStates[0] != blendState) { _pipelineState = _pipeStateBuilder .BlendState(blendState) .Build(); _drawCallBuilder.PipelineState(_pipelineState); } _drawCall = _drawCallBuilder.ConstantBuffers(ShaderType.Pixel, constantBuffers) .SamplerState(ShaderType.Pixel, samplerState) .ShaderResource(ShaderType.Pixel, texture) .Build(_drawAllocator); }
/// <summary> /// Function to assign a texture sampler to the polygon sprite. /// </summary> /// <param name="sampler">The sampler to assign to the sprite.</param> /// <returns>The fluent interface for this builder.</returns> public GorgonPolySpriteBuilder TextureSampler(GorgonSamplerState sampler) { _workingSprite.TextureSampler = sampler; return(this); }