/// <summary> /// Disposes all resources that have been created by the filter. /// </summary> public void Dispose() { _helper?.Dispose(); _effect?.Dispose(); _quad?.Dispose(); _effect = null; _quad = null; }
private void RenderPasses(Painter painter, bool forCache) { if (_helper == null) { _helper = new FilterHelper(_textureFormat); } if (_quad == null) { _quad = new FilterQuad(_textureSmoothing); } else { _helper.PutTexture(_quad.Texture); _quad.Texture = null; } Rectangle bounds; bool drawLastPassToBackBuffer = false; float origResolution = _resolution; DisplayObject renderSpace = _target.Stage != null ? _target.Stage : _target.Parent; bool isOnStage = renderSpace is Stage; Stage stage = SparrowSharp.Stage; if (!forCache && (_alwaysDrawToBackBuffer || _target.RequiresRedraw)) { // If 'requiresRedraw' is true, the object is non-static, and we guess that this // will be the same in the next frame. So we render directly to the back buffer. // // -- That, however, is only possible for full alpha values, because // (1) 'FilterEffect' can't handle alpha (and that will do the rendering) // (2) we don't want lower layers (CompositeFilter!) to shine through. drawLastPassToBackBuffer = painter.State.Alpha == 1.0f; painter.ExcludeFromCache(_target); } if (_target == SparrowSharp.Root) { // full-screen filters use exactly the stage bounds bounds = stage.GetStageBounds(_target); } else { // Unfortunately, the following bounds calculation yields the wrong result when // drawing a filter to a RenderTexture using a custom matrix. The 'modelviewMatrix' // should be used for the bounds calculation, but the API doesn't support this. // A future version should change this to: "GetBounds(modelviewMatrix, bounds)" bounds = _target.GetBounds(renderSpace); if (!forCache && isOnStage) // normally, we don't need anything outside { var stageBounds = stage.GetStageBounds(null); bounds = bounds.Intersection(stageBounds); } } _quad.Visible = !bounds.IsEmpty(); if (!_quad.Visible) { return; } if (_padding != null) { bounds.Extend(_padding.Left, _padding.Right, _padding.Top, _padding.Bottom); } // integer bounds for maximum sharpness + to avoid jiggling bounds.SetTo((float)Math.Floor(bounds.X), (float)Math.Floor(bounds.Y), (float)Math.Ceiling(bounds.Width), (float)Math.Ceiling(bounds.Height)); _helper.TextureScale = SparrowSharp.ContentScaleFactor * _resolution; _helper.ProjectionMatrix3D = painter.State.ProjectionMatrix3D; _helper.RenderTarget = painter.State.RenderTarget; _helper.TargetBounds = bounds; _helper.Target = _target; _helper.Start(NumPasses, drawLastPassToBackBuffer); _quad.SetBounds(bounds); _resolution = 1.0f; // applied via '_helper.textureScale' already; // only 'child'-filters use resolution directly (in 'process') bool wasCacheEnabled = painter.CacheEnabled; Texture input = _helper.GetTexture(); painter.CacheEnabled = false; // -> what follows should not be cached painter.PushState(); painter.State.Alpha = 1.0f; painter.State.RenderTarget = input; painter.State.SetProjectionMatrix(bounds.X, bounds.Y, input.Root.Width, input.Root.Height, stage.StageWidth, stage.StageHeight, stage.CameraPosition); // OpenGL renders into textures with Y coordinates flipped :( painter.State.ModelviewMatrix.Scale(1, -1); painter.State.ModelviewMatrix.Translate(0, input.Root.Height + 2 * bounds.Y); _target.Render(painter); // -> draw target object into 'input' painter.FinishMeshBatch(); painter.State.SetModelviewMatricesToIdentity(); painter.State.ClipRect = null; var output = Process(painter, _helper, input); painter.PopState(); painter.CacheEnabled = wasCacheEnabled; // -> cache again if (output != null) // indirect rendering { painter.PushState(); _quad.MoveVertices(renderSpace, _target); // -> local coords _quad.Texture = output; _quad.Render(painter); // renders to the screen painter.FinishMeshBatch(); painter.PopState(); } _helper.Target = null; _helper.PutTexture(input); _resolution = origResolution; }