예제 #1
0
        /// <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;
        }
예제 #2
0
        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;
        }