/// <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 called to render the effect. /// </summary> /// <param name="renderMethod">The method used to render the scene that will be used in the effect.</param> /// <param name="output">The render target that will receive the results of rendering the effect.</param> /// <param name="blendStateOverride">[Optional] An override for the current blending state.</param> /// <param name="depthStencilStateOverride">[Optional] An override for the current depth/stencil state.</param> /// <param name="rasterStateOverride">[Optional] An override for the current raster state.</param> /// <param name="camera">[Optional] The camera to use when rendering.</param> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="renderMethod"/>, or the <paramref name="output"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// The <paramref name="renderMethod"/> is a callback to a method with 3 parameters: /// <list type="number"> /// <item> /// <description>The current pass index.</description> /// </item> /// <item> /// <description>The total number of passes.</description> /// </item> /// <item> /// <description>The size of the current render target.</description> /// </item> /// </list> /// Users should pass a method that will render the items they want to use with this effect. /// </para> /// <para> /// <para> /// If the <paramref name="blendStateOverride"/>, parameter is omitted, then the <see cref="GorgonBlendState.Default"/> is used. When provided, this will override the current blending state. /// </para> /// <para> /// If the <paramref name="depthStencilStateOverride"/> parameter is omitted, then the <see cref="GorgonDepthStencilState.Default"/> is used. When provided, this will override the current /// depth/stencil state. /// </para> /// <para> /// If the <paramref name="rasterStateOverride"/> parameter is omitted, then the <see cref="GorgonRasterState.Default"/> is used. When provided, this will override the current raster state. /// </para> /// <para> /// The <paramref name="camera"/> parameter is used to render the texture using a different view, and optionally, a different coordinate set. /// </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> /// </para> /// </remarks> public void Render(Action <int, int, DX.Size2> renderMethod, GorgonRenderTargetView output, GorgonBlendState blendStateOverride = null, GorgonDepthStencilState depthStencilStateOverride = null, GorgonRasterState rasterStateOverride = null, IGorgon2DCamera camera = null) { renderMethod.ValidateObject(nameof(renderMethod)); output.ValidateObject(nameof(output)); bool stateChanged = SetupStates(blendStateOverride, depthStencilStateOverride, rasterStateOverride, output, camera); for (int i = 0; i < PassCount; ++i) { // Batch state should be cached on the implementation side, otherwise the GC could be impacted by a lot of dead objects per frame. Gorgon2DBatchState batchState = OnGetBatchState(i, stateChanged); switch (OnBeforeRenderPass(i, output, camera)) { case PassContinuationState.Continue: Renderer.Begin(batchState, camera); OnRenderPass(i, renderMethod, output); Renderer.End(); OnAfterRenderPass(i, output); break; case PassContinuationState.Skip: continue; default: OnAfterRender(output); return; } } OnAfterRender(output); }
/// <summary> /// Function to set up state prior to rendering. /// </summary> /// <param name="blendStateOverride">An override for the current blending state.</param> /// <param name="depthStencilStateOverride">An override for the current depth/stencil state.</param> /// <param name="rasterStateOverride">An override for the current raster state.</param> /// <param name="output">The target used as the output.</param> /// <param name="camera">The active camera.</param> /// <returns><b>true</b> if state was overridden, <b>false</b> if not or <b>null</b> if rendering is canceled.</returns> private bool SetupStates(GorgonBlendState blendStateOverride, GorgonDepthStencilState depthStencilStateOverride, GorgonRasterState rasterStateOverride, GorgonRenderTargetView output, IGorgon2DCamera camera) { if (!_isInitialized) { OnInitialize(); _isInitialized = true; } bool outputSizeChanged = false; if ((_prevOutputSize.Width != output.Width) || (_prevOutputSize.Height != output.Height)) { _prevOutputSize = new DX.Size2(output.Width, output.Height); outputSizeChanged = true; } OnBeforeRender(output, camera, outputSizeChanged); if ((blendStateOverride == BlendStateOverride) && (depthStencilStateOverride == DepthStencilStateOverride) && (rasterStateOverride == RasterStateOverride)) { return(false); } BatchStateBuilder.BlendState(blendStateOverride ?? GorgonBlendState.Default) .DepthStencilState(depthStencilStateOverride ?? GorgonDepthStencilState.Default) .RasterState(rasterStateOverride ?? GorgonRasterState.Default); BlendStateOverride = blendStateOverride; DepthStencilStateOverride = depthStencilStateOverride; RasterStateOverride = rasterStateOverride; return(true); }
/// <summary> /// Function to assign the blend state to the batch state. /// </summary> /// <param name="blendState">The blend state to assign, or <b>null</b> for a default state.</param> /// <returns>The fluent builder interface.</returns> public Gorgon2DBatchStateBuilder BlendState(GorgonBlendState blendState) { _worker.BlendState = blendState; return(this); }
/// <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 provide an override for the blending state when rendering the initial scene. /// </summary> /// <param name="blendState">The blending state to use.</param> /// <returns>The fluent interface for the effects processor.</returns> public Gorgon2DCompositor FinalBlendState(GorgonBlendState blendState) { _finalBatchStateBuilder.BlendState(blendState ?? GorgonBlendState.NoBlending); _hasFinalBatchStateChanged = true; return(this); }