/// <summary> /// Adds another quad batch to this batch, using custom alpha and blend mode values (ignoring the /// batch's original values) and transforming each vertex by a certain transformation matrix. Just /// like the 'AddQuad' method, you have to make sure that you only add batches with an equal state. /// </summary> public void AddQuadBatch(QuadBatch quadBatch, float alpha, uint blendMode, Matrix matrix = null) { int vertexID = _numQuads * 4; int numQuads = quadBatch.NumQuads; int numVertices = numQuads * 4; if (matrix == null) { matrix = quadBatch.TransformationMatrix; } if (_numQuads + numQuads > _capacity) { Capacity = _numQuads + numQuads; } if (_numQuads == 0) { _texture = quadBatch.QuadTexture; _premultipliedAlpha = quadBatch.PremultipliedAlpha; BlendMode = blendMode; _vertexData.SetPremultipliedAlpha(_premultipliedAlpha, false); } _tinted = alpha != 1.0f || quadBatch.Tinted; quadBatch.VertexData.CopyToVertexData(_vertexData, _tinted, vertexID, numVertices); _vertexData.TransformVertices(matrix, vertexID, numVertices); if (alpha != 1.0f) { _vertexData.ScaleAlphaBy(alpha, vertexID, numVertices); } _syncRequired = true; _numQuads += numQuads; }
override public void Render(RenderSupport support) { if (ClipRect != null) { Rectangle stageClipRect = support.PushClipRect(ClipRectInSpace(Stage)); if (stageClipRect != null || stageClipRect.IsEmpty()) { // empty clipping bounds - no need to render children support.PopClipRect(); return; } } if (_flattenRequested) { _flattenedContents = QuadBatch.Compile(this, _flattenedContents); _flattenRequested = false; } if (_flattenedContents.Count > 0) { support.FinishQuadBatch(); support.AddDrawCalls(_flattenedContents.Count); Matrix mvpMatrix = support.MvpMatrix; float alpha = support.Alpha; uint supportBlendMode = support.BlendMode; foreach (QuadBatch quadBatch in _flattenedContents) { uint blendMode = quadBatch.BlendMode; if (blendMode == Sparrow.Display.BlendMode.AUTO) { blendMode = supportBlendMode; } quadBatch.Render(mvpMatrix, alpha, blendMode); } } else { base.Render(support); } if (ClipRect != null) { support.PopClipRect(); } }
public TextField(float width, float height, string text = "", string fontName = "mini", float fontSize = 14, uint color = 0x0) { _text = text; _fontSize = fontSize; _color = color; _hAlign = HAlign.Center; _vAlign = VAlign.Center; _autoScale = false; _kerning = true; _requiresRedraw = true; FontName = fontName; _hitArea = new Quad(width, height); _hitArea.Alpha = 0.0f; AddChild(_hitArea); _contents = new QuadBatch(); _contents.Touchable = false; AddChild(_contents); //[self addEventListener:@selector(onFlatten:) atObject:self forType:SPEventTypeFlatten]; }
/// <summary> /// Adds another quad batch to this batch. /// </summary> public void AddQuadBatch(QuadBatch quadBatch) { AddQuadBatch(quadBatch, quadBatch.Alpha, quadBatch.BlendMode); }
private QuadBatch RenderPasses(DisplayObject obj, RenderSupport support, bool intoCache) { Texture cacheTexture = null; Stage stage = obj.Stage; float scale = Resolution; if (stage == null) { throw new InvalidOperationException("Filtered object must be on the stage."); } // the bounds of the object in stage coordinates Rectangle boundsPOT; Rectangle bounds; CalcBounds(obj, stage, scale, !intoCache, out bounds, out boundsPOT); if (bounds.IsEmpty()) { DisposePassTextures(); return intoCache ? new QuadBatch() : null; } UpdateBuffers(boundsPOT); UpdatePassTextures((int)boundsPOT.Width, (int)boundsPOT.Height, scale); support.FinishQuadBatch(); support.AddDrawCalls(NumPasses); support.PushState(Matrix.Create(), 1.0f, BlendMode.AUTO); // save original projection matrix and render target _projMatrix.CopyFromMatrix(support.ProjectionMatrix); Texture previousRenderTarget = support.RenderTarget; // use cache? if (intoCache) { cacheTexture = CreateTexture((int)boundsPOT.Width, (int)boundsPOT.Height, scale); } // draw the original object into a texture support.RenderTarget = _passTextures[0]; SparrowSharpApp.Context.ScissorBox = null; // we want the entire texture cleared support.Clear(); support.BlendMode = BlendMode.NORMAL; support.SetupOrthographicProjection(boundsPOT.Left, boundsPOT.Right, boundsPOT.Bottom, boundsPOT.Top); obj.Render(support); support.FinishQuadBatch(); // prepare drawing of actual filter passes support.ApplyBlendMode(true); support.ModelViewMatrix.Identity(); support.PushClipRect(bounds); GL.BindBuffer (BufferTarget.ArrayBuffer, _vertexBufferName); GL.BindBuffer (BufferTarget.ElementArrayBuffer, _indexBufferName); GL.EnableVertexAttribArray (VertexPosID); GL.VertexAttribPointer (VertexPosID, 2, VertexAttribPointerType.Float, false, Vertex.SIZE, (IntPtr)Vertex.POSITION_OFFSET); GL.EnableVertexAttribArray (TexCoordsID); GL.VertexAttribPointer (TexCoordsID, 2, VertexAttribPointerType.Float, false, Vertex.SIZE, (IntPtr)Vertex.TEXTURE_OFFSET); // draw all passes for (int i = 0; i < NumPasses; ++i) { if (i < NumPasses - 1) { // intermediate pass // draw into pass texture support.RenderTarget = PassTextureForPass(i + 1); support.Clear(); } else { // final pass if (intoCache) { // draw into cache texture support.RenderTarget = cacheTexture; support.Clear(); } else { // draw into back buffer, at original (stage) coordinates support.RenderTarget = previousRenderTarget; support.ProjectionMatrix = _projMatrix; support.ModelViewMatrix.Translate(OffsetX, OffsetY); support.BlendMode = obj.BlendMode; support.ApplyBlendMode(true); } } Texture passTexture = PassTextureForPass(i); GL.ActiveTexture (TextureUnit.Texture0); GL.BindTexture (TextureTarget.Texture2D, passTexture.Name); ActivateWithPass (i, passTexture, support.MvpMatrix); GL.DrawElements (BeginMode.Triangles, 6, DrawElementsType.UnsignedShort, IntPtr.Zero); DeactivateWithPass(i, passTexture); } GL.DisableVertexAttribArray(VertexPosID); GL.DisableVertexAttribArray(TexCoordsID); support.PopState(); support.PopClipRect(); QuadBatch cache = null; if (intoCache) { // restore support settings support.RenderTarget = previousRenderTarget; support.ProjectionMatrix = _projMatrix; // Create an image containing the cache. To have a display object that contains // the filter output in object coordinates, we wrap it in a QuadBatch: that way, // we can modify it with a transformation matrix. cache = new QuadBatch(); Image image = new Image(cacheTexture); Matrix matrix = stage.TransformationMatrixToSpace(obj); // Note: the next line was originally: // matrix.Translate (bounds.X + OffsetX, bounds.Y + OffsetY); // this seems like a sparrow-s bug; fix is from Starling matrix.PrependTranslation(bounds.X + OffsetX, bounds.Top + OffsetY); cache.AddQuad(image, 1.0f, BlendMode.AUTO, matrix); } return cache; }
private void DisposeCache() { _cache = null; }
/// <summary> /// Applies the filter on a certain display object, rendering the output into the current render /// target. This method is called automatically by Sparrow's rendering system for the object the /// filter is attached to. /// </summary> public void RenderObject(DisplayObject obj, RenderSupport support) { // bottom layer if (Mode == FragmentFilterMode.Above) { obj.Render(support); } // center layer if (_cacheRequested) { _cacheRequested = false; _cache = RenderPasses(obj, support, true); DisposePassTextures(); } if (_cache != null) { _cache.Render(support); } else { RenderPasses(obj, support, false); } // top layer if (Mode == FragmentFilterMode.Below) { obj.Render(support); } }
/// <summary> /// Draws text into a quad batch. /// </summary> public void FillQuadBatch(QuadBatch quadBatch, float width, float height, string text, float size, uint color, HAlign hAlign, VAlign vAlign, bool autoScale, bool kerning) { List<CharLocation> charLocations = ArrangeCharsInArea(width, height, text, size, hAlign, vAlign, autoScale, kerning); _helperImage.Color = color; if (charLocations.Count > MAX_TEXT_CHAR_COUNT) { throw new InvalidDataException(string.Format("Bitmap font text is limited to {0} characters", MAX_TEXT_CHAR_COUNT)); } CharLocation charLocation; for (int i = 0; i < charLocations.Count; i++) { charLocation = charLocations[i]; _helperImage.Texture = charLocation.BitmapChar.Texture; _helperImage.X = charLocation.X; _helperImage.Y = charLocation.Y; _helperImage.ScaleX = _helperImage.ScaleY = charLocation.Scale; _helperImage.ReadjustSize(); quadBatch.AddQuad(_helperImage); } }
/// <summary> /// Resets the render state stack to the default. /// </summary> public void NextFrame() { _clipRectStackSize = 0; _stateStackIndex = 0; _quadBatchIndex = 0; _numDrawCalls = 0; _quadBatchTop = _quadBatches[0]; _stateStackTop = _stateStack[0]; }
/// <summary> /// Clears all vertex and index buffers, releasing the associated memory. Useful in low-memory /// situations. Don't call from within a render method! /// </summary> public void PurgeBuffers() { _quadBatches.Clear(); _quadBatchTop = new QuadBatch(); _quadBatches.Add(_quadBatchTop); _quadBatchIndex = 0; _quadBatchSize = 1; }
public RenderSupport() { _projectionMatrix = Matrix.Create(); _mvpMatrix = Matrix.Create(); _stateStack = new List<RenderState> { new RenderState() }; _stateStackIndex = 0; _stateStackSize = 1; _stateStackTop = _stateStack[0]; _quadBatches = new List<QuadBatch> { new QuadBatch() }; _quadBatchIndex = 0; _quadBatchSize = 1; _quadBatchTop = _quadBatches[0]; _clipRectStack = new List<Rectangle>(); _clipRectStackSize = 0; SetupOrthographicProjection(0, 320, 0, 480); }
public static int Compile(DisplayObject displayObject, List <QuadBatch> quadBatches, int quadBatchID, Matrix transformationMatrix, float alpha, uint blendMode) { bool isRootObject = false; float objectAlpha = displayObject.Alpha; Quad quad = displayObject is Quad ? (Quad)displayObject : null; QuadBatch batch = displayObject is QuadBatch ? (QuadBatch)displayObject : null; DisplayObjectContainer container = displayObject is DisplayObjectContainer ? (DisplayObjectContainer)displayObject : null; if (quadBatchID == -1) { isRootObject = true; quadBatchID = 0; objectAlpha = 1.0f; blendMode = displayObject.BlendMode; if (quadBatches.Count == 0) { quadBatches.Add(new QuadBatch()); } else { quadBatches[0].Reset(); } } if (container != null) { Matrix childMatrix = Matrix.Create(); childMatrix.Identity(); int numChildren = container.NumChildren; for (int i = 0; i < numChildren; i++) { DisplayObject child = container.GetChild(i); if (child.HasVisibleArea) { uint childBlendMode = child.BlendMode; if (childBlendMode == Sparrow.Display.BlendMode.AUTO) { childBlendMode = blendMode; } childMatrix.CopyFromMatrix(transformationMatrix); childMatrix.PrependMatrix(child.TransformationMatrix); quadBatchID = Compile(child, quadBatches, quadBatchID, childMatrix, alpha * objectAlpha, childBlendMode); } } } else if (quad != null) { Texture texture = quad.Texture; bool tinted = quad.Tinted; bool pma = quad.PremultipliedAlpha; QuadBatch currentBatch = quadBatches[quadBatchID]; if (currentBatch.IsStateChange(tinted, texture, alpha * objectAlpha, pma, blendMode, 1)) { quadBatchID++; if (quadBatches.Count <= quadBatchID) { quadBatches.Add(new QuadBatch()); } currentBatch = quadBatches[quadBatchID]; currentBatch.Reset(); } currentBatch.AddQuad(quad, alpha * objectAlpha, blendMode, transformationMatrix); } else if (batch != null) { Texture texture = quad.Texture; bool tinted = quad.Tinted; bool pma = quad.PremultipliedAlpha; int numQuads = batch.NumQuads; QuadBatch currentBatch = quadBatches[quadBatchID]; if (currentBatch.IsStateChange(tinted, texture, alpha * objectAlpha, pma, blendMode, numQuads)) { quadBatchID++; if (quadBatches.Count <= quadBatchID) { quadBatches.Add(new QuadBatch()); } currentBatch = quadBatches[quadBatchID]; currentBatch.Reset(); } currentBatch.AddQuadBatch(batch, alpha * objectAlpha, blendMode, transformationMatrix); } else { throw new InvalidOperationException("Unsupported display object"); } if (!isRootObject) { return(quadBatchID); } // remove unused batches for (int i = quadBatches.Count - 1; i > quadBatchID; --i) { quadBatches.RemoveAt(quadBatches.Count - 1); } return(quadBatchID); }
/// <summary> /// Adds another quad batch to this batch, using a custom alpha value (ignoring the batch's /// original alpha). /// </summary> public void AddQuadBatch(QuadBatch quadBatch, float alpha) { AddQuadBatch(quadBatch, alpha, quadBatch.BlendMode); }
/// <summary> /// Renders the current quad batch and resets it. /// </summary> public void FinishQuadBatch() { if (_quadBatchTop.NumQuads != 0) { _quadBatchTop.Render(_projectionMatrix); _quadBatchTop.Reset(); if (_quadBatchSize == _quadBatchIndex + 1) { _quadBatches.Add(new QuadBatch()); _quadBatchSize++; } _numDrawCalls++; _quadBatchTop = _quadBatches[++_quadBatchIndex]; } }