protected override void Apply(GraphicsContext gfx, Surface surface) { // Will compose images without blending gfx.Blending = Blending.Opaque; gfx.Shader = _blurShader; // Request a temporary surface (we need to multipass) var temp = SurfacePool.Request(surface.Size); { // Horizontal pass (surface to temp) gfx.Surface = temp; _blurShader.Vector = Vector.Right * Strength; gfx.DrawImage(surface, Vector.Zero); // Vertical pass (temp to surface) gfx.Surface = surface; _blurShader.Vector = Vector.Down * Strength; gfx.DrawImage(temp, Vector.Zero); } SurfacePool.Recycle(temp); }
internal void Render(GraphicsContext gfx, float dt, IEnumerable <Entity> entities) { var screenSize = gfx.Screen.Surface.Size; // Sort effect layers EffectLayers.StableSort(); // Get first effect layer var layer = GetEffectLayer(0); var layerIndex = 0; // Get initial surface var surface = GetSurface(screenSize, layer); // Clear initial surface with background color gfx.Surface = surface; gfx.Clear(BackgroundColor); gfx.GlobalTransform *= Matrix.CreateScale(1F / layer.Downscale); // Draw entities from back to front (negative to positive) foreach (var entity in entities) { // Update Entity entity.Update(dt); // Entity is above layer, advance to next layer. if (entity.Depth > layer.Depth) { // Apply effect to surface gfx.Apply(layer.Effect); // Mark surface as old surface var oldSurface = surface; // Get next layer and surface layer = GetEffectLayer(++layerIndex); surface = GetSurface(screenSize, layer); // Copy old surface to new surface (basis) gfx.Blit(oldSurface, surface); // Recycle old surface (no longer needed) SurfacePool.Recycle(oldSurface); // Begin drawing to new layer surface gfx.ResetState(); gfx.Surface = surface; gfx.GlobalTransform *= Matrix.CreateScale(1F / layer.Downscale); } // Draw Entity gfx.PushState(); entity.Draw(gfx, dt); gfx.PopState(); } // Copy surface to screen gfx.Blit(surface, gfx.Screen.Surface); // Recycle old surface (no longer needed) SurfacePool.Recycle(surface); }