Exemple #1
0
        /// <summary>
        /// Calculates the current render state for the given object. This is based on the current object's
        /// state (position, rotation,..) and its parent objects state.
        /// So it basically contains the final values for the object that are needed for rendering
        /// (its position and rotation relative to the window, its final alpha and scale value)
        /// The render state then gets pushed to the render queue which gets processed as a whole on each frame.
        /// </summary>
        /// <param name="displayObject">The displayObject whose RenderState needs to be calculated</param>
        public void PushRenderState(DisplayObject displayObject)
        {
            // TODO: in the future use an object pool for this, it gets created once for every renderable object on each frame
            var renderState = new RenderState();

            renderState.SetValues(_renderStates.Peek(), displayObject);
            _renderStates.Push(renderState);
            if (renderState.ResSet != null && !displayObject.GetBounds().IsEmpty())
            {
                _renderQueue.Add(renderState);
            }
        }
Exemple #2
0
        // masks

        /// <summary>
        /// Draws a display object into the stencil buffer, incrementing the buffer on each
        /// used pixel. The stencil reference value is incremented as well; thus, any subsequent
        /// stencil tests outside of this area will fail.
        ///
        /// <p>If 'mask' is part of the display list, it will be drawn at its conventional stage
        /// coordinates. Otherwise, it will be drawn with the current modelview matrix.</p>
        ///
        /// <p>As an optimization, this method might update the clipping rectangle of the render
        /// state instead of utilizing the stencil buffer. This is possible when the mask object
        /// is of type <code>Sparrow.Display.Quad</code> and is aligned parallel to the stage
        /// axes.</p>
        ///
        /// <p>Note that masking breaks the render cache; the masked object must be redrawn anew
        /// in the next frame. If you pass <code>maskee</code>, the method will automatically
        /// call <code>ExcludeFromCache(maskee)</code> for you.</p>
        /// </summary>
        public void DrawMask(DisplayObject mask, DisplayObject maskee = null)
        {
            FinishMeshBatch();

            if (IsRectangularMask(mask, SMatrix))
            {
                _sClipRect = mask.GetBounds(mask);
                _sClipRect = _sClipRect.GetBounds(SMatrix);
                PushClipRect(_sClipRect);
            }
            else
            {
                throw new NotImplementedException();
            }

            ExcludeFromCache(maskee);
        }
        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;
        }