void ListOperations(ICompositingOperation op, List <ICompositingOperation> list) { if (op.Source1 != null) { ListOperations(op.Source1, list); } if (op.Source2 != null) { ListOperations(op.Source2, list); } list.Add(op); }
/// <summary> /// Applies effect to topmost image and writes result to the top. /// </summary> /// <param name="effect"></param> public void Call(ICompositingOperation operation) { switch (operation.OperationType) { case OperationType.NoSource: break; case OperationType.OneSource: operation.Source1 = results.Pop(); break; case OperationType.TwoSources: operation.Source1 = results.Pop(); operation.Source2 = results.Pop(); break; } results.Push(operation); }
/// <summary> /// Composites to source. /// </summary> /// <param name="compositeOperation"></param> public void CompositeToSource(ICompositingOperation compositeOperation, BlendState blendOverwrite, Colour blendColour, Region2i viewport, RenderTargetView target) { // 1) We first prepare the providers. List <ICompositingOperation> relavantOperations = new List <ICompositingOperation>(); ListOperations(compositeOperation, relavantOperations); // 2) We extract processors. List <ICompositeInterface> processors = new List <ICompositeInterface>(relavantOperations.Count); for (int i = 0; i < relavantOperations.Count; i++) { processors.Add(relavantOperations[i].Interface); } // 3) We prepare the shader. ShaderCode pshader = PixelShader; ShaderCode vshader = VertexShader; States.BlendState bstate = blendOverwrite != null ? blendOverwrite : DefaultBlendState; States.DepthStencilState dstate = DefaultDepthStencilState; States.RasterizationState rstate = DefaultRasterizationState; FixedShaderParameters pparams = pshader.FixedParameters; FixedShaderParameters vparams = vshader.FixedParameters; ConstantBufferLayoutBuilder builder = new ConstantBufferLayoutBuilder(); List <TextureView> textures = new List <TextureView>(); List <States.SamplerState> samplers = new List <States.SamplerState>(); // We set interface array. pparams.SetInterfaceArray("Composite", processors); builder.AppendElement("Offset", PinFormat.Floatx2); // 4) We fill parameters and builder. for (int i = 0; i < processors.Count; i++) { string name = string.Format("Composite[{0}]", i); InterfaceHelper.ApplyInterfaceConstants(name, processors[i], builder, pparams, textures, samplers, processors[i].ParameterValues); } // 5) We obtain layout big enough. ConstantBufferLayout layout = builder.CreateLayout(); pparams.AddLayout(0, layout); ConstantBufferView constantBuffer = pixelTypelessConstantBuffer.CreateConstantBuffer(layout); // 6) We fill buffer. constantBuffer.Map(MapOptions.Write); try { constantBuffer.SetConstant("Offset", new Vector2f((float)viewport.X, (float)viewport.Y)); for (int i = 0; i < processors.Count; i++) { InterfaceHelper.FillInterfaceConstants(string.Format("Composite[{0}]", i), processors[i], constantBuffer, processors[i].ParameterValues); } } finally { constantBuffer.UnMap(); } // 7) We prepare geometry. // We get quad geometry Geometry geometry = alignedQuad; // ) We render the composition. GraphicsDevice device = Device; using (DeviceLock l = device.Lock()) { // We set our state objects. device.SetBlendState(bstate, blendColour, 0xFFFFFFFF); device.SetDepthStencilState(dstate, 0); device.SetRasterizationState(rstate); device.Viewport = viewport; // We prepare to render. device.SetVertexShader(vshader.Compile(device, vparams) as VShader, geometry, null, null, null); device.SetGeometryShader(null, null, null, null, null); device.SetPixelShader(pshader.Compile(device, pparams) as PShader, samplers.ToArray(), textures.ToArray(), new ConstantBufferView[] { constantBuffer }, new RenderTargetView[] { target }, null); // We render it. if (geometry.IndexBuffer != null) { device.DrawIndexed(0, 6, 0); } else { device.Draw(0, 6); } device.SetPixelShader(null, null, null, null, null, null); } // We do not use constant buffer anymore. constantBuffer.Dispose(); }