/// <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); } }
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; }
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); }